diff options
-rw-r--r-- | api/gobgp.pb.go | 74 | ||||
-rw-r--r-- | api/gobgp.proto | 10 | ||||
-rw-r--r-- | gobgp/main.go | 356 | ||||
-rw-r--r-- | policy/policy.go | 151 | ||||
-rw-r--r-- | server/grpc_server.go | 40 | ||||
-rw-r--r-- | server/peer.go | 12 | ||||
-rw-r--r-- | server/server.go | 74 |
7 files changed, 628 insertions, 89 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index fda0a608..76443c48 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -989,7 +989,7 @@ type Conditions struct { MatchPrefixSet *PrefixSet `protobuf:"bytes,1,opt,name=match_prefix_set" json:"match_prefix_set,omitempty"` MatchNeighborSet *NeighborSet `protobuf:"bytes,2,opt,name=match_neighbor_set" json:"match_neighbor_set,omitempty"` MatchAsPathLength *AsPathLength `protobuf:"bytes,3,opt,name=match_as_path_length" json:"match_as_path_length,omitempty"` - MatchSetOptions int64 `protobuf:"varint,4,opt,name=match_set_options" json:"match_set_options,omitempty"` + MatchSetOptions string `protobuf:"bytes,4,opt,name=match_set_options" json:"match_set_options,omitempty"` } func (m *Conditions) Reset() { *m = Conditions{} } @@ -1018,8 +1018,7 @@ func (m *Conditions) GetMatchAsPathLength() *AsPathLength { } type Actions struct { - AcceptRoute bool `protobuf:"varint,1,opt,name=accept_route" json:"accept_route,omitempty"` - RejectRoute bool `protobuf:"varint,2,opt,name=reject_route" json:"reject_route,omitempty"` + RouteAction string `protobuf:"bytes,1,opt,name=route_action" json:"route_action,omitempty"` } func (m *Actions) Reset() { *m = Actions{} } @@ -1083,9 +1082,9 @@ func (m *RoutingPolicy) GetPolicyDifinition() []*PolicyDefinition { type ApplyPolicy struct { ImportPolicies []*PolicyDefinition `protobuf:"bytes,1,rep,name=import_policies" json:"import_policies,omitempty"` - DefaultImportPolicy int64 `protobuf:"varint,2,opt,name=default_import_policy" json:"default_import_policy,omitempty"` + DefaultImportPolicy string `protobuf:"bytes,2,opt,name=default_import_policy" json:"default_import_policy,omitempty"` ExportPolicies []*PolicyDefinition `protobuf:"bytes,3,rep,name=export_policies" json:"export_policies,omitempty"` - DefaultExportPolicy int64 `protobuf:"varint,4,opt,name=default_export_policy" json:"default_export_policy,omitempty"` + DefaultExportPolicy string `protobuf:"bytes,4,opt,name=default_export_policy" json:"default_export_policy,omitempty"` } func (m *ApplyPolicy) Reset() { *m = ApplyPolicy{} } @@ -1146,6 +1145,7 @@ type GrpcClient interface { ModPolicyNeighbor(ctx context.Context, opts ...grpc.CallOption) (Grpc_ModPolicyNeighborClient, error) GetPolicyRoutePolicies(ctx context.Context, in *PolicyArguments, opts ...grpc.CallOption) (Grpc_GetPolicyRoutePoliciesClient, error) GetPolicyRoutePolicy(ctx context.Context, in *PolicyArguments, opts ...grpc.CallOption) (*PolicyDefinition, error) + ModPolicyRoutePolicy(ctx context.Context, opts ...grpc.CallOption) (Grpc_ModPolicyRoutePolicyClient, error) } type grpcClient struct { @@ -1549,6 +1549,37 @@ func (c *grpcClient) GetPolicyRoutePolicy(ctx context.Context, in *PolicyArgumen return out, nil } +func (c *grpcClient) ModPolicyRoutePolicy(ctx context.Context, opts ...grpc.CallOption) (Grpc_ModPolicyRoutePolicyClient, error) { + stream, err := grpc.NewClientStream(ctx, &_Grpc_serviceDesc.Streams[9], c.cc, "/api.Grpc/ModPolicyRoutePolicy", opts...) + if err != nil { + return nil, err + } + x := &grpcModPolicyRoutePolicyClient{stream} + return x, nil +} + +type Grpc_ModPolicyRoutePolicyClient interface { + Send(*PolicyArguments) error + Recv() (*Error, error) + grpc.ClientStream +} + +type grpcModPolicyRoutePolicyClient struct { + grpc.ClientStream +} + +func (x *grpcModPolicyRoutePolicyClient) Send(m *PolicyArguments) error { + return x.ClientStream.SendMsg(m) +} + +func (x *grpcModPolicyRoutePolicyClient) 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 { @@ -1573,6 +1604,7 @@ type GrpcServer interface { ModPolicyNeighbor(Grpc_ModPolicyNeighborServer) error GetPolicyRoutePolicies(*PolicyArguments, Grpc_GetPolicyRoutePoliciesServer) error GetPolicyRoutePolicy(context.Context, *PolicyArguments) (*PolicyDefinition, error) + ModPolicyRoutePolicy(Grpc_ModPolicyRoutePolicyServer) error } func RegisterGrpcServer(s *grpc.Server, srv GrpcServer) { @@ -1927,6 +1959,32 @@ func _Grpc_GetPolicyRoutePolicy_Handler(srv interface{}, ctx context.Context, co return out, nil } +func _Grpc_ModPolicyRoutePolicy_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(GrpcServer).ModPolicyRoutePolicy(&grpcModPolicyRoutePolicyServer{stream}) +} + +type Grpc_ModPolicyRoutePolicyServer interface { + Send(*Error) error + Recv() (*PolicyArguments, error) + grpc.ServerStream +} + +type grpcModPolicyRoutePolicyServer struct { + grpc.ServerStream +} + +func (x *grpcModPolicyRoutePolicyServer) Send(m *Error) error { + return x.ServerStream.SendMsg(m) +} + +func (x *grpcModPolicyRoutePolicyServer) 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), @@ -2029,5 +2087,11 @@ var _Grpc_serviceDesc = grpc.ServiceDesc{ Handler: _Grpc_GetPolicyRoutePolicies_Handler, ServerStreams: true, }, + { + StreamName: "ModPolicyRoutePolicy", + Handler: _Grpc_ModPolicyRoutePolicy_Handler, + ServerStreams: true, + ClientStreams: true, + }, }, } diff --git a/api/gobgp.proto b/api/gobgp.proto index 7c6bce1b..dd6fc46d 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -41,6 +41,7 @@ service Grpc { rpc ModPolicyNeighbor(stream PolicyArguments) returns (stream Error) {} rpc GetPolicyRoutePolicies(PolicyArguments) returns (stream PolicyDefinition) {} rpc GetPolicyRoutePolicy(PolicyArguments) returns (PolicyDefinition) {} + rpc ModPolicyRoutePolicy(stream PolicyArguments) returns (stream Error) {} } message Error { @@ -376,12 +377,11 @@ message Conditions { PrefixSet match_prefix_set = 1; NeighborSet match_neighbor_set = 2; AsPathLength match_as_path_length = 3; - int64 match_set_options = 4; + string match_set_options = 4; } message Actions { - bool accept_route = 1; - bool reject_route = 2; + string route_action = 1; } message Statement { @@ -401,7 +401,7 @@ message RoutingPolicy { message ApplyPolicy { repeated PolicyDefinition import_policies = 1; - int64 default_import_policy = 2; + string default_import_policy = 2; repeated PolicyDefinition export_policies = 3; - int64 default_export_policy = 4; + string default_export_policy = 4; } diff --git a/gobgp/main.go b/gobgp/main.go index cda9aa1c..9b50e53f 100644 --- a/gobgp/main.go +++ b/gobgp/main.go @@ -21,8 +21,6 @@ import ( "fmt" "github.com/jessevdk/go-flags" "github.com/osrg/gobgp/api" - "github.com/osrg/gobgp/config" - "github.com/osrg/gobgp/policy" "golang.org/x/net/context" "google.golang.org/grpc" "io" @@ -54,6 +52,8 @@ const ( CMD_DISABLE = "disable" CMD_PREFIX = "prefix" CMD_ROUTEPOLICY = "routepolicy" + CMD_CONDITIONS = "conditions" + CMD_ACTIONS = "actions" ) func formatTimedelta(d int64) string { @@ -200,7 +200,7 @@ func connGrpc() *grpc.ClientConn { return conn } -func requestGrpc(cmd string, eArgs []string, remoteIP net.IP) error { +func requestGrpc(cmd string, eArgs []string, request interface{}) error { conn := connGrpc() defer conn.Close() client = api.NewGrpcClient(conn) @@ -219,27 +219,27 @@ func requestGrpc(cmd string, eArgs []string, remoteIP net.IP) error { return showNeighbor(eArgs) } case CMD_NEIGHBOR + "_" + CMD_LOCAL: - return showNeighborRib(api.Resource_LOCAL, remoteIP) + return showNeighborRib(api.Resource_LOCAL, request.(*NeighborRibCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_ADJ_IN: - return showNeighborRib(api.Resource_ADJ_IN, remoteIP) + return showNeighborRib(api.Resource_ADJ_IN, request.(*NeighborRibCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_ADJ_OUT: - return showNeighborRib(api.Resource_ADJ_OUT, remoteIP) + return showNeighborRib(api.Resource_ADJ_OUT, request.(*NeighborRibCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_RESET: - return resetNeighbor(CMD_RESET, remoteIP) + return resetNeighbor(CMD_RESET, request.(*NeighborResetCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_SOFT_RESET: - return resetNeighbor(CMD_SOFT_RESET, remoteIP) + return resetNeighbor(CMD_SOFT_RESET, request.(*NeighborResetCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_SOFT_RESET_IN: - return resetNeighbor(CMD_SOFT_RESET_IN, remoteIP) + return resetNeighbor(CMD_SOFT_RESET_IN, request.(*NeighborResetCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_SOFT_RESET_OUT: - return resetNeighbor(CMD_SOFT_RESET_OUT, remoteIP) + return resetNeighbor(CMD_SOFT_RESET_OUT, request.(*NeighborResetCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_SHUTDOWN: - return stateChangeNeighbor(CMD_SHUTDOWN, remoteIP) + return stateChangeNeighbor(CMD_SHUTDOWN, request.(*NeighborChangeStateCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_ENABLE: - return stateChangeNeighbor(CMD_ENABLE, remoteIP) + return stateChangeNeighbor(CMD_ENABLE, request.(*NeighborChangeStateCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_DISABLE: - return stateChangeNeighbor(CMD_DISABLE, remoteIP) + return stateChangeNeighbor(CMD_DISABLE, request.(*NeighborChangeStateCommand).remoteIP) case CMD_NEIGHBOR + "_" + CMD_POLICY: - return showNeighborPolicy(remoteIP) + return showNeighborPolicy(request.(*NeighborPolicyCommand).remoteIP) case CMD_POLICY + "_" + CMD_PREFIX: if len(eArgs) == 0 { return showPolicyPrefixes() @@ -266,6 +266,16 @@ func requestGrpc(cmd string, eArgs []string, remoteIP net.IP) error { } else { return showPolicyRoutePolicy(eArgs) } + case CMD_POLICY + "_" + CMD_ROUTEPOLICY + "_" + CMD_ADD + "_" + CMD_CONDITIONS: + return modPolicyRoutePolicy(CMD_ADD, CMD_CONDITIONS, eArgs, + request.(*PolicyRoutePolicyAddConditionsCommand).policyName, + request.(*PolicyRoutePolicyAddConditionsCommand).statementName) + case CMD_POLICY + "_" + CMD_ROUTEPOLICY + "_" + CMD_ADD + "_" + CMD_ACTIONS: + return modPolicyRoutePolicy(CMD_ADD, CMD_ACTIONS, eArgs, + request.(*PolicyRoutePolicyAddActionsCommand).policyName, + request.(*PolicyRoutePolicyAddActionsCommand).statementName) + case CMD_POLICY + "_" + CMD_ROUTEPOLICY + "_" + CMD_DEL: + return modPolicyRoutePolicy(CMD_DEL, "", eArgs, "", "") } return nil } @@ -509,9 +519,9 @@ func modPath(modtype string, eArgs []string) error { } } switch modtype { - case "add": + case CMD_ADD: path.IsWithdraw = false - case "del": + case CMD_DEL: path.IsWithdraw = true } @@ -1045,7 +1055,7 @@ func (x *NeighborRibCommand) Execute(args []string) error { if len(eArgs) != 0 && (eArgs[0] == "-h" || eArgs[0] == "--help") { return nil } - if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x.remoteIP); err != nil { + if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x); err != nil { return err } return nil @@ -1093,7 +1103,7 @@ func (x *NeighborResetCommand) Execute(args []string) error { if len(eArgs) != 0 && (eArgs[0] == "-h" || eArgs[0] == "--help") { return nil } - if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x.remoteIP); err != nil { + if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x); err != nil { return err } return nil @@ -1128,7 +1138,7 @@ func stateChangeNeighbor(cmd string, remoteIP net.IP) error { func (x *NeighborChangeStateCommand) Execute(args []string) error { eArgs := extractArgs(x.command) - if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x.remoteIP); err != nil { + if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x); err != nil { return err } return nil @@ -1164,22 +1174,9 @@ func showNeighborPolicy(remoteIP net.IP) error { fmt.Println(string(j)) return nil } - var defaultInPolicy, defaultOutPolicy string - switch ap.DefaultImportPolicy { - case int64(policy.ROUTE_TYPE_ACCEPT): - defaultInPolicy = "ACCEPT" - case int64(policy.ROUTE_TYPE_REJECT): - defaultInPolicy = "REJECT" - } - switch ap.DefaultExportPolicy { - case int64(policy.ROUTE_TYPE_ACCEPT): - defaultOutPolicy = "ACCEPT" - case int64(policy.ROUTE_TYPE_REJECT): - defaultOutPolicy = "REJECT" - } - fmt.Printf("DefaultImportPolicy: %s\n", defaultInPolicy) - fmt.Printf("DefaultImportPolicy: %s\n", defaultOutPolicy) + fmt.Printf("DefaultImportPolicy: %s\n", ap.DefaultImportPolicy) + fmt.Printf("DefaultImportPolicy: %s\n", ap.DefaultExportPolicy) fmt.Printf("ImportPolicies:\n") for _, inPolicy := range ap.ImportPolicies { @@ -1201,7 +1198,7 @@ func (x *NeighborPolicyCommand) Execute(args []string) error { if _, err := parser.ParseArgs(eArgs); err != nil { os.Exit(1) } - if err := requestGrpc(CMD_NEIGHBOR+"_"+CMD_POLICY, eArgs, x.remoteIP); err != nil { + if err := requestGrpc(CMD_NEIGHBOR+"_"+CMD_POLICY, eArgs, x); err != nil { return err } } else { @@ -1337,7 +1334,7 @@ func (x *PolicyPrefixCommand) Execute(args []string) error { return err } return nil - } else if len(eArgs) == 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "add" || eArgs[0] == "del") { + } else if len(eArgs) == 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == CMD_ADD || eArgs[0] == CMD_DEL) { if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX, eArgs, nil); err != nil { return err } @@ -1356,7 +1353,7 @@ 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]) + return nil, fmt.Errorf("invalid prefix: %s\nplease enter ipv4 or ipv6 format", eArgs[1]) } mask, _ := ipNet.Mask.Size() prefix := &api.Prefix{ @@ -1368,31 +1365,31 @@ func parsePrefixSet(eArgs []string) (*api.PrefixSet, error) { maskRange := eArgs[2] idx := strings.Index(maskRange, "..") if idx == -1 { - return nil, fmt.Errorf("mask length range invalid format %s", maskRange) + return nil, fmt.Errorf("invalid mask length range: %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) + return nil, fmt.Errorf("invalid mask length range: %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) + return nil, fmt.Errorf("invalid mask length range: %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) + 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) + 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) + return nil, fmt.Errorf("invalid mask length range: %s\nTo a large value to the right from the left", maskRange) } prefix.MaskLengthRange = maskRange } @@ -1616,7 +1613,7 @@ func (x *PolicyNeighborCommand) Execute(args []string) error { return err } return nil - } else if len(eArgs) == 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "add" || eArgs[0] == "del") { + } else if len(eArgs) == 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == CMD_ADD || eArgs[0] == CMD_DEL) { if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR, eArgs, nil); err != nil { return err } @@ -1636,7 +1633,7 @@ func parseNeighborSet(eArgs []string) (*api.NeighborSet, error) { address := net.ParseIP(eArgs[1]) if address.To4() == nil { if address.To16() == nil { - return nil, fmt.Errorf("address is invalid format %s\nplease enter ipv4 or ipv6 format", eArgs[1]) + return nil, fmt.Errorf("invalid address: %s\nplease enter ipv4 or ipv6 format", eArgs[1]) } } @@ -1798,22 +1795,9 @@ func showPolicyStatement(head string, pd *api.PolicyDefinition) { } asPathLentgh := st.Conditions.MatchAsPathLength fmt.Printf("%s AsPathLength: %s %s\n", head, asPathLentgh.Value, asPathLentgh.Operator) - var option string - switch st.Conditions.MatchSetOptions { - case config.MATCH_SET_OPTIONS_TYPE_ANY: - option = "ANY" - case config.MATCH_SET_OPTIONS_TYPE_ALL: - option = "ALL" - case config.MATCH_SET_OPTIONS_TYPE_INVERT: - option = "INVERT" - } - fmt.Printf("%s MatchOption: %s\n", head, option) + fmt.Printf("%s MatchOption: %s\n", head, st.Conditions.MatchSetOptions) fmt.Printf("%s Actions:\n", head) - action := "REJECT" - if st.Actions.AcceptRoute { - action = "ACCEPT" - } - fmt.Printf("%s %s\n", head, action) + fmt.Printf("%s %s\n", head, st.Actions.RouteAction) } } @@ -1886,7 +1870,7 @@ func (x *PolicyRoutePolicyCommand) Execute(args []string) error { return err } return nil - } else if len(eArgs) == 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "add" || eArgs[0] == "del") { + } else if len(eArgs) == 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == CMD_ADD || eArgs[0] == CMD_DEL) { if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY, eArgs, nil); err != nil { return err } @@ -1894,6 +1878,243 @@ func (x *PolicyRoutePolicyCommand) Execute(args []string) error { } parser := flags.NewParser(nil, flags.Default) parser.Usage = "policy routepolicy [OPTIONS]\n gobgp policy routepolicy" + parser.AddCommand(CMD_ADD, "subcommand for add routing policy", "", &PolicyRoutePolicyAddCommand{}) + parser.AddCommand(CMD_DEL, "subcommand for delete routing policy", "", &PolicyRoutePolicyDelCommand{}) + parser.ParseArgs(eArgs) + return nil +} + +type PolicyRoutePolicyAddCommand struct{} + +func parseConditions() (*api.Conditions, error) { + conditions := &api.Conditions{} + if conditionOpts.Prefix != "" { + conditions.MatchPrefixSet = &api.PrefixSet{ + PrefixSetName: conditionOpts.Prefix, + } + } + if conditionOpts.Neighbor != "" { + conditions.MatchNeighborSet = &api.NeighborSet{ + NeighborSetName: conditionOpts.Neighbor, + } + } + if conditionOpts.AsPathLength != "" { + asPathLen := conditionOpts.AsPathLength + idx := strings.Index(asPathLen, ",") + if idx == -1 { + return nil, fmt.Errorf("invalid as path length: %s\nPlease enter the <value>,<operator>", asPathLen) + } + value := asPathLen[:idx] + if _, err := strconv.ParseUint(value, 10, 32); err != nil { + return nil, fmt.Errorf("invalid as path length: %s\nPlease enter a numeric", value) + } + operator := asPathLen[idx+1:] + conditions.MatchAsPathLength = &api.AsPathLength{ + Value: value, + Operator: operator, + } + } + if conditionOpts.Option != "" { + optionUpper := strings.ToUpper(conditionOpts.Option) + var option string + switch optionUpper { + case "ANY", "ALL", "INVERT": + option = optionUpper + default: + return nil, fmt.Errorf("invalid condition option: %s\nPlease enter the any or all or invert", + conditionOpts.Option) + } + conditions.MatchSetOptions = option + } + return conditions, nil +} + +func parseActions() (*api.Actions, error) { + actions := &api.Actions{} + if actionOpts.RouteType != "" { + routeTypeUpper := strings.ToUpper(actionOpts.RouteType) + var routeType string + switch routeTypeUpper { + case "ACCEPT", "REJECT": + routeType = routeTypeUpper + default: + return nil, fmt.Errorf("invalid route type: %s\nPlease enter the accept or reject", + actionOpts.RouteType) + } + actions.RouteAction = routeType + } + return actions, nil +} + +func modPolicyRoutePolicy(modtype string, stmtType string, eArgs []string, pName string, sName string) error { + var e error + var operation api.Operation + pd := &api.PolicyDefinition{} + switch modtype { + case CMD_ADD: + stmt := &api.Statement{ + StatementNeme: sName, + } + switch stmtType { + case CMD_CONDITIONS: + conditions, err := parseConditions() + if err != nil { + return err + } + stmt.Conditions = conditions + case CMD_ACTIONS: + actions, err := parseActions() + if err != nil { + return err + } + stmt.Actions = actions + } + + pd.PolicyDefinitionName = pName + pd.StatementList = []*api.Statement{stmt} + operation = api.Operation_ADD + + case CMD_DEL: + if len(eArgs) == 0 { + operation = api.Operation_DEL_ALL + } else if len(eArgs) == 1 { + pd.PolicyDefinitionName = eArgs[0] + operation = api.Operation_DEL + } else if len(eArgs) == 2 { + stmt := &api.Statement{ + StatementNeme: eArgs[1], + } + pd.PolicyDefinitionName = eArgs[0] + pd.StatementList = []*api.Statement{stmt} + operation = api.Operation_DEL + } + } + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_ROUTEPOLICY, + Operation: operation, + PolicyDifinition: pd, + } + stream, err := client.ModPolicyNeighbor(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 *PolicyRoutePolicyAddCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ADD) + if len(eArgs) < 2 { + return fmt.Errorf("policy routepolicy add <routing policy name> <statement name>") + } + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "policy routepolicy add <routing policy name>" + parser.AddCommand(CMD_CONDITIONS, "subcommand for routing policy conditions", "", NewPolicyRoutePolicyAddConditionsCommand(eArgs[0], eArgs[1])) + parser.AddCommand(CMD_ACTIONS, "subcommand for routing policy actions", "", NewPolicyRoutePolicyAddActionsCommand(eArgs[0], eArgs[1])) + parser.ParseArgs(eArgs) + return nil +} + +type PolicyRoutePolicyAddConditionsCommand struct { + policyName string + statementName string +} + +func NewPolicyRoutePolicyAddConditionsCommand(pName string, sName string) *PolicyRoutePolicyAddConditionsCommand { + return &PolicyRoutePolicyAddConditionsCommand{ + policyName: pName, + statementName: sName, + } +} + +func (x *PolicyRoutePolicyAddConditionsCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_CONDITIONS) + parser := flags.NewParser(&conditionOpts, flags.Default) + parser.Usage = "policy routepolicy add <routing policy name> <statement name> conditions [OPTIONS]" + parser.ParseArgs(eArgs) + if len(eArgs) == 0 { + return fmt.Errorf("policy routepolicy add <routing policy name> <statement name> conditions [OPTIONS]") + } else if !(eArgs[0] == "-h" || eArgs[0] == "--help") { + if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY+"_"+CMD_ADD+"_"+CMD_CONDITIONS, eArgs, x); err != nil { + return err + } + } + + return nil +} + +type PolicyRoutePolicyAddActionsCommand struct { + policyName string + statementName string +} + +func NewPolicyRoutePolicyAddActionsCommand(pName string, sName string) *PolicyRoutePolicyAddActionsCommand { + return &PolicyRoutePolicyAddActionsCommand{ + policyName: pName, + statementName: sName, + } +} + +func (x *PolicyRoutePolicyAddActionsCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ACTIONS) + parser := flags.NewParser(&actionOpts, flags.Default) + parser.Usage = "policy routepolicy add <routing policy name> <statement name> actions [OPTIONS]" + parser.ParseArgs(eArgs) + if len(eArgs) == 0 { + return fmt.Errorf("policy routepolicy add <routing policy name> <statement name> actions [OPTIONS]") + } else if !(eArgs[0] == "-h" || eArgs[0] == "--help") { + if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY+"_"+CMD_ADD+"_"+CMD_ACTIONS, eArgs, x); err != nil { + return err + } + } + return nil +} + +type PolicyRoutePolicyDelCommand struct{} + +func (x *PolicyRoutePolicyDelCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_DEL) + if len(eArgs) > 2 { + return fmt.Errorf("policy routepolicy del <routing policy name> [<statement name>]") + } else if len(eArgs) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "all") { + if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY+"_"+CMD_DEL, eArgs, nil); err != nil { + return err + } + return nil + } + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "policy routepolicy del <routing policy name> [<statement name>]" + parser.AddCommand(CMD_ALL, "subcommand for delete all routing policy", "", &PolicyRoutePolicyDelAllCommand{}) + parser.ParseArgs(eArgs) + return nil +} + +type PolicyRoutePolicyDelAllCommand struct{} + +func (x *PolicyRoutePolicyDelAllCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ALL) + if len(eArgs) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help") { + return fmt.Errorf("Argument can not be entered") + } else if len(eArgs) == 0 { + if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY+"_"+CMD_DEL, eArgs, nil); err != nil { + return err + } + } + + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "policy routepolicy del all" parser.ParseArgs(eArgs) return nil } @@ -1914,10 +2135,21 @@ var neighborsOpts struct { Transport string `short:"t" long:"transport" description:"specifying a transport protocol"` } +var conditionOpts struct { + Prefix string `short:"p" long:"prefix" description:"specifying a prefix set name of policy"` + Neighbor string `short:"n" long:"neighbor" description:"specifying a neighbor set name of policy"` + AsPathLength string `short:"a" long:"aspath-len" description:"specifying an as path length of policy"` + Option string `short:"o" long:"option" description:"specifying an option of policy"` +} + +var actionOpts struct { + RouteType string `short:"r" long:"route-type" description:"specifying a route type of policy (accept | reject)"` +} + func main() { cmds = []string{CMD_GLOBAL, CMD_NEIGHBOR, CMD_POLICY, CMD_RIB, CMD_ADD, CMD_DEL, CMD_ALL, 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_ROUTEPOLICY} + CMD_DISABLE, CMD_PREFIX, CMD_ROUTEPOLICY, CMD_CONDITIONS, CMD_ACTIONS} eArgs := extractArgs("") parser := flags.NewParser(&globalOpts, flags.Default) diff --git a/policy/policy.go b/policy/policy.go index a13aeebc..cf93d640 100644 --- a/policy/policy.go +++ b/policy/policy.go @@ -929,25 +929,31 @@ func (p *Policy) ToApiStruct() *api.PolicyDefinition { } } } - resCondition := &api.Conditions{ + var op string + switch st.MatchSetOptions { + case config.MATCH_SET_OPTIONS_TYPE_ALL: + op = "ALL" + case config.MATCH_SET_OPTIONS_TYPE_ANY: + op = "ANY" + case config.MATCH_SET_OPTIONS_TYPE_INVERT: + op = "INVERT" + } + resConditions := &api.Conditions{ MatchPrefixSet: resPrefixSet, MatchNeighborSet: resNeighborSet, MatchAsPathLength: resAsPathLength, - MatchSetOptions: int64(st.MatchSetOptions), + MatchSetOptions: op, } - resAction := &api.Actions{ - AcceptRoute: false, - RejectRoute: true, + resActions := &api.Actions{ + RouteAction: "REJECT", } - - if st.routingAction.AcceptRoute { - resAction.AcceptRoute = true - resAction.RejectRoute = false + if st.Actions.(*RoutingActions).AcceptRoute { + resActions.RouteAction = "ACCEPT" } resStatement := &api.Statement{ StatementNeme: st.Name, - Conditions: resCondition, - Actions: resAction, + Conditions: resConditions, + Actions: resActions, } resStatements = append(resStatements, resStatement) } @@ -1005,6 +1011,29 @@ func IndexOfNeighborSet(conNeighborSetList []config.NeighborSet, reqNeighborSet return idxNeighborSet, idxNeighbor } +// find index PolicyDefinition of request from PolicyDefinition of configuration file. +// Return the idxPolicyDefinition of the location where the name of PolicyDefinition matches, +// and idxStatement of the location where Statement of PolicyDefinition matches +func IndexOfPolicyDefinition(conPolicyList []config.PolicyDefinition, reqPolicy config.PolicyDefinition) (int, int) { + idxPolicyDefinition := -1 + idxStatement := -1 + for i, conPolicy := range conPolicyList { + if conPolicy.Name == reqPolicy.Name { + idxPolicyDefinition = i + if reqPolicy.StatementList == nil { + return idxPolicyDefinition, idxStatement + } + for j, conStatement := range conPolicy.StatementList { + if conStatement.Name == reqPolicy.StatementList[0].Name { + idxStatement = j + return idxPolicyDefinition, idxStatement + } + } + } + } + return idxPolicyDefinition, idxStatement +} + func PrefixSetToApiStruct(ps config.PrefixSet) *api.PrefixSet { resPrefixList := make([]*api.Prefix, 0) for _, p := range ps.PrefixList { @@ -1087,6 +1116,17 @@ func NeighborSetToConfigStruct(reqNeighborSet *api.NeighborSet) (bool, config.Ne return isReqNeighborSet, neighborSet } +func AsPathLengthToConfigStruct(reqAsPathLength *api.AsPathLength) config.AsPathLength { + operator := reqAsPathLength.Operator + value := reqAsPathLength.Value + valueUint, _ := strconv.ParseUint(value, 10, 32) + asPathLength := config.AsPathLength{ + Operator: operator, + Value: uint32(valueUint), + } + return asPathLength +} + func AsPathLengthToApiStruct(asPathLength config.AsPathLength) *api.AsPathLength { value := "" if asPathLength.Operator != "" { @@ -1099,6 +1139,77 @@ func AsPathLengthToApiStruct(asPathLength config.AsPathLength) *api.AsPathLength return resAsPathLength } +func ConditionsToConfigStruct(reqConditions *api.Conditions) config.Conditions { + conditions := config.Conditions{} + if reqConditions.MatchPrefixSet != nil { + conditions.MatchPrefixSet = reqConditions.MatchPrefixSet.PrefixSetName + } + if reqConditions.MatchNeighborSet != nil { + conditions.MatchNeighborSet = reqConditions.MatchNeighborSet.NeighborSetName + } + if reqConditions.MatchAsPathLength != nil { + asPathLength := AsPathLengthToConfigStruct(reqConditions.MatchAsPathLength) + bgpConditions := config.BgpConditions{ + AsPathLength: asPathLength, + } + conditions.BgpConditions = bgpConditions + } + var setOption config.MatchSetOptionsType + switch reqConditions.MatchSetOptions { + case "ALL": + setOption = config.MATCH_SET_OPTIONS_TYPE_ALL + case "ANY": + setOption = config.MATCH_SET_OPTIONS_TYPE_ANY + case "INVERT": + setOption = config.MATCH_SET_OPTIONS_TYPE_INVERT + } + conditions.MatchSetOptions = setOption + return conditions +} + +func ActionsToConfigStruct(reqActions *api.Actions) config.Actions { + acceptRoute := false + rejectRoute := false + switch reqActions.RouteAction { + case "ACCEPT": + acceptRoute = true + case "REJECT": + rejectRoute = true + } + actions := config.Actions{ + AcceptRoute: acceptRoute, + RejectRoute: rejectRoute, + } + return actions +} + +func StatementToConfigStruct(reqStatement *api.Statement) config.Statement { + statement := config.Statement{ + Name: reqStatement.StatementNeme, + } + if reqStatement.Conditions != nil { + statement.Conditions = ConditionsToConfigStruct(reqStatement.Conditions) + } + if reqStatement.Actions != nil { + statement.Actions = ActionsToConfigStruct(reqStatement.Actions) + } + return statement +} + +func PolicyDefinitionToConfigStruct(reqPolicy *api.PolicyDefinition) (bool, config.PolicyDefinition) { + isReqStatement := true + policy := config.PolicyDefinition{ + Name: reqPolicy.PolicyDefinitionName, + } + if reqPolicy.StatementList != nil { + statement := StatementToConfigStruct(reqPolicy.StatementList[0]) + policy.StatementList = []config.Statement{statement} + } else { + isReqStatement = false + } + return isReqStatement, policy +} + func PolicyDefinitionToApiStruct(pd config.PolicyDefinition, df config.DefinedSets) *api.PolicyDefinition { conPrefixSetList := df.PrefixSetList conNeighborSetList := df.NeighborSetList @@ -1125,16 +1236,26 @@ func PolicyDefinitionToApiStruct(pd config.PolicyDefinition, df config.DefinedSe neighborSet = NeighborSetToApiStruct(conNeighborSetList[idxNeighborSet]) } asPathLength := AsPathLengthToApiStruct(st.Conditions.BgpConditions.AsPathLength) - + var op string + switch conditions.MatchSetOptions { + case config.MATCH_SET_OPTIONS_TYPE_ALL: + op = "ALL" + case config.MATCH_SET_OPTIONS_TYPE_ANY: + op = "ANY" + case config.MATCH_SET_OPTIONS_TYPE_INVERT: + op = "INVERT" + } resConditions := &api.Conditions{ MatchPrefixSet: prefixSet, MatchNeighborSet: neighborSet, MatchAsPathLength: asPathLength, - MatchSetOptions: int64(conditions.MatchSetOptions), + MatchSetOptions: op, } resActions := &api.Actions{ - AcceptRoute: actions.AcceptRoute, - RejectRoute: actions.RejectRoute, + RouteAction: "REJECT", + } + if actions.AcceptRoute { + resActions.RouteAction = "ACCEPT" } resStatement := &api.Statement{ StatementNeme: st.Name, diff --git a/server/grpc_server.go b/server/grpc_server.go index dbd1be1e..f1d040a2 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -56,6 +56,9 @@ const ( REQ_POLICY_NEIGHBORS_DELETE REQ_POLICY_ROUTEPOLICIES REQ_POLICY_ROUTEPOLICY + REQ_POLICY_ROUTEPOLICY_ADD + REQ_POLICY_ROUTEPOLICY_DELETE + REQ_POLICY_ROUTEPOLICIES_DELETE ) const GRPC_PORT = 8080 @@ -390,6 +393,28 @@ func (s *Server) modPolicy(arg *api.PolicyArguments, stream interface{}) error { err = stream.(api.Grpc_ModPolicyNeighborServer).Send(&api.Error{ Code: api.Error_SUCCESS, }) + case api.Resource_POLICY_ROUTEPOLICY: + switch arg.Operation { + case api.Operation_ADD: + reqType = REQ_POLICY_ROUTEPOLICY_ADD + case api.Operation_DEL: + reqType = REQ_POLICY_ROUTEPOLICY_DELETE + case api.Operation_DEL_ALL: + reqType = REQ_POLICY_ROUTEPOLICIES_DELETE + default: + return fmt.Errorf("unsupported operation: %s", arg.Operation) + } + req := NewGrpcRequest(reqType, "", rf, arg.PolicyDifinition) + s.bgpServerCh <- req + + res := <-req.ResponseCh + if err := res.Err(); err != nil { + log.Debug(err.Error()) + return err + } + err = stream.(api.Grpc_ModPolicyRoutePolicyServer).Send(&api.Error{ + Code: api.Error_SUCCESS, + }) default: return fmt.Errorf("unsupported resource type: %v", arg.Resource) } @@ -476,6 +501,21 @@ func (s *Server) GetPolicyRoutePolicy(ctx context.Context, arg *api.PolicyArgume return data.(*api.PolicyDefinition), nil } +func (s *Server) ModPolicyRoutePolicy(stream api.Grpc_ModPolicyRoutePolicyServer) 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 RemoteAddr string diff --git a/server/peer.go b/server/peer.go index f83bbc3e..02585e11 100644 --- a/server/peer.go +++ b/server/peer.go @@ -624,10 +624,18 @@ func (peer *Peer) handleGrpc(grpcReq *GrpcRequest) { resOutPolicies = append(resOutPolicies, &api.PolicyDefinition{PolicyDefinitionName: conOutPolicyName}) } } + defaultInPolicy := "REJECT" + defaultOutPolicy := "REJECT" + if peer.defaultImportPolicy == 0 { + defaultInPolicy = "ACCEPT" + } + if peer.defaultExportPolicy == 0 { + defaultOutPolicy = "ACCEPT" + } result.Data = &api.ApplyPolicy{ - DefaultImportPolicy: int64(peer.defaultImportPolicy), + DefaultImportPolicy: defaultInPolicy, ImportPolicies: resInPolicies, - DefaultExportPolicy: int64(peer.defaultExportPolicy), + DefaultExportPolicy: defaultOutPolicy, ExportPolicies: resOutPolicies, } grpcReq.ResponseCh <- result diff --git a/server/server.go b/server/server.go index adc2bc57..88ff5a99 100644 --- a/server/server.go +++ b/server/server.go @@ -581,5 +581,79 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) { grpcReq.ResponseCh <- result } close(grpcReq.ResponseCh) + case REQ_POLICY_ROUTEPOLICY_ADD: + reqPolicy := grpcReq.Data.(*api.PolicyDefinition) + conPolicyList := server.routingPolicy.PolicyDefinitionList + result := &GrpcResponse{} + _, policyDef := policy.PolicyDefinitionToConfigStruct(reqPolicy) + idxPolicy, idxStatement := policy.IndexOfPolicyDefinition(conPolicyList, policyDef) + if idxPolicy == -1 { + conPolicyList = append(conPolicyList, policyDef) + } else { + statement := policyDef.StatementList[0] + if idxStatement == -1 { + conPolicyList[idxPolicy].StatementList = + append(conPolicyList[idxPolicy].StatementList, statement) + } else { + if reqPolicy.StatementList[0].Conditions != nil { + conPolicyList[idxPolicy].StatementList[idxStatement].Conditions = + statement.Conditions + } + if reqPolicy.StatementList[0].Actions != nil { + conPolicyList[idxPolicy].StatementList[idxStatement].Actions = + statement.Actions + } + } + } + server.routingPolicy.PolicyDefinitionList = conPolicyList + server.handlePolicy(server.routingPolicy) + grpcReq.ResponseCh <- result + close(grpcReq.ResponseCh) + + case REQ_POLICY_ROUTEPOLICY_DELETE: + reqPolicy := grpcReq.Data.(*api.PolicyDefinition) + conPolicyList := server.routingPolicy.PolicyDefinitionList + result := &GrpcResponse{} + isStatement, policyDef := policy.PolicyDefinitionToConfigStruct(reqPolicy) + idxPolicy, idxStatement := policy.IndexOfPolicyDefinition(conPolicyList, policyDef) + if isStatement { + if idxPolicy == -1 { + result.ResponseErr = fmt.Errorf("Policy that has %v doesn't exist.", policyDef.Name) + } else { + if idxStatement == -1 { + result.ResponseErr = fmt.Errorf("Policy Statment that has %v doesn't exist.", policyDef.StatementList[0].Name) + } else { + copy(conPolicyList[idxPolicy].StatementList[idxStatement:], + conPolicyList[idxPolicy].StatementList[idxStatement+1:]) + conPolicyList[idxPolicy].StatementList = + conPolicyList[idxPolicy].StatementList[:len(conPolicyList[idxPolicy].StatementList)-1] + } + } + } else { + idxPolicy := -1 + for i, conPolicy := range conPolicyList { + if conPolicy.Name == reqPolicy.PolicyDefinitionName { + idxPolicy = i + break + } + } + if idxPolicy == -1 { + result.ResponseErr = fmt.Errorf("Policy that has %v doesn't exist.", policyDef.Name) + } else { + copy(conPolicyList[idxPolicy:], conPolicyList[idxPolicy+1:]) + conPolicyList = conPolicyList[:len(conPolicyList)-1] + } + } + server.routingPolicy.PolicyDefinitionList = conPolicyList + server.handlePolicy(server.routingPolicy) + grpcReq.ResponseCh <- result + close(grpcReq.ResponseCh) + + case REQ_POLICY_ROUTEPOLICIES_DELETE: + result := &GrpcResponse{} + server.routingPolicy.PolicyDefinitionList = make([]config.PolicyDefinition, 0) + server.handlePolicy(server.routingPolicy) + grpcReq.ResponseCh <- result + close(grpcReq.ResponseCh) } } |