summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--api/gobgp.pb.go47
-rw-r--r--api/gobgp.proto7
-rw-r--r--server/grpc_server.go12
-rw-r--r--server/server.go45
-rw-r--r--table/policy.go179
5 files changed, 287 insertions, 3 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go
index 577c29ed..3b583fe7 100644
--- a/api/gobgp.pb.go
+++ b/api/gobgp.pb.go
@@ -15,6 +15,7 @@ It has these top-level messages:
PolicyArguments
MrtArguments
ModVrfArguments
+ ModDefinedSetArguments
Path
Destination
PeerConf
@@ -109,17 +110,20 @@ const (
Operation_ADD Operation = 0
Operation_DEL Operation = 1
Operation_DEL_ALL Operation = 2
+ Operation_REPLACE Operation = 3
)
var Operation_name = map[int32]string{
0: "ADD",
1: "DEL",
2: "DEL_ALL",
+ 3: "REPLACE",
}
var Operation_value = map[string]int32{
"ADD": 0,
"DEL": 1,
"DEL_ALL": 2,
+ "REPLACE": 3,
}
func (x Operation) String() string {
@@ -282,6 +286,22 @@ func (m *ModVrfArguments) GetVrf() *Vrf {
return nil
}
+type ModDefinedSetArguments struct {
+ Operation Operation `protobuf:"varint,1,opt,name=operation,enum=gobgpapi.Operation" json:"operation,omitempty"`
+ Set *DefinedSet `protobuf:"bytes,2,opt,name=set" json:"set,omitempty"`
+}
+
+func (m *ModDefinedSetArguments) Reset() { *m = ModDefinedSetArguments{} }
+func (m *ModDefinedSetArguments) String() string { return proto.CompactTextString(m) }
+func (*ModDefinedSetArguments) ProtoMessage() {}
+
+func (m *ModDefinedSetArguments) GetSet() *DefinedSet {
+ if m != nil {
+ return m.Set
+ }
+ return nil
+}
+
type Path struct {
Nlri []byte `protobuf:"bytes,1,opt,name=nlri,proto3" json:"nlri,omitempty"`
Pattrs [][]byte `protobuf:"bytes,2,rep,name=pattrs,proto3" json:"pattrs,omitempty"`
@@ -728,6 +748,7 @@ type GobgpApiClient interface {
ModVrf(ctx context.Context, in *ModVrfArguments, opts ...grpc.CallOption) (*Error, error)
GetDefinedSet(ctx context.Context, in *DefinedSet, opts ...grpc.CallOption) (*DefinedSet, error)
GetDefinedSets(ctx context.Context, in *DefinedSet, opts ...grpc.CallOption) (GobgpApi_GetDefinedSetsClient, error)
+ ModDefinedSet(ctx context.Context, in *ModDefinedSetArguments, opts ...grpc.CallOption) (*Error, error)
}
type gobgpApiClient struct {
@@ -1262,6 +1283,15 @@ func (x *gobgpApiGetDefinedSetsClient) Recv() (*DefinedSet, error) {
return m, nil
}
+func (c *gobgpApiClient) ModDefinedSet(ctx context.Context, in *ModDefinedSetArguments, opts ...grpc.CallOption) (*Error, error) {
+ out := new(Error)
+ err := grpc.Invoke(ctx, "/gobgpapi.GobgpApi/ModDefinedSet", in, out, c.cc, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
// Server API for GobgpApi service
type GobgpApiServer interface {
@@ -1290,6 +1320,7 @@ type GobgpApiServer interface {
ModVrf(context.Context, *ModVrfArguments) (*Error, error)
GetDefinedSet(context.Context, *DefinedSet) (*DefinedSet, error)
GetDefinedSets(*DefinedSet, GobgpApi_GetDefinedSetsServer) error
+ ModDefinedSet(context.Context, *ModDefinedSetArguments) (*Error, error)
}
func RegisterGobgpApiServer(s *grpc.Server, srv GobgpApiServer) {
@@ -1728,6 +1759,18 @@ func (x *gobgpApiGetDefinedSetsServer) Send(m *DefinedSet) error {
return x.ServerStream.SendMsg(m)
}
+func _GobgpApi_ModDefinedSet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error) (interface{}, error) {
+ in := new(ModDefinedSetArguments)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ out, err := srv.(GobgpApiServer).ModDefinedSet(ctx, in)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
var _GobgpApi_serviceDesc = grpc.ServiceDesc{
ServiceName: "gobgpapi.GobgpApi",
HandlerType: (*GobgpApiServer)(nil),
@@ -1780,6 +1823,10 @@ var _GobgpApi_serviceDesc = grpc.ServiceDesc{
MethodName: "GetDefinedSet",
Handler: _GobgpApi_GetDefinedSet_Handler,
},
+ {
+ MethodName: "ModDefinedSet",
+ Handler: _GobgpApi_ModDefinedSet_Handler,
+ },
},
Streams: []grpc.StreamDesc{
{
diff --git a/api/gobgp.proto b/api/gobgp.proto
index 7ef404f4..f6b59356 100644
--- a/api/gobgp.proto
+++ b/api/gobgp.proto
@@ -45,6 +45,7 @@ service GobgpApi {
rpc ModVrf(ModVrfArguments) returns (Error) {}
rpc GetDefinedSet(DefinedSet) returns (DefinedSet) {}
rpc GetDefinedSets(DefinedSet) returns (stream DefinedSet) {}
+ rpc ModDefinedSet(ModDefinedSetArguments) returns (Error) {}
}
message Error {
@@ -89,6 +90,11 @@ message ModVrfArguments {
Vrf vrf = 2;
}
+message ModDefinedSetArguments {
+ Operation operation = 1;
+ DefinedSet set = 2;
+}
+
enum Resource {
GLOBAL = 0;
LOCAL = 1;
@@ -107,6 +113,7 @@ enum Operation {
ADD = 0;
DEL = 1;
DEL_ALL = 2;
+ REPLACE = 3;
}
message Path {
diff --git a/server/grpc_server.go b/server/grpc_server.go
index c3f004df..e768c4c8 100644
--- a/server/grpc_server.go
+++ b/server/grpc_server.go
@@ -75,6 +75,7 @@ const (
REQ_MOD_PATH
REQ_GLOBAL_POLICY
REQ_DEFINED_SET
+ REQ_MOD_DEFINED_SET
)
const GRPC_PORT = 8080
@@ -519,6 +520,17 @@ func (s *Server) GetDefinedSets(arg *api.DefinedSet, stream api.GobgpApi_GetDefi
})
}
+func (s *Server) ModDefinedSet(ctx context.Context, arg *api.ModDefinedSetArguments) (*api.Error, error) {
+ none := &api.Error{}
+ req := NewGrpcRequest(REQ_MOD_DEFINED_SET, "", bgp.RouteFamily(0), arg)
+ s.bgpServerCh <- req
+ res := <-req.ResponseCh
+ if err := res.Err(); err != nil {
+ return none, err
+ }
+ return none, nil
+}
+
type GrpcRequest struct {
RequestType int
Name string
diff --git a/server/server.go b/server/server.go
index f60d4d6e..8867186c 100644
--- a/server/server.go
+++ b/server/server.go
@@ -1637,6 +1637,13 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
}
}
close(grpcReq.ResponseCh)
+ case REQ_MOD_DEFINED_SET:
+ if err := server.handleGrpcModDefinedSet(grpcReq); err != nil {
+ grpcReq.ResponseCh <- &GrpcResponse{
+ ResponseErr: err,
+ }
+ }
+ close(grpcReq.ResponseCh)
case REQ_POLICY_ROUTEPOLICY, REQ_POLICY_ROUTEPOLICIES:
info := server.policy.PolicyMap
typ := grpcReq.RequestType
@@ -1705,6 +1712,44 @@ func (server *BgpServer) handleGrpcGetDefinedSet(grpcReq *GrpcRequest) error {
return nil
}
+func (server *BgpServer) handleGrpcModDefinedSet(grpcReq *GrpcRequest) error {
+ arg := grpcReq.Data.(*api.ModDefinedSetArguments)
+ set := arg.Set
+ typ := table.DefinedType(set.Type)
+ name := set.Name
+ var err error
+ m, ok := server.policy.DefinedSetMap[typ]
+ if !ok {
+ return fmt.Errorf("invalid defined-set type: %d", typ)
+ }
+ d, ok := m[name]
+ if arg.Operation != api.Operation_ADD && !ok {
+ return fmt.Errorf("not found defined-set: %s", name)
+ }
+ s, err := table.NewDefinedSetFromApiStruct(set)
+ if err != nil {
+ return err
+ }
+ switch arg.Operation {
+ case api.Operation_ADD:
+ if ok {
+ err = d.Append(s)
+ } else {
+ m[name] = s
+ }
+ case api.Operation_DEL:
+ err = d.Remove(s)
+ case api.Operation_DEL_ALL:
+ if server.policy.InUse(d) {
+ return fmt.Errorf("can't delete. defined-set %s is in use", name)
+ }
+ delete(m, name)
+ case api.Operation_REPLACE:
+ err = d.Replace(s)
+ }
+ return err
+}
+
func (server *BgpServer) handleMrt(grpcReq *GrpcRequest) {
now := uint32(time.Now().Unix())
view := ""
diff --git a/table/policy.go b/table/policy.go
index 843eb7d2..5fd406f4 100644
--- a/table/policy.go
+++ b/table/policy.go
@@ -137,6 +137,9 @@ type DefinedSet interface {
Type() DefinedType
Name() string
ToApiStruct() *api.DefinedSet
+ Append(DefinedSet) error
+ Remove(DefinedSet) error
+ Replace(DefinedSet) error
}
type DefinedSetMap map[DefinedType]map[string]DefinedSet
@@ -170,6 +173,16 @@ func (p *Prefix) Match(path *Path) bool {
return (p.MasklengthRangeMin <= pMasklen && pMasklen <= p.MasklengthRangeMax) && p.Prefix.Contains(pAddr)
}
+func (lhs *Prefix) Equal(rhs *Prefix) bool {
+ if lhs == rhs {
+ return true
+ }
+ if rhs == nil {
+ return false
+ }
+ return lhs.Prefix.String() == rhs.Prefix.String() && lhs.MasklengthRangeMin == rhs.MasklengthRangeMin && lhs.MasklengthRangeMax == rhs.MasklengthRangeMax
+}
+
func (p *Prefix) ToApiStruct() *api.Prefix {
return &api.Prefix{
IpPrefix: p.Prefix.String(),
@@ -248,6 +261,46 @@ func (s *PrefixSet) Type() DefinedType {
return DEFINED_TYPE_PREFIX
}
+func (lhs *PrefixSet) Append(arg DefinedSet) error {
+ rhs, ok := arg.(*PrefixSet)
+ if !ok {
+ return fmt.Errorf("type cast failed")
+ }
+ lhs.list = append(lhs.list, rhs.list...)
+ return nil
+}
+
+func (lhs *PrefixSet) Remove(arg DefinedSet) error {
+ rhs, ok := arg.(*PrefixSet)
+ if !ok {
+ return fmt.Errorf("type cast failed")
+ }
+ ps := make([]*Prefix, 0, len(lhs.list))
+ for _, x := range lhs.list {
+ found := false
+ for _, y := range rhs.list {
+ if x.Equal(y) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ ps = append(ps, x)
+ }
+ }
+ lhs.list = ps
+ return nil
+}
+
+func (lhs *PrefixSet) Replace(arg DefinedSet) error {
+ rhs, ok := arg.(*PrefixSet)
+ if !ok {
+ return fmt.Errorf("type cast failed")
+ }
+ lhs.list = rhs.list
+ return nil
+}
+
func (s *PrefixSet) ToApiStruct() *api.DefinedSet {
list := make([]*api.Prefix, 0, len(s.list))
for _, p := range s.list {
@@ -313,6 +366,46 @@ func (s *NeighborSet) Type() DefinedType {
return DEFINED_TYPE_NEIGHBOR
}
+func (lhs *NeighborSet) Append(arg DefinedSet) error {
+ rhs, ok := arg.(*NeighborSet)
+ if !ok {
+ return fmt.Errorf("type cast failed")
+ }
+ lhs.list = append(lhs.list, rhs.list...)
+ return nil
+}
+
+func (lhs *NeighborSet) Remove(arg DefinedSet) error {
+ rhs, ok := arg.(*NeighborSet)
+ if !ok {
+ return fmt.Errorf("type cast failed")
+ }
+ ps := make([]net.IP, 0, len(lhs.list))
+ for _, x := range lhs.list {
+ found := false
+ for _, y := range rhs.list {
+ if x.Equal(y) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ ps = append(ps, x)
+ }
+ }
+ lhs.list = ps
+ return nil
+}
+
+func (lhs *NeighborSet) Replace(arg DefinedSet) error {
+ rhs, ok := arg.(*NeighborSet)
+ if !ok {
+ return fmt.Errorf("type cast failed")
+ }
+ lhs.list = rhs.list
+ return nil
+}
+
func (s *NeighborSet) ToApiStruct() *api.DefinedSet {
list := make([]string, 0, len(s.list))
for _, n := range s.list {
@@ -375,6 +468,46 @@ func (s *regExpSet) Type() DefinedType {
return s.typ
}
+func (lhs *regExpSet) Append(arg DefinedSet) error {
+ rhs, ok := arg.(*regExpSet)
+ if !ok {
+ return fmt.Errorf("type cast failed")
+ }
+ lhs.list = append(lhs.list, rhs.list...)
+ return nil
+}
+
+func (lhs *regExpSet) Remove(arg DefinedSet) error {
+ rhs, ok := arg.(*regExpSet)
+ if !ok {
+ return fmt.Errorf("type cast failed")
+ }
+ ps := make([]*regexp.Regexp, 0, len(lhs.list))
+ for _, x := range lhs.list {
+ found := false
+ for _, y := range rhs.list {
+ if x.String() == y.String() {
+ found = true
+ break
+ }
+ }
+ if !found {
+ ps = append(ps, x)
+ }
+ }
+ lhs.list = ps
+ return nil
+}
+
+func (lhs *regExpSet) Replace(arg DefinedSet) error {
+ rhs, ok := arg.(*regExpSet)
+ if !ok {
+ return fmt.Errorf("type cast failed")
+ }
+ lhs.list = rhs.list
+ return nil
+}
+
func (s *regExpSet) ToApiStruct() *api.DefinedSet {
list := make([]string, 0, len(s.list))
for _, exp := range s.list {
@@ -586,8 +719,26 @@ func NewExtCommunitySet(c config.ExtCommunitySet) (*ExtCommunitySet, error) {
}, nil
}
+func NewDefinedSetFromApiStruct(a *api.DefinedSet) (DefinedSet, error) {
+ switch DefinedType(a.Type) {
+ case DEFINED_TYPE_PREFIX:
+ return NewPrefixSetFromApiStruct(a)
+ case DEFINED_TYPE_NEIGHBOR:
+ return NewNeighborSetFromApiStruct(a)
+ case DEFINED_TYPE_AS_PATH:
+ return NewAsPathSetFromApiStruct(a)
+ case DEFINED_TYPE_COMMUNITY:
+ return NewCommunitySetFromApiStruct(a)
+ case DEFINED_TYPE_EXT_COMMUNITY:
+ return NewExtCommunitySetFromApiStruct(a)
+ default:
+ return nil, fmt.Errorf("invalid defined type")
+ }
+}
+
type Condition interface {
Evaluate(*Path) bool
+ Set() DefinedSet
}
type PrefixCondition struct {
@@ -761,7 +912,7 @@ type AsPathCondition struct {
option MatchOption
}
-func (c *AsPathCondition) Set() *AsPathSet {
+func (c *AsPathCondition) Set() DefinedSet {
return c.set
}
@@ -838,7 +989,7 @@ type CommunityCondition struct {
option MatchOption
}
-func (c *CommunityCondition) Set() *CommunitySet {
+func (c *CommunityCondition) Set() DefinedSet {
return c.set
}
@@ -918,7 +1069,7 @@ type ExtCommunityCondition struct {
option MatchOption
}
-func (c *ExtCommunityCondition) Set() *ExtCommunitySet {
+func (c *ExtCommunityCondition) Set() DefinedSet {
return c.set
}
@@ -1029,6 +1180,10 @@ func (c *AsPathLengthCondition) Evaluate(path *Path) bool {
return result
}
+func (c *AsPathLengthCondition) Set() DefinedSet {
+ return nil
+}
+
func (c *AsPathLengthCondition) ToApiStruct() *api.AsPathLength {
return &api.AsPathLength{
Length: c.length,
@@ -1072,6 +1227,10 @@ func (c *RpkiValidationCondition) Evaluate(path *Path) bool {
return c.result == path.Validation
}
+func (c *RpkiValidationCondition) Set() DefinedSet {
+ return nil
+}
+
func NewRpkiValidationConditionFromApiStruct(a int32) (*RpkiValidationCondition, error) {
typ := config.RpkiValidationResultType(a)
return NewRpkiValidationCondition(typ)
@@ -1854,6 +2013,20 @@ type RoutingPolicy struct {
PolicyMap map[string]*Policy
}
+func (r *RoutingPolicy) InUse(d DefinedSet) bool {
+ name := d.Name()
+ for _, p := range r.PolicyMap {
+ for _, s := range p.Statements {
+ for _, c := range s.Conditions {
+ if c.Set().Name() == name {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
func NewRoutingPolicy(c config.RoutingPolicy) (*RoutingPolicy, error) {
dmap := make(map[DefinedType]map[string]DefinedSet)
dmap[DEFINED_TYPE_PREFIX] = make(map[string]DefinedSet)