summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--api/gobgp.pb.go242
-rw-r--r--api/gobgp.proto28
-rw-r--r--gobgp/main.go384
-rw-r--r--server/grpc_server.go115
-rw-r--r--server/server.go184
5 files changed, 901 insertions, 52 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go
index e552e363..a67af8f7 100644
--- a/api/gobgp.pb.go
+++ b/api/gobgp.pb.go
@@ -12,6 +12,7 @@ It has these top-level messages:
Error
Arguments
ModPathArguments
+ PolicyArguments
AddressFamily
GracefulRestartTuple
GracefulRestart
@@ -30,6 +31,8 @@ It has these top-level messages:
PeerConf
PeerInfo
Peer
+ Prefix
+ PrefixSet
*/
package api
@@ -50,10 +53,11 @@ var _ = proto.Marshal
type Resource int32
const (
- Resource_GLOBAL Resource = 0
- Resource_LOCAL Resource = 1
- Resource_ADJ_IN Resource = 2
- Resource_ADJ_OUT Resource = 3
+ Resource_GLOBAL Resource = 0
+ Resource_LOCAL Resource = 1
+ Resource_ADJ_IN Resource = 2
+ Resource_ADJ_OUT Resource = 3
+ Resource_POLICY_PREFIX Resource = 4
)
var Resource_name = map[int32]string{
@@ -61,18 +65,43 @@ var Resource_name = map[int32]string{
1: "LOCAL",
2: "ADJ_IN",
3: "ADJ_OUT",
+ 4: "POLICY_PREFIX",
}
var Resource_value = map[string]int32{
- "GLOBAL": 0,
- "LOCAL": 1,
- "ADJ_IN": 2,
- "ADJ_OUT": 3,
+ "GLOBAL": 0,
+ "LOCAL": 1,
+ "ADJ_IN": 2,
+ "ADJ_OUT": 3,
+ "POLICY_PREFIX": 4,
}
func (x Resource) String() string {
return proto.EnumName(Resource_name, int32(x))
}
+type Operation int32
+
+const (
+ Operation_ADD Operation = 0
+ Operation_DEL Operation = 1
+ Operation_DEL_ALL Operation = 2
+)
+
+var Operation_name = map[int32]string{
+ 0: "ADD",
+ 1: "DEL",
+ 2: "DEL_ALL",
+}
+var Operation_value = map[string]int32{
+ "ADD": 0,
+ "DEL": 1,
+ "DEL_ALL": 2,
+}
+
+func (x Operation) String() string {
+ return proto.EnumName(Operation_name, int32(x))
+}
+
type AFI int32
const (
@@ -476,6 +505,24 @@ func (m *ModPathArguments) GetPath() *Path {
return nil
}
+type PolicyArguments struct {
+ Resource Resource `protobuf:"varint,1,opt,name=resource,enum=api.Resource" json:"resource,omitempty"`
+ Operation Operation `protobuf:"varint,2,opt,name=operation,enum=api.Operation" json:"operation,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"`
+ PrefixSet *PrefixSet `protobuf:"bytes,4,opt,name=prefix_set" json:"prefix_set,omitempty"`
+}
+
+func (m *PolicyArguments) Reset() { *m = PolicyArguments{} }
+func (m *PolicyArguments) String() string { return proto.CompactTextString(m) }
+func (*PolicyArguments) ProtoMessage() {}
+
+func (m *PolicyArguments) GetPrefixSet() *PrefixSet {
+ if m != nil {
+ return m.PrefixSet
+ }
+ return nil
+}
+
type AddressFamily struct {
Afi AFI `protobuf:"varint,1,opt,enum=api.AFI" json:"Afi,omitempty"`
Safi SAFI `protobuf:"varint,2,opt,enum=api.SAFI" json:"Safi,omitempty"`
@@ -848,8 +895,35 @@ func (m *Peer) GetInfo() *PeerInfo {
return nil
}
+type Prefix struct {
+ Address string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
+ MaskLength uint32 `protobuf:"varint,2,opt,name=mask_length" json:"mask_length,omitempty"`
+ MaskLengthRange string `protobuf:"bytes,3,opt,name=mask_length_range" json:"mask_length_range,omitempty"`
+}
+
+func (m *Prefix) Reset() { *m = Prefix{} }
+func (m *Prefix) String() string { return proto.CompactTextString(m) }
+func (*Prefix) ProtoMessage() {}
+
+type PrefixSet struct {
+ PrefixSetName string `protobuf:"bytes,1,opt,name=prefix_set_name" json:"prefix_set_name,omitempty"`
+ PrefixList []*Prefix `protobuf:"bytes,2,rep,name=prefix_list" json:"prefix_list,omitempty"`
+}
+
+func (m *PrefixSet) Reset() { *m = PrefixSet{} }
+func (m *PrefixSet) String() string { return proto.CompactTextString(m) }
+func (*PrefixSet) ProtoMessage() {}
+
+func (m *PrefixSet) GetPrefixList() []*Prefix {
+ if m != nil {
+ return m.PrefixList
+ }
+ return nil
+}
+
func init() {
proto.RegisterEnum("api.Resource", Resource_name, Resource_value)
+ proto.RegisterEnum("api.Operation", Operation_name, Operation_value)
proto.RegisterEnum("api.AFI", AFI_name, AFI_value)
proto.RegisterEnum("api.SAFI", SAFI_name, SAFI_value)
proto.RegisterEnum("api.BGP_CAPABILITY", BGP_CAPABILITY_name, BGP_CAPABILITY_value)
@@ -878,6 +952,9 @@ type GrpcClient interface {
Enable(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (*Error, error)
Disable(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (*Error, error)
ModPath(ctx context.Context, opts ...grpc.CallOption) (Grpc_ModPathClient, error)
+ GetPolicyPrefixes(ctx context.Context, in *PolicyArguments, opts ...grpc.CallOption) (Grpc_GetPolicyPrefixesClient, error)
+ GetPolicyPrefix(ctx context.Context, in *PolicyArguments, opts ...grpc.CallOption) (*PrefixSet, error)
+ ModPolicyPrefix(ctx context.Context, opts ...grpc.CallOption) (Grpc_ModPolicyPrefixClient, error)
}
type grpcClient struct {
@@ -1087,6 +1164,78 @@ func (x *grpcModPathClient) Recv() (*Error, error) {
return m, nil
}
+func (c *grpcClient) GetPolicyPrefixes(ctx context.Context, in *PolicyArguments, opts ...grpc.CallOption) (Grpc_GetPolicyPrefixesClient, error) {
+ stream, err := grpc.NewClientStream(ctx, &_Grpc_serviceDesc.Streams[4], c.cc, "/api.Grpc/GetPolicyPrefixes", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpcGetPolicyPrefixesClient{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_GetPolicyPrefixesClient interface {
+ Recv() (*PrefixSet, error)
+ grpc.ClientStream
+}
+
+type grpcGetPolicyPrefixesClient struct {
+ grpc.ClientStream
+}
+
+func (x *grpcGetPolicyPrefixesClient) Recv() (*PrefixSet, error) {
+ m := new(PrefixSet)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *grpcClient) GetPolicyPrefix(ctx context.Context, in *PolicyArguments, opts ...grpc.CallOption) (*PrefixSet, error) {
+ out := new(PrefixSet)
+ err := grpc.Invoke(ctx, "/api.Grpc/GetPolicyPrefix", in, out, c.cc, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *grpcClient) ModPolicyPrefix(ctx context.Context, opts ...grpc.CallOption) (Grpc_ModPolicyPrefixClient, error) {
+ stream, err := grpc.NewClientStream(ctx, &_Grpc_serviceDesc.Streams[5], c.cc, "/api.Grpc/ModPolicyPrefix", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpcModPolicyPrefixClient{stream}
+ return x, nil
+}
+
+type Grpc_ModPolicyPrefixClient interface {
+ Send(*PolicyArguments) error
+ Recv() (*Error, error)
+ grpc.ClientStream
+}
+
+type grpcModPolicyPrefixClient struct {
+ grpc.ClientStream
+}
+
+func (x *grpcModPolicyPrefixClient) Send(m *PolicyArguments) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *grpcModPolicyPrefixClient) Recv() (*Error, error) {
+ m := new(Error)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
// Server API for Grpc service
type GrpcServer interface {
@@ -1102,6 +1251,9 @@ type GrpcServer interface {
Enable(context.Context, *Arguments) (*Error, error)
Disable(context.Context, *Arguments) (*Error, error)
ModPath(Grpc_ModPathServer) error
+ GetPolicyPrefixes(*PolicyArguments, Grpc_GetPolicyPrefixesServer) error
+ GetPolicyPrefix(context.Context, *PolicyArguments) (*PrefixSet, error)
+ ModPolicyPrefix(Grpc_ModPolicyPrefixServer) error
}
func RegisterGrpcServer(s *grpc.Server, srv GrpcServer) {
@@ -1293,6 +1445,65 @@ func (x *grpcModPathServer) Recv() (*ModPathArguments, error) {
return m, nil
}
+func _Grpc_GetPolicyPrefixes_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(PolicyArguments)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(GrpcServer).GetPolicyPrefixes(m, &grpcGetPolicyPrefixesServer{stream})
+}
+
+type Grpc_GetPolicyPrefixesServer interface {
+ Send(*PrefixSet) error
+ grpc.ServerStream
+}
+
+type grpcGetPolicyPrefixesServer struct {
+ grpc.ServerStream
+}
+
+func (x *grpcGetPolicyPrefixesServer) Send(m *PrefixSet) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func _Grpc_GetPolicyPrefix_Handler(srv interface{}, ctx context.Context, codec grpc.Codec, buf []byte) (interface{}, error) {
+ in := new(PolicyArguments)
+ if err := codec.Unmarshal(buf, in); err != nil {
+ return nil, err
+ }
+ out, err := srv.(GrpcServer).GetPolicyPrefix(ctx, in)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func _Grpc_ModPolicyPrefix_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(GrpcServer).ModPolicyPrefix(&grpcModPolicyPrefixServer{stream})
+}
+
+type Grpc_ModPolicyPrefixServer interface {
+ Send(*Error) error
+ Recv() (*PolicyArguments, error)
+ grpc.ServerStream
+}
+
+type grpcModPolicyPrefixServer struct {
+ grpc.ServerStream
+}
+
+func (x *grpcModPolicyPrefixServer) Send(m *Error) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func (x *grpcModPolicyPrefixServer) Recv() (*PolicyArguments, error) {
+ m := new(PolicyArguments)
+ if err := x.ServerStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
var _Grpc_serviceDesc = grpc.ServiceDesc{
ServiceName: "api.Grpc",
HandlerType: (*GrpcServer)(nil),
@@ -1329,6 +1540,10 @@ var _Grpc_serviceDesc = grpc.ServiceDesc{
MethodName: "Disable",
Handler: _Grpc_Disable_Handler,
},
+ {
+ MethodName: "GetPolicyPrefix",
+ Handler: _Grpc_GetPolicyPrefix_Handler,
+ },
},
Streams: []grpc.StreamDesc{
{
@@ -1352,5 +1567,16 @@ var _Grpc_serviceDesc = grpc.ServiceDesc{
ServerStreams: true,
ClientStreams: true,
},
+ {
+ StreamName: "GetPolicyPrefixes",
+ Handler: _Grpc_GetPolicyPrefixes_Handler,
+ ServerStreams: true,
+ },
+ {
+ StreamName: "ModPolicyPrefix",
+ Handler: _Grpc_ModPolicyPrefix_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
},
}
diff --git a/api/gobgp.proto b/api/gobgp.proto
index a3f4228d..6a2e3844 100644
--- a/api/gobgp.proto
+++ b/api/gobgp.proto
@@ -32,6 +32,9 @@ service Grpc {
rpc Enable(Arguments) returns (Error) {}
rpc Disable(Arguments) returns (Error) {}
rpc ModPath(stream ModPathArguments) returns (stream Error) {}
+ rpc GetPolicyPrefixes(PolicyArguments) returns (stream PrefixSet) {}
+ rpc GetPolicyPrefix(PolicyArguments) returns (PrefixSet) {}
+ rpc ModPolicyPrefix(stream PolicyArguments) returns (stream Error) {}
}
message Error {
@@ -54,11 +57,25 @@ message ModPathArguments {
Path path = 2;
}
+message PolicyArguments {
+ Resource resource = 1;
+ Operation operation = 2;
+ string name = 3;
+ PrefixSet prefix_set = 4;
+}
+
enum Resource {
GLOBAL = 0;
LOCAL = 1;
ADJ_IN = 2;
ADJ_OUT = 3;
+ POLICY_PREFIX = 4;
+}
+
+enum Operation {
+ ADD = 0;
+ DEL = 1;
+ DEL_ALL = 2;
}
enum AFI {
@@ -319,3 +336,14 @@ message Peer {
PeerConf conf = 1;
PeerInfo info = 2;
}
+
+message Prefix {
+ string address = 1;
+ uint32 mask_length = 2;
+ string mask_length_range = 3;
+}
+
+message PrefixSet {
+ string prefix_set_name = 1;
+ repeated Prefix prefix_list = 2;
+}
diff --git a/gobgp/main.go b/gobgp/main.go
index 8fcd33fd..4f5a3052 100644
--- a/gobgp/main.go
+++ b/gobgp/main.go
@@ -35,6 +35,7 @@ import (
const (
CMD_GLOBAL = "global"
CMD_NEIGHBOR = "neighbor"
+ CMD_POLICY = "policy"
CMD_RIB = "rib"
CMD_ADD = "add"
CMD_DEL = "del"
@@ -48,6 +49,8 @@ const (
CMD_SHUTDOWN = "shutdown"
CMD_ENABLE = "enable"
CMD_DISABLE = "disable"
+ CMD_PREFIX = "prefix"
+ CMD_ALL = "all"
)
func formatTimedelta(d int64) string {
@@ -134,6 +137,20 @@ func (p peers) Less(i, j int) bool {
return strings.Less(0, 1)
}
+type prefixes []*api.PrefixSet
+
+func (p prefixes) Len() int {
+ return len(p)
+}
+
+func (p prefixes) Swap(i, j int) {
+ p[i], p[j] = p[j], p[i]
+}
+
+func (p prefixes) Less(i, j int) bool {
+ return p[i].PrefixSetName < p[j].PrefixSetName
+}
+
func connGrpc() *grpc.ClientConn {
timeout := grpc.WithTimeout(time.Second)
@@ -166,9 +183,9 @@ func requestGrpc(cmd string, eArgs []string, remoteIP net.IP) error {
return modPath(CMD_DEL, eArgs)
case CMD_NEIGHBOR:
if len(eArgs) == 0 {
- showNeighbors()
+ return showNeighbors()
} else {
- showNeighbor(eArgs)
+ return showNeighbor(eArgs)
}
case CMD_NEIGHBOR + "_" + CMD_LOCAL:
return showNeighborRib(api.Resource_LOCAL, remoteIP)
@@ -190,6 +207,16 @@ func requestGrpc(cmd string, eArgs []string, remoteIP net.IP) error {
return stateChangeNeighbor(CMD_ENABLE, remoteIP)
case CMD_NEIGHBOR + "_" + CMD_DISABLE:
return stateChangeNeighbor(CMD_DISABLE, remoteIP)
+ case CMD_POLICY + "_" + CMD_PREFIX:
+ if len(eArgs) == 0 {
+ return showPolicyPrefixes()
+ } else {
+ return showPolicyPrefix(eArgs)
+ }
+ case CMD_POLICY + "_" + CMD_PREFIX + "_" + CMD_ADD:
+ return modPolicyPrefix(CMD_ADD, eArgs)
+ case CMD_POLICY + "_" + CMD_PREFIX + "_" + CMD_DEL:
+ return modPolicyPrefix(CMD_DEL, eArgs)
}
return nil
}
@@ -252,29 +279,21 @@ func checkAddressFamily(ip net.IP) (*api.AddressFamily, error) {
var client api.GrpcClient
-type GlobalCommand struct {
-}
+type GlobalCommand struct{}
func (x *GlobalCommand) Execute(args []string) error {
eArgs := extractArgs(CMD_GLOBAL)
parser := flags.NewParser(nil, flags.Default)
parser.Usage = "global"
- parser.AddCommand(CMD_RIB, "subcommand for rib of global", "", NewGlobalRibCommand(api.Resource_GLOBAL))
+ parser.AddCommand(CMD_RIB, "subcommand for rib of global", "", &GlobalRibCommand{})
if _, err := parser.ParseArgs(eArgs); err != nil {
os.Exit(1)
}
return nil
}
-type GlobalRibCommand struct {
- resource api.Resource
-}
+type GlobalRibCommand struct{}
-func NewGlobalRibCommand(resource api.Resource) *GlobalRibCommand {
- return &GlobalRibCommand{
- resource: resource,
- }
-}
func showGlobalRib() error {
rt, err := checkAddressFamily(net.IP{})
if err != nil {
@@ -334,8 +353,8 @@ func (x *GlobalRibCommand) Execute(args []string) error {
}
} else {
parser.Usage = "global rib [OPTIONS]\n gobgp global rib"
- parser.AddCommand(CMD_ADD, "subcommand for add route to global rib", "", NewGlobalRibAddCommand(x.resource))
- parser.AddCommand(CMD_DEL, "subcommand for delete route from global rib", "", NewGlobalRibDelCommand(x.resource))
+ parser.AddCommand(CMD_ADD, "subcommand for add route to global rib", "", &GlobalRibAddCommand{})
+ parser.AddCommand(CMD_DEL, "subcommand for delete route from global rib", "", &GlobalRibDelCommand{})
if _, err := parser.ParseArgs(eArgs); err != nil {
os.Exit(1)
}
@@ -343,15 +362,7 @@ func (x *GlobalRibCommand) Execute(args []string) error {
return nil
}
-type GlobalRibAddCommand struct {
- resource api.Resource
-}
-
-func NewGlobalRibAddCommand(resource api.Resource) *GlobalRibAddCommand {
- return &GlobalRibAddCommand{
- resource: resource,
- }
-}
+type GlobalRibAddCommand struct{}
func modPath(modtype string, eArgs []string) error {
rf, err := checkAddressFamily(net.IP{})
@@ -366,7 +377,7 @@ func modPath(modtype string, eArgs []string) error {
if len(eArgs) == 1 || len(eArgs) == 3 {
prefix = eArgs[0]
} else {
- return fmt.Errorf("usage: global rib add <prefix> -a { ipv4 | ipv6 }")
+ return fmt.Errorf("usage: global rib %s <prefix> -a { ipv4 | ipv6 }", modtype)
}
path.Nlri = &api.Nlri{
Af: rf,
@@ -377,7 +388,7 @@ func modPath(modtype string, eArgs []string) error {
macAddr = eArgs[0]
ipAddr = eArgs[1]
} else {
- return fmt.Errorf("usage: global rib add <mac address> <ip address> -a evpn")
+ return fmt.Errorf("usage: global rib %s <mac address> <ip address> -a evpn", modtype)
}
path.Nlri = &api.Nlri{
Af: rf,
@@ -391,7 +402,7 @@ func modPath(modtype string, eArgs []string) error {
}
case api.AF_ENCAP:
if len(eArgs) < 3 {
- return fmt.Errorf("usage: global rib add <end point ip address> [<vni>] -a encap")
+ return fmt.Errorf("usage: global rib %s <end point ip address> [<vni>] -a encap", modtype)
}
prefix = eArgs[0]
@@ -498,15 +509,7 @@ func (x *GlobalRibAddCommand) Execute(args []string) error {
return nil
}
-type GlobalRibDelCommand struct {
- resource api.Resource
-}
-
-func NewGlobalRibDelCommand(resource api.Resource) *GlobalRibDelCommand {
- return &GlobalRibDelCommand{
- resource: resource,
- }
-}
+type GlobalRibDelCommand struct{}
func (x *GlobalRibDelCommand) Execute(args []string) error {
eArgs := extractArgs(CMD_DEL)
@@ -1081,6 +1084,309 @@ func (x *NeighborChangeStateCommand) Execute(args []string) error {
return nil
}
+type PolicyCommand struct{}
+
+func (x *PolicyCommand) Execute(args []string) error {
+ eArgs := extractArgs(CMD_POLICY)
+ parser := flags.NewParser(nil, flags.Default)
+ parser.Usage = "policy"
+ parser.AddCommand(CMD_PREFIX, "subcommand for prefix of policy", "", &PolicyPrefixCommand{})
+ if _, err := parser.ParseArgs(eArgs); err != nil {
+ os.Exit(1)
+ }
+ return nil
+}
+
+type PolicyPrefixCommand struct{}
+
+func showPolicyPrefixes() error {
+ arg := &api.PolicyArguments{
+ Resource: api.Resource_POLICY_PREFIX,
+ }
+ stream, e := client.GetPolicyPrefixes(context.Background(), arg)
+ if e != nil {
+ fmt.Println(e)
+ return e
+ }
+ m := prefixes{}
+ for {
+ p, e := stream.Recv()
+ if e == io.EOF {
+ break
+ } else if e != nil {
+ return e
+ }
+ m = append(m, p)
+ }
+
+ if globalOpts.Json {
+ j, _ := json.Marshal(m)
+ fmt.Println(string(j))
+ return nil
+ }
+
+ if globalOpts.Quiet {
+ for _, p := range m {
+ fmt.Println(p.PrefixSetName)
+ }
+ return nil
+ }
+ maxnamelen := len("Name")
+ maxprefixlen := len("Prefix")
+ maxrangelen := len("MaskRange")
+
+ sort.Sort(m)
+
+ for _, ps := range m {
+ if len(ps.PrefixSetName) > maxnamelen {
+ maxnamelen = len(ps.PrefixSetName)
+ }
+ for _, p := range ps.PrefixList {
+ if len(p.Address)+len(fmt.Sprint(p.MaskLength)) > maxprefixlen {
+ maxprefixlen = len(p.Address) + len(fmt.Sprint(p.MaskLength))
+ }
+ if len(p.MaskLengthRange) > maxrangelen {
+ maxrangelen = len(p.MaskLengthRange)
+ }
+ }
+ }
+ var format string
+ format = "%" + fmt.Sprint(maxnamelen) + "s %-" + fmt.Sprint(maxprefixlen) + "s %-" + fmt.Sprint(maxrangelen) + "s\n"
+ fmt.Printf(format, "Name", "Prefix", "MaskRange")
+ for _, ps := range m {
+ for i, p := range ps.PrefixList {
+ prefix := fmt.Sprintf("%s/%d", p.Address, p.MaskLength)
+ if i == 0 {
+ fmt.Printf(format, ps.PrefixSetName, prefix, p.MaskLengthRange)
+ } else {
+ fmt.Printf(format, "", prefix, p.MaskLengthRange)
+ }
+ }
+ }
+ return nil
+}
+
+func showPolicyPrefix(args []string) error {
+ arg := &api.PolicyArguments{
+ Resource: api.Resource_POLICY_PREFIX,
+ Name: args[0],
+ }
+ ps, e := client.GetPolicyPrefix(context.Background(), arg)
+ if e != nil {
+ return e
+ }
+
+ if globalOpts.Json {
+ j, _ := json.Marshal(ps)
+ fmt.Println(string(j))
+ return nil
+ }
+
+ maxprefixlen := len("Prefix")
+ maxrangelen := len("MaskRange")
+
+ for _, p := range ps.PrefixList {
+ if len(p.Address)+len(fmt.Sprint(p.MaskLength)) > maxprefixlen {
+ maxprefixlen = len(p.Address) + len(fmt.Sprint(p.MaskLength))
+ }
+ if len(p.MaskLengthRange) > maxrangelen {
+ maxrangelen = len(p.MaskLengthRange)
+ }
+ }
+ var format string
+ format = "%-" + fmt.Sprint(maxprefixlen) + "s %-" + fmt.Sprint(maxrangelen) + "s\n"
+ fmt.Printf(format, "Prefix", "MaskRange")
+
+ for _, p := range ps.PrefixList {
+ prefix := fmt.Sprintf("%s/%d", p.Address, p.MaskLength)
+ fmt.Printf(format, prefix, p.MaskLengthRange)
+ }
+ return nil
+}
+
+func (x *PolicyPrefixCommand) Execute(args []string) error {
+ eArgs := extractArgs(CMD_PREFIX)
+ if len(eArgs) == 0 {
+ if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX, eArgs, nil); err != nil {
+ return err
+ }
+ return nil
+ } else if len(eArgs) == 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "add" || eArgs[0] == "del") {
+ if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX, eArgs, nil); err != nil {
+ return err
+ }
+ return nil
+ }
+ parser := flags.NewParser(nil, flags.Default)
+ parser.Usage = "policy prefix [OPTIONS]\n gobgp policy prefix"
+ parser.AddCommand(CMD_ADD, "subcommand for add route to policy prefix", "", &PolicyPrefixAddCommand{})
+ parser.AddCommand(CMD_DEL, "subcommand for delete route from policy prefix", "", &PolicyPrefixDelCommand{})
+ parser.ParseArgs(eArgs)
+ return nil
+}
+
+type PolicyPrefixAddCommand struct{}
+
+func parsePrefixSet(eArgs []string) (*api.PrefixSet, error) {
+ _, ipNet, e := net.ParseCIDR(eArgs[1])
+ if e != nil {
+ return nil, fmt.Errorf("prefix is invalid format %s\nplease enter ipv4 or ipv6 format", eArgs[1])
+ }
+ mask, _ := ipNet.Mask.Size()
+ prefix := &api.Prefix{
+ Address: ipNet.IP.String(),
+ MaskLength: uint32(mask),
+ }
+
+ if len(eArgs) == 3 {
+ maskRange := eArgs[2]
+ idx := strings.Index(maskRange, "..")
+ if idx == -1 {
+ return nil, fmt.Errorf("mask length range invalid format %s", maskRange)
+ }
+ var min, max int
+ var e error
+ if idx != 0 {
+ if min, e = strconv.Atoi(maskRange[:idx]); e != nil {
+ return nil, fmt.Errorf("mask length range invalid format %s", maskRange)
+ }
+ }
+ if idx != len(maskRange)-1 {
+ if max, e = strconv.Atoi(maskRange[idx+2:]); e != nil {
+ return nil, fmt.Errorf("mask length range invalid format %s", maskRange)
+ }
+ }
+ if ipv4 := ipNet.IP.To4(); ipv4 != nil {
+ if min < 0 || 32 < max {
+ return nil, fmt.Errorf("ipv4 mask length range outside scope %s", maskRange)
+ }
+ } else {
+ if min < 0 || 128 < max {
+ return nil, fmt.Errorf("ipv6 mask length range outside scope %s", maskRange)
+ }
+ }
+ if min >= max {
+ return nil, fmt.Errorf("mask length range invalid format %s\nTo a large value to the right from the left", maskRange)
+ }
+ prefix.MaskLengthRange = maskRange
+ }
+ prefixList := []*api.Prefix{prefix}
+ prefixSet := &api.PrefixSet{
+ PrefixSetName: eArgs[0],
+ PrefixList: prefixList,
+ }
+ return prefixSet, nil
+}
+
+func modPolicyPrefix(modtype string, eArgs []string) error {
+ prefixSet := &api.PrefixSet{}
+ var e error
+ var operation api.Operation
+
+ switch modtype {
+ case CMD_ADD:
+ if len(eArgs) < 2 {
+ return fmt.Errorf("policy prefix add <prefix name> <prefix> [<mask length renge>]")
+ }
+ if prefixSet, e = parsePrefixSet(eArgs); e != nil {
+ return e
+ }
+ operation = api.Operation_ADD
+ case CMD_DEL:
+ if len(eArgs) == 0 {
+ operation = api.Operation_DEL_ALL
+ } else if len(eArgs) == 1 {
+ prefixSet = &api.PrefixSet{
+ PrefixSetName: eArgs[0],
+ PrefixList: nil,
+ }
+ operation = api.Operation_DEL
+ } else {
+ if prefixSet, e = parsePrefixSet(eArgs); e != nil {
+ return e
+ }
+ operation = api.Operation_DEL
+ }
+ }
+
+ arg := &api.PolicyArguments{
+ Resource: api.Resource_POLICY_PREFIX,
+ Operation: operation,
+ PrefixSet: prefixSet,
+ }
+ stream, err := client.ModPolicyPrefix(context.Background())
+ if err != nil {
+ return err
+ }
+ err = stream.Send(arg)
+ if err != nil {
+ return err
+ }
+ stream.CloseSend()
+
+ res, e := stream.Recv()
+ if e != nil {
+ return e
+ }
+ if res.Code != api.Error_SUCCESS {
+ return fmt.Errorf("error: code: %d, msg: %s", res.Code, res.Msg)
+ }
+ return nil
+}
+
+func (x *PolicyPrefixAddCommand) Execute(args []string) error {
+ eArgs := extractArgs(CMD_ADD)
+ if len(eArgs) == 0 || len(eArgs) > 3 {
+ return fmt.Errorf("policy prefix add <prefix name> <prefix> [<mask length renge>]")
+ } else if !(eArgs[0] == "-h" || eArgs[0] == "--help") {
+ if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX+"_"+CMD_ADD, eArgs, nil); err != nil {
+ return err
+ }
+ return nil
+ }
+ parser := flags.NewParser(nil, flags.Default)
+ parser.Usage = "policy prefix add <prefix name> <prefix> [mask length renge]"
+ parser.ParseArgs(eArgs)
+ return nil
+}
+
+type PolicyPrefixDelCommand struct{}
+
+func (x *PolicyPrefixDelCommand) Execute(args []string) error {
+ eArgs := extractArgs(CMD_DEL)
+ if len(eArgs) > 3 {
+ return fmt.Errorf("policy prefix del [<prefix name> [<prefix> [<mask length range>]]] ")
+ } else if len(eArgs) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "all") {
+ if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX+"_"+CMD_DEL, eArgs, nil); err != nil {
+ return err
+ }
+ return nil
+ }
+ parser := flags.NewParser(nil, flags.Default)
+ parser.Usage = "policy prefix del [ <prefix name> <prefix> ]\n policy prefix del"
+ parser.AddCommand(CMD_ALL, "subcommand for delete all route from policy prefix", "", &PolicyPrefixDelAllCommand{})
+ parser.ParseArgs(eArgs)
+ return nil
+}
+
+type PolicyPrefixDelAllCommand struct{}
+
+func (x *PolicyPrefixDelAllCommand) Execute(args []string) error {
+ eArgs := extractArgs(CMD_ALL)
+ if len(eArgs) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help") {
+ return fmt.Errorf("Argument dose not input")
+ } else if len(eArgs) == 0 {
+ if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX+"_"+CMD_DEL, eArgs, nil); err != nil {
+ return err
+ }
+ }
+
+ parser := flags.NewParser(nil, flags.Default)
+ parser.Usage = "policy prefix del all"
+ parser.ParseArgs(eArgs)
+ return nil
+}
+
var globalOpts struct {
Host string `short:"u" long:"url" description:"specifying an url" default:"127.0.0.1"`
Port int `short:"p" long:"port" description:"specifying a port" default:"8080"`
@@ -1098,13 +1404,15 @@ var neighborsOpts struct {
}
func main() {
- cmds = []string{CMD_GLOBAL, CMD_NEIGHBOR, CMD_RIB, CMD_ADD, CMD_DEL, CMD_LOCAL, CMD_ADJ_IN, CMD_ADJ_OUT,
- CMD_RESET, CMD_SOFT_RESET, CMD_SOFT_RESET_IN, CMD_SOFT_RESET_OUT, CMD_SHUTDOWN, CMD_ENABLE, CMD_DISABLE}
+ cmds = []string{CMD_GLOBAL, CMD_NEIGHBOR, CMD_POLICY, CMD_RIB, CMD_ADD, CMD_DEL, CMD_LOCAL, CMD_ADJ_IN, CMD_ADJ_OUT,
+ CMD_RESET, CMD_SOFT_RESET, CMD_SOFT_RESET_IN, CMD_SOFT_RESET_OUT, CMD_SHUTDOWN, CMD_ENABLE, CMD_DISABLE,
+ CMD_PREFIX, CMD_ALL}
eArgs := extractArgs("")
parser := flags.NewParser(&globalOpts, flags.Default)
parser.AddCommand(CMD_GLOBAL, "subcommand for global", "", &GlobalCommand{})
parser.AddCommand(CMD_NEIGHBOR, "subcommand for neighbor", "", &NeighborCommand{})
+ parser.AddCommand(CMD_POLICY, "subcommand for policy", "", &PolicyCommand{})
if _, err := parser.ParseArgs(eArgs); err != nil {
os.Exit(1)
}
diff --git a/server/grpc_server.go b/server/grpc_server.go
index c218a4ac..cc0a0e16 100644
--- a/server/grpc_server.go
+++ b/server/grpc_server.go
@@ -43,6 +43,11 @@ const (
REQ_GLOBAL_RIB
REQ_GLOBAL_ADD
REQ_GLOBAL_DELETE
+ REQ_POLICY_PREFIX
+ REQ_POLICY_PREFIXES
+ REQ_POLICY_PREFIX_ADD
+ REQ_POLICY_PREFIX_DELETE
+ REQ_POLICY_PREFIXES_DELETE
)
const GRPC_PORT = 8080
@@ -259,6 +264,116 @@ func (s *Server) ModPath(stream api.Grpc_ModPathServer) error {
}
}
}
+func (s *Server) getPolicies(reqType int, arg *api.PolicyArguments, stream interface{}) error {
+ var rf bgp.RouteFamily
+ req := NewGrpcRequest(reqType, "", rf, nil)
+ s.bgpServerCh <- req
+ for res := range req.ResponseCh {
+ if err := res.Err(); err != nil {
+ log.Debug(err.Error())
+ return err
+ }
+ var err error
+ switch arg.Resource {
+ case api.Resource_POLICY_PREFIX:
+ err = stream.(api.Grpc_GetPolicyPrefixesServer).Send(res.Data.(*api.PrefixSet))
+ default:
+ return fmt.Errorf("unsupported resource type: %v", arg.Resource)
+ }
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (s *Server) getPolicy(arg *api.PolicyArguments) (interface{}, error) {
+ var rf bgp.RouteFamily
+ var reqType int
+ switch arg.Resource {
+ case api.Resource_POLICY_PREFIX:
+ reqType = REQ_POLICY_PREFIX
+ default:
+ return nil, fmt.Errorf("unsupported resource type: %v", arg.Resource)
+ }
+ req := NewGrpcRequest(reqType, "", rf, arg.Name)
+ s.bgpServerCh <- req
+
+ res := <-req.ResponseCh
+ if err := res.Err(); err != nil {
+ log.Debug(err.Error())
+ return nil, err
+ }
+ return res.Data, nil
+}
+
+func (s *Server) modPolicy(arg *api.PolicyArguments, stream interface{}) error {
+ var rf bgp.RouteFamily
+ var reqType int
+ switch arg.Resource {
+ case api.Resource_POLICY_PREFIX:
+ switch arg.Operation {
+ case api.Operation_ADD:
+ reqType = REQ_POLICY_PREFIX_ADD
+ case api.Operation_DEL:
+ reqType = REQ_POLICY_PREFIX_DELETE
+ case api.Operation_DEL_ALL:
+ reqType = REQ_POLICY_PREFIXES_DELETE
+ default:
+ return fmt.Errorf("unsupported operation: %s", arg.Operation)
+ }
+ req := NewGrpcRequest(reqType, "", rf, arg.PrefixSet)
+ s.bgpServerCh <- req
+
+ res := <-req.ResponseCh
+ if err := res.Err(); err != nil {
+ log.Debug(err.Error())
+ return err
+ }
+
+ err := stream.(api.Grpc_ModPolicyPrefixServer).Send(&api.Error{
+ Code: api.Error_SUCCESS,
+ })
+
+ if err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("unsupported resource type: %v", arg.Resource)
+ }
+ return nil
+
+}
+
+func (s *Server) GetPolicyPrefixes(arg *api.PolicyArguments, stream api.Grpc_GetPolicyPrefixesServer) error {
+ if err := s.getPolicies(REQ_POLICY_PREFIXES, arg, stream); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (s *Server) GetPolicyPrefix(ctx context.Context, arg *api.PolicyArguments) (*api.PrefixSet, error) {
+ data, err := s.getPolicy(arg)
+ if err != nil {
+ return nil, err
+ }
+ return data.(*api.PrefixSet), nil
+}
+
+func (s *Server) ModPolicyPrefix(stream api.Grpc_ModPolicyPrefixServer) error {
+ for {
+ arg, err := stream.Recv()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ if err := s.modPolicy(arg, stream); err != nil {
+ return err
+ }
+ return nil
+ }
+}
type GrpcRequest struct {
RequestType int
diff --git a/server/server.go b/server/server.go
index 92b9b606..b2096d49 100644
--- a/server/server.go
+++ b/server/server.go
@@ -18,10 +18,12 @@ package server
import (
"fmt"
log "github.com/Sirupsen/logrus"
+ "github.com/osrg/gobgp/api"
"github.com/osrg/gobgp/config"
"github.com/osrg/gobgp/policy"
"net"
"os"
+ "reflect"
"strconv"
)
@@ -65,6 +67,7 @@ type BgpServer struct {
globalRib *Peer
policyUpdateCh chan config.RoutingPolicy
policyMap map[string]*policy.Policy
+ routingPolicy config.RoutingPolicy
}
func NewBgpServer(port int) *BgpServer {
@@ -219,12 +222,7 @@ func (server *BgpServer) Serve() {
case grpcReq := <-server.GrpcReqCh:
server.handleGrpc(grpcReq)
case pl := <-server.policyUpdateCh:
- server.SetPolicy(pl)
- msg := &serverMsg{
- msgType: SRV_MSG_POLICY_UPDATED,
- msgData: server.policyMap,
- }
- sendServerMsgToAll(server.peerMap, msg)
+ server.handlePolicy(pl)
}
}
}
@@ -266,6 +264,16 @@ func (server *BgpServer) SetPolicy(pl config.RoutingPolicy) {
pMap[p.Name] = policy.NewPolicy(p.Name, p, df)
}
server.policyMap = pMap
+ server.routingPolicy = pl
+}
+
+func (server *BgpServer) handlePolicy(pl config.RoutingPolicy) {
+ server.SetPolicy(pl)
+ msg := &serverMsg{
+ msgType: SRV_MSG_POLICY_UPDATED,
+ msgData: server.policyMap,
+ }
+ sendServerMsgToAll(server.peerMap, msg)
}
func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) {
@@ -318,5 +326,169 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) {
grpcReq.ResponseCh <- result
close(grpcReq.ResponseCh)
}
+ case REQ_POLICY_PREFIXES:
+ info := server.routingPolicy.DefinedSets.PrefixSetList
+ result := &GrpcResponse{}
+ if len(info) > 0 {
+ for _, ps := range info {
+ resPrefixSet := prefixToApiStruct(ps)
+ result = &GrpcResponse{
+ Data: resPrefixSet,
+ }
+ grpcReq.ResponseCh <- result
+ }
+ } else {
+ result.ResponseErr = fmt.Errorf("Policy Prefix is not exist.")
+ grpcReq.ResponseCh <- result
+ }
+ close(grpcReq.ResponseCh)
+ case REQ_POLICY_PREFIX:
+ name := grpcReq.Data.(string)
+ info := server.routingPolicy.DefinedSets.PrefixSetList
+ result := &GrpcResponse{}
+ resPrefixSet := &api.PrefixSet{}
+ for _, ps := range info {
+ if ps.PrefixSetName == name {
+ resPrefixSet = prefixToApiStruct(ps)
+ break
+ }
+ }
+ if len(resPrefixSet.PrefixList) > 0 {
+ result = &GrpcResponse{
+ Data: resPrefixSet,
+ }
+ grpcReq.ResponseCh <- result
+ } else {
+ result.ResponseErr = fmt.Errorf("Policy Prefix that has %v does not exist.", name)
+ grpcReq.ResponseCh <- result
+ }
+ close(grpcReq.ResponseCh)
+ case REQ_POLICY_PREFIX_ADD:
+ reqPrefixSet := grpcReq.Data.(*api.PrefixSet)
+ conPrefixSetList := server.routingPolicy.DefinedSets.PrefixSetList
+ result := &GrpcResponse{}
+ isReqPrefixSet, prefixSet := prefixToConfigStruct(reqPrefixSet)
+ if !isReqPrefixSet {
+ result.ResponseErr = fmt.Errorf("dose not reqest of policy prefix.")
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ }
+ idxPrefixSet, idxPrefix := findPrefixSet(conPrefixSetList, reqPrefixSet, prefixSet)
+ if idxPrefixSet == -1 {
+ conPrefixSetList = append(conPrefixSetList, prefixSet)
+ } else {
+ if idxPrefix == -1 {
+ conPrefixSetList[idxPrefixSet].PrefixList = append(conPrefixSetList[idxPrefixSet].PrefixList, prefixSet.PrefixList[0])
+ }
+ }
+ server.routingPolicy.DefinedSets.PrefixSetList = conPrefixSetList
+ server.handlePolicy(server.routingPolicy)
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ case REQ_POLICY_PREFIX_DELETE:
+ reqPrefixSet := grpcReq.Data.(*api.PrefixSet)
+ conPrefixSetList := server.routingPolicy.DefinedSets.PrefixSetList
+ result := &GrpcResponse{}
+ isReqPrefixSet, prefixSet := prefixToConfigStruct(reqPrefixSet)
+ if isReqPrefixSet {
+ idxPrefixSet, idxPrefix := findPrefixSet(conPrefixSetList, reqPrefixSet, prefixSet)
+ if idxPrefixSet == -1 {
+ result.ResponseErr = fmt.Errorf("Policy Prefix %v %v/%v %v does not exist.", prefixSet.PrefixSetName,
+ prefixSet.PrefixList[0].Address, prefixSet.PrefixList[0].Masklength, prefixSet.PrefixList[0].MasklengthRange)
+ } else {
+ if idxPrefix == -1 {
+ result.ResponseErr = fmt.Errorf("Policy Prefix %v %v/%v %v does not exist.", prefixSet.PrefixSetName,
+ prefixSet.PrefixList[0].Address, prefixSet.PrefixList[0].Masklength, prefixSet.PrefixList[0].MasklengthRange)
+ } else {
+ copy(conPrefixSetList[idxPrefixSet].PrefixList[idxPrefix:], conPrefixSetList[idxPrefixSet].PrefixList[idxPrefix+1:])
+ conPrefixSetList[idxPrefixSet].PrefixList = conPrefixSetList[idxPrefixSet].PrefixList[:len(conPrefixSetList[idxPrefixSet].PrefixList)-1]
+ }
+ }
+ } else {
+ idxPrefixSet := -1
+ for i, conPrefixSet := range conPrefixSetList {
+ if conPrefixSet.PrefixSetName == reqPrefixSet.PrefixSetName {
+ idxPrefixSet = i
+ break
+ }
+ }
+ if idxPrefixSet == -1 {
+ result.ResponseErr = fmt.Errorf("Policy Prefix %v does not exist.", prefixSet.PrefixSetName)
+ } else {
+ copy(conPrefixSetList[idxPrefixSet:], conPrefixSetList[idxPrefixSet+1:])
+ conPrefixSetList = conPrefixSetList[:len(conPrefixSetList)-1]
+ }
+ }
+ server.routingPolicy.DefinedSets.PrefixSetList = conPrefixSetList
+ server.handlePolicy(server.routingPolicy)
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ case REQ_POLICY_PREFIXES_DELETE:
+ result := &GrpcResponse{}
+ pl := config.RoutingPolicy{}
+ server.handlePolicy(pl)
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ }
+}
+
+func findPrefixSet(conPrefixSetList []config.PrefixSet, reqPrefixSet *api.PrefixSet, prefixSet config.PrefixSet) (int, int) {
+ idxPrefixSet := -1
+ idxPrefix := -1
+ for i, conPrefixSet := range conPrefixSetList {
+ if conPrefixSet.PrefixSetName == reqPrefixSet.PrefixSetName {
+ idxPrefixSet = i
+ for j, conPrefix := range conPrefixSet.PrefixList {
+ if reflect.DeepEqual(conPrefix.Address, prefixSet.PrefixList[0].Address) && conPrefix.Masklength == prefixSet.PrefixList[0].Masklength &&
+ conPrefix.MasklengthRange == prefixSet.PrefixList[0].MasklengthRange {
+ idxPrefix = j
+ break
+ }
+ }
+ }
+ }
+ return idxPrefixSet, idxPrefix
+}
+
+func prefixToApiStruct(ps config.PrefixSet) *api.PrefixSet {
+ resPrefixList := make([]*api.Prefix, 0)
+ for _, p := range ps.PrefixList {
+ resPrefix := &api.Prefix{
+ Address: p.Address.String(),
+ MaskLength: uint32(p.Masklength),
+ MaskLengthRange: p.MasklengthRange,
+ }
+ resPrefixList = append(resPrefixList, resPrefix)
+ }
+ resPrefixSet := &api.PrefixSet{
+ PrefixSetName: ps.PrefixSetName,
+ PrefixList: resPrefixList,
+ }
+ return resPrefixSet
+}
+
+func prefixToConfigStruct(reqPrefixSet *api.PrefixSet) (bool, config.PrefixSet) {
+ var prefix config.Prefix
+ var prefixSet config.PrefixSet
+ isReqPrefixSet := true
+ if reqPrefixSet.PrefixList != nil {
+ prefix = config.Prefix{
+ Address: net.ParseIP(reqPrefixSet.PrefixList[0].Address),
+ Masklength: uint8(reqPrefixSet.PrefixList[0].MaskLength),
+ MasklengthRange: reqPrefixSet.PrefixList[0].MaskLengthRange,
+ }
+ prefixList := []config.Prefix{prefix}
+
+ prefixSet = config.PrefixSet{
+ PrefixSetName: reqPrefixSet.PrefixSetName,
+ PrefixList: prefixList,
+ }
+ } else {
+ isReqPrefixSet = false
+ prefixSet = config.PrefixSet{
+ PrefixSetName: reqPrefixSet.PrefixSetName,
+ PrefixList: nil,
+ }
}
+ return isReqPrefixSet, prefixSet
}