summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--api/gobgp.pb.go44
-rw-r--r--api/gobgp.proto6
-rw-r--r--server/grpc_server.go5
-rw-r--r--server/server.go36
-rw-r--r--table/policy.go206
5 files changed, 296 insertions, 1 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go
index d3bdc1e4..e3d4e8b3 100644
--- a/api/gobgp.pb.go
+++ b/api/gobgp.pb.go
@@ -16,6 +16,7 @@ It has these top-level messages:
MrtArguments
ModVrfArguments
ModDefinedSetArguments
+ ModStatementArguments
Path
Destination
PeerConf
@@ -302,6 +303,22 @@ func (m *ModDefinedSetArguments) GetSet() *DefinedSet {
return nil
}
+type ModStatementArguments struct {
+ Operation Operation `protobuf:"varint,1,opt,name=operation,enum=gobgpapi.Operation" json:"operation,omitempty"`
+ Statement *Statement `protobuf:"bytes,2,opt,name=statement" json:"statement,omitempty"`
+}
+
+func (m *ModStatementArguments) Reset() { *m = ModStatementArguments{} }
+func (m *ModStatementArguments) String() string { return proto.CompactTextString(m) }
+func (*ModStatementArguments) ProtoMessage() {}
+
+func (m *ModStatementArguments) GetStatement() *Statement {
+ if m != nil {
+ return m.Statement
+ }
+ 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"`
@@ -751,6 +768,7 @@ type GobgpApiClient interface {
ModDefinedSet(ctx context.Context, in *ModDefinedSetArguments, opts ...grpc.CallOption) (*Error, error)
GetStatement(ctx context.Context, in *Statement, opts ...grpc.CallOption) (*Statement, error)
GetStatements(ctx context.Context, in *Statement, opts ...grpc.CallOption) (GobgpApi_GetStatementsClient, error)
+ ModStatement(ctx context.Context, in *ModStatementArguments, opts ...grpc.CallOption) (*Error, error)
}
type gobgpApiClient struct {
@@ -1335,6 +1353,15 @@ func (x *gobgpApiGetStatementsClient) Recv() (*Statement, error) {
return m, nil
}
+func (c *gobgpApiClient) ModStatement(ctx context.Context, in *ModStatementArguments, opts ...grpc.CallOption) (*Error, error) {
+ out := new(Error)
+ err := grpc.Invoke(ctx, "/gobgpapi.GobgpApi/ModStatement", in, out, c.cc, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
// Server API for GobgpApi service
type GobgpApiServer interface {
@@ -1366,6 +1393,7 @@ type GobgpApiServer interface {
ModDefinedSet(context.Context, *ModDefinedSetArguments) (*Error, error)
GetStatement(context.Context, *Statement) (*Statement, error)
GetStatements(*Statement, GobgpApi_GetStatementsServer) error
+ ModStatement(context.Context, *ModStatementArguments) (*Error, error)
}
func RegisterGobgpApiServer(s *grpc.Server, srv GobgpApiServer) {
@@ -1849,6 +1877,18 @@ func (x *gobgpApiGetStatementsServer) Send(m *Statement) error {
return x.ServerStream.SendMsg(m)
}
+func _GobgpApi_ModStatement_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error) (interface{}, error) {
+ in := new(ModStatementArguments)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ out, err := srv.(GobgpApiServer).ModStatement(ctx, in)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
var _GobgpApi_serviceDesc = grpc.ServiceDesc{
ServiceName: "gobgpapi.GobgpApi",
HandlerType: (*GobgpApiServer)(nil),
@@ -1909,6 +1949,10 @@ var _GobgpApi_serviceDesc = grpc.ServiceDesc{
MethodName: "GetStatement",
Handler: _GobgpApi_GetStatement_Handler,
},
+ {
+ MethodName: "ModStatement",
+ Handler: _GobgpApi_ModStatement_Handler,
+ },
},
Streams: []grpc.StreamDesc{
{
diff --git a/api/gobgp.proto b/api/gobgp.proto
index ad070e60..84eb8c74 100644
--- a/api/gobgp.proto
+++ b/api/gobgp.proto
@@ -48,6 +48,7 @@ service GobgpApi {
rpc ModDefinedSet(ModDefinedSetArguments) returns (Error) {}
rpc GetStatement(Statement) returns (Statement) {}
rpc GetStatements(Statement) returns (stream Statement) {}
+ rpc ModStatement(ModStatementArguments) returns (Error) {}
}
message Error {
@@ -97,6 +98,11 @@ message ModDefinedSetArguments {
DefinedSet set = 2;
}
+message ModStatementArguments {
+ Operation operation = 1;
+ Statement statement = 2;
+}
+
enum Resource {
GLOBAL = 0;
LOCAL = 1;
diff --git a/server/grpc_server.go b/server/grpc_server.go
index 6753417b..d68ecd96 100644
--- a/server/grpc_server.go
+++ b/server/grpc_server.go
@@ -62,6 +62,7 @@ const (
REQ_DEFINED_SET
REQ_MOD_DEFINED_SET
REQ_STATEMENT
+ REQ_MOD_STATEMENT
)
const GRPC_PORT = 8080
@@ -481,6 +482,10 @@ func (s *Server) GetStatements(arg *api.Statement, stream api.GobgpApi_GetStatem
})
}
+func (s *Server) ModStatement(ctx context.Context, arg *api.ModStatementArguments) (*api.Error, error) {
+ return s.mod(REQ_MOD_STATEMENT, arg)
+}
+
type GrpcRequest struct {
RequestType int
Name string
diff --git a/server/server.go b/server/server.go
index e25d314f..69c27f14 100644
--- a/server/server.go
+++ b/server/server.go
@@ -1650,6 +1650,12 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
}
}
close(grpcReq.ResponseCh)
+ case REQ_MOD_STATEMENT:
+ err := server.handleGrpcModStatement(grpcReq)
+ grpcReq.ResponseCh <- &GrpcResponse{
+ ResponseErr: err,
+ }
+ close(grpcReq.ResponseCh)
case REQ_POLICY_ROUTEPOLICY, REQ_POLICY_ROUTEPOLICIES:
info := server.policy.PolicyMap
typ := grpcReq.RequestType
@@ -1783,6 +1789,36 @@ func (server *BgpServer) handleGrpcGetStatement(grpcReq *GrpcRequest) error {
return nil
}
+func (server *BgpServer) handleGrpcModStatement(grpcReq *GrpcRequest) error {
+ arg := grpcReq.Data.(*api.ModStatementArguments)
+ s, err := table.NewStatementFromApiStruct(arg.Statement, server.policy.DefinedSetMap)
+ if err != nil {
+ return err
+ }
+ m := server.policy.StatementMap
+ name := s.Name
+ d, ok := m[name]
+ switch arg.Operation {
+ case api.Operation_ADD:
+ if ok {
+ err = d.Add(s)
+ } else {
+ m[name] = s
+ }
+ case api.Operation_DEL:
+ err = d.Remove(s)
+ case api.Operation_DEL_ALL:
+ if server.policy.StatementInUse(d) {
+ return fmt.Errorf("can't delete. statement %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 8375faab..1d8cb161 100644
--- a/table/policy.go
+++ b/table/policy.go
@@ -96,6 +96,28 @@ var CommunityOptionValueMap = map[string]config.BgpSetCommunityOptionType{
CommunityOptionNameMap[config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE]: config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE,
}
+type ConditionType int
+
+const (
+ CONDITION_PREFIX ConditionType = iota
+ CONDITION_NEIGHBOR
+ CONDITION_AS_PATH
+ CONDITION_COMMUNITY
+ CONDITION_EXT_COMMUNITY
+ CONDITION_AS_PATH_LENGTH
+ CONDITION_RPKI
+)
+
+type ActionType int
+
+const (
+ ACTION_ROUTING ActionType = iota
+ ACTION_COMMUNITY
+ ACTION_EXT_COMMUNITY
+ ACTION_MED
+ ACTION_AS_PATH_PREPEND
+)
+
func NewMatchOption(c interface{}) (MatchOption, error) {
switch c.(type) {
case config.MatchSetOptionsType:
@@ -779,6 +801,7 @@ func NewDefinedSetFromApiStruct(a *api.DefinedSet) (DefinedSet, error) {
}
type Condition interface {
+ Type() ConditionType
Evaluate(*Path) bool
Set() DefinedSet
}
@@ -788,6 +811,10 @@ type PrefixCondition struct {
option MatchOption
}
+func (c *PrefixCondition) Type() ConditionType {
+ return CONDITION_PREFIX
+}
+
func (c *PrefixCondition) Set() DefinedSet {
return c.set
}
@@ -869,6 +896,10 @@ type NeighborCondition struct {
option MatchOption
}
+func (c *NeighborCondition) Type() ConditionType {
+ return CONDITION_NEIGHBOR
+}
+
func (c *NeighborCondition) Set() DefinedSet {
return c.set
}
@@ -954,6 +985,10 @@ type AsPathCondition struct {
option MatchOption
}
+func (c *AsPathCondition) Type() ConditionType {
+ return CONDITION_AS_PATH
+}
+
func (c *AsPathCondition) Set() DefinedSet {
return c.set
}
@@ -1031,6 +1066,10 @@ type CommunityCondition struct {
option MatchOption
}
+func (c *CommunityCondition) Type() ConditionType {
+ return CONDITION_COMMUNITY
+}
+
func (c *CommunityCondition) Set() DefinedSet {
return c.set
}
@@ -1111,6 +1150,10 @@ type ExtCommunityCondition struct {
option MatchOption
}
+func (c *ExtCommunityCondition) Type() ConditionType {
+ return CONDITION_EXT_COMMUNITY
+}
+
func (c *ExtCommunityCondition) Set() DefinedSet {
return c.set
}
@@ -1197,6 +1240,10 @@ type AsPathLengthCondition struct {
operator AttributeComparison
}
+func (c *AsPathLengthCondition) Type() ConditionType {
+ return CONDITION_AS_PATH_LENGTH
+}
+
// compare AS_PATH length in the message's AS_PATH attribute with
// the one in condition.
func (c *AsPathLengthCondition) Evaluate(path *Path) bool {
@@ -1265,6 +1312,10 @@ type RpkiValidationCondition struct {
result config.RpkiValidationResultType
}
+func (c *RpkiValidationCondition) Type() ConditionType {
+ return CONDITION_RPKI
+}
+
func (c *RpkiValidationCondition) Evaluate(path *Path) bool {
return c.result == path.Validation
}
@@ -1288,6 +1339,7 @@ func NewRpkiValidationCondition(c config.RpkiValidationResultType) (*RpkiValidat
}
type Action interface {
+ Type() ActionType
Apply(*Path) *Path
}
@@ -1295,6 +1347,10 @@ type RoutingAction struct {
AcceptRoute bool
}
+func (a *RoutingAction) Type() ActionType {
+ return ACTION_ROUTING
+}
+
func (a *RoutingAction) Apply(path *Path) *Path {
if a.AcceptRoute {
return path
@@ -1384,6 +1440,10 @@ func RegexpRemoveExtCommunities(path *Path, exps []*regexp.Regexp, subtypes []bg
path.SetExtCommunities(newComms, true)
}
+func (a *CommunityAction) Type() ActionType {
+ return ACTION_COMMUNITY
+}
+
func (a *CommunityAction) Apply(path *Path) *Path {
switch a.action {
case config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD:
@@ -1492,6 +1552,10 @@ type ExtCommunityAction struct {
subtypeList []bgp.ExtendedCommunityAttrSubType
}
+func (a *ExtCommunityAction) Type() ActionType {
+ return ACTION_EXT_COMMUNITY
+}
+
func (a *ExtCommunityAction) Apply(path *Path) *Path {
switch a.action {
case config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD:
@@ -1611,6 +1675,10 @@ type MedAction struct {
action MedActionType
}
+func (a *MedAction) Type() ActionType {
+ return ACTION_MED
+}
+
func (a *MedAction) Apply(path *Path) *Path {
var err error
switch a.action {
@@ -1678,6 +1746,10 @@ type AsPathPrependAction struct {
repeat uint8
}
+func (a *AsPathPrependAction) Type() ActionType {
+ return ACTION_AS_PATH_PREPEND
+}
+
func (a *AsPathPrependAction) Apply(path *Path) *Path {
var asn uint32
if a.useLeftMost {
@@ -1779,6 +1851,14 @@ func (s *Statement) Apply(path *Path) (RouteType, *Path) {
}).Debug("statement evaluate : ", result)
if result {
//Routing action
+ if s.RouteAction == nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Path": path,
+ "PolicyName": s.Name,
+ }).Warn("route action is nil")
+ return ROUTE_TYPE_REJECT, path
+ }
p := s.RouteAction.Apply(path)
if p == nil {
return ROUTE_TYPE_REJECT, path
@@ -1837,7 +1917,120 @@ func (s *Statement) ToApiStruct() *api.Statement {
}
}
-func NewStatementFromApiStruct(a api.Statement, dmap DefinedSetMap) (*Statement, error) {
+type opType int
+
+const (
+ ADD opType = iota
+ REMOVE
+ REPLACE
+)
+
+func (lhs *Statement) mod(op opType, rhs *Statement) error {
+ cs := make([]Condition, len(lhs.Conditions))
+ copy(cs, lhs.Conditions)
+ ra := lhs.RouteAction
+ as := make([]Action, len(lhs.ModActions))
+ copy(as, lhs.ModActions)
+ for _, x := range rhs.Conditions {
+ var c Condition
+ i := 0
+ for idx, y := range lhs.Conditions {
+ if x.Type() == y.Type() {
+ c = y
+ i = idx
+ break
+ }
+ }
+ switch op {
+ case ADD:
+ if c != nil {
+ return fmt.Errorf("condition %d is already set", c.Type())
+ }
+ if cs == nil {
+ cs = make([]Condition, len(rhs.Conditions))
+ }
+ cs = append(cs, x)
+ case REMOVE:
+ if c == nil {
+ return fmt.Errorf("condition %d is not set", c.Type())
+ }
+ cs = append(cs[:i], cs[i+1:]...)
+ case REPLACE:
+ if c == nil {
+ return fmt.Errorf("condition %d is not set", c.Type())
+ }
+ cs[i] = x
+ }
+ }
+ if rhs.RouteAction != nil {
+ switch op {
+ case ADD:
+ if lhs.RouteAction != nil {
+ return fmt.Errorf("route action is already set")
+ }
+ ra = rhs.RouteAction
+ case REMOVE:
+ if lhs.RouteAction == nil {
+ return fmt.Errorf("route action is not set")
+ }
+ ra = nil
+ case REPLACE:
+ if lhs.RouteAction == nil {
+ return fmt.Errorf("route action is not set")
+ }
+ ra = rhs.RouteAction
+ }
+ }
+ for _, x := range rhs.ModActions {
+ var a Action
+ i := 0
+ for idx, y := range lhs.ModActions {
+ if x.Type() == y.Type() {
+ a = y
+ i = idx
+ break
+ }
+ }
+ switch op {
+ case ADD:
+ if a != nil {
+ return fmt.Errorf("action %d is already set", a.Type())
+ }
+ if as == nil {
+ as = make([]Action, len(rhs.ModActions))
+ }
+ as = append(as, a)
+ case REMOVE:
+ if a == nil {
+ return fmt.Errorf("action %d is not set", a.Type())
+ }
+ as = append(as[:i], as[i+1:]...)
+ case REPLACE:
+ if a == nil {
+ return fmt.Errorf("action %d is not set", a.Type())
+ }
+ as[i] = x
+ }
+ }
+ lhs.Conditions = cs
+ lhs.RouteAction = ra
+ lhs.ModActions = as
+ return nil
+}
+
+func (lhs *Statement) Add(rhs *Statement) error {
+ return lhs.mod(ADD, rhs)
+}
+
+func (lhs *Statement) Remove(rhs *Statement) error {
+ return lhs.mod(REMOVE, rhs)
+}
+
+func (lhs *Statement) Replace(rhs *Statement) error {
+ return lhs.mod(REPLACE, rhs)
+}
+
+func NewStatementFromApiStruct(a *api.Statement, dmap DefinedSetMap) (*Statement, error) {
if a.Name == "" {
return nil, fmt.Errorf("empty statement name")
}
@@ -2070,6 +2263,17 @@ func (r *RoutingPolicy) InUse(d DefinedSet) bool {
return false
}
+func (r *RoutingPolicy) StatementInUse(x *Statement) bool {
+ for _, p := range r.PolicyMap {
+ for _, y := range p.Statements {
+ if x.Name == y.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)