diff options
-rw-r--r-- | api/gobgp.pb.go | 47 | ||||
-rw-r--r-- | api/gobgp.proto | 7 | ||||
-rw-r--r-- | server/grpc_server.go | 12 | ||||
-rw-r--r-- | server/server.go | 45 | ||||
-rw-r--r-- | table/policy.go | 179 |
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) |