summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2015-10-18 17:42:02 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2015-10-20 10:33:10 +0900
commitf834e421284080a8d4b9150d19148be3b886779e (patch)
tree516e86d87691baccf50f5d0799fe2db2138237de
parenta88e0b5592b5f344981983d91f4f55a6d3f002bf (diff)
cli: support statement configuration
- create statement $ gobgp policy statement add st01 - add community condition $ gobgp policy statement st01 condition add community c1 - add route action $ gobgp policy statement st01 action add accept - add set-community action $ gobgp policy statement st01 action add community 100:100 Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
-rw-r--r--api/gobgp.pb.go14
-rw-r--r--api/gobgp.proto7
-rw-r--r--gobgp/cmd/common.go9
-rw-r--r--gobgp/cmd/neighbor.go1
-rw-r--r--gobgp/cmd/policy.go371
-rw-r--r--table/policy.go75
6 files changed, 427 insertions, 50 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go
index e3d4e8b3..5dc0f6fc 100644
--- a/api/gobgp.pb.go
+++ b/api/gobgp.pb.go
@@ -24,7 +24,6 @@ It has these top-level messages:
Peer
Prefix
DefinedSet
- PrefixSet
MatchSet
AsPathLength
Conditions
@@ -452,15 +451,6 @@ func (m *DefinedSet) GetPrefixes() []*Prefix {
return nil
}
-type PrefixSet struct {
- Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
- Option int32 `protobuf:"varint,2,opt,name=option" json:"option,omitempty"`
-}
-
-func (m *PrefixSet) Reset() { *m = PrefixSet{} }
-func (m *PrefixSet) String() string { return proto.CompactTextString(m) }
-func (*PrefixSet) ProtoMessage() {}
-
type MatchSet struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
Option int32 `protobuf:"varint,2,opt,name=option" json:"option,omitempty"`
@@ -480,7 +470,7 @@ func (m *AsPathLength) String() string { return proto.CompactTextString(m) }
func (*AsPathLength) ProtoMessage() {}
type Conditions struct {
- PrefixSet *PrefixSet `protobuf:"bytes,1,opt,name=prefix_set" json:"prefix_set,omitempty"`
+ PrefixSet *MatchSet `protobuf:"bytes,1,opt,name=prefix_set" json:"prefix_set,omitempty"`
NeighborSet *MatchSet `protobuf:"bytes,2,opt,name=neighbor_set" json:"neighbor_set,omitempty"`
AsPathLength *AsPathLength `protobuf:"bytes,3,opt,name=as_path_length" json:"as_path_length,omitempty"`
AsPathSet *MatchSet `protobuf:"bytes,4,opt,name=as_path_set" json:"as_path_set,omitempty"`
@@ -493,7 +483,7 @@ func (m *Conditions) Reset() { *m = Conditions{} }
func (m *Conditions) String() string { return proto.CompactTextString(m) }
func (*Conditions) ProtoMessage() {}
-func (m *Conditions) GetPrefixSet() *PrefixSet {
+func (m *Conditions) GetPrefixSet() *MatchSet {
if m != nil {
return m.PrefixSet
}
diff --git a/api/gobgp.proto b/api/gobgp.proto
index 84eb8c74..212f4073 100644
--- a/api/gobgp.proto
+++ b/api/gobgp.proto
@@ -201,11 +201,6 @@ message DefinedSet {
repeated Prefix prefixes = 4;
}
-message PrefixSet {
- string name = 1;
- int32 option = 2;
-}
-
message MatchSet {
string name = 1;
int32 option = 2;
@@ -217,7 +212,7 @@ message AsPathLength {
}
message Conditions {
- PrefixSet prefix_set = 1;
+ MatchSet prefix_set = 1;
MatchSet neighbor_set = 2;
AsPathLength as_path_length = 3;
MatchSet as_path_set = 4;
diff --git a/gobgp/cmd/common.go b/gobgp/cmd/common.go
index 54bf07ea..d3f9a8cd 100644
--- a/gobgp/cmd/common.go
+++ b/gobgp/cmd/common.go
@@ -47,12 +47,9 @@ const (
CMD_ENABLE = "enable"
CMD_DISABLE = "disable"
CMD_PREFIX = "prefix"
- CMD_ASPATH = "aspath"
+ CMD_ASPATH = "as-path"
CMD_COMMUNITY = "community"
- CMD_EXTCOMMUNITY = "extcommunity"
- CMD_ROUTEPOLICY = "routepolicy"
- CMD_CONDITIONS = "conditions"
- CMD_ACTIONS = "actions"
+ CMD_EXTCOMMUNITY = "ext-community"
CMD_IMPORT = "import"
CMD_EXPORT = "export"
CMD_IN = "in"
@@ -67,6 +64,8 @@ const (
CMD_ACCEPTED = "accepted"
CMD_REJECTED = "rejected"
CMD_STATEMENT = "statement"
+ CMD_CONDITION = "condition"
+ CMD_ACTION = "action"
)
var subOpts struct {
diff --git a/gobgp/cmd/neighbor.go b/gobgp/cmd/neighbor.go
index 12dbabf0..7627e943 100644
--- a/gobgp/cmd/neighbor.go
+++ b/gobgp/cmd/neighbor.go
@@ -789,6 +789,7 @@ func NewNeighborCmd() *cobra.Command {
Use: w,
Run: func(subcmd *cobra.Command, args []string) {
remoteIP := net.ParseIP(args[len(args)-1])
+ args = args[:len(args)-1]
if remoteIP == nil {
fmt.Println("invalid ip address:", args[len(args)-1])
os.Exit(1)
diff --git a/gobgp/cmd/policy.go b/gobgp/cmd/policy.go
index 441c1ff9..239676e8 100644
--- a/gobgp/cmd/policy.go
+++ b/gobgp/cmd/policy.go
@@ -26,6 +26,7 @@ import (
"golang.org/x/net/context"
"io"
"net"
+ "os"
"regexp"
"sort"
"strconv"
@@ -130,7 +131,7 @@ func formatDefinedSet(head bool, typ string, indent int, list []*api.DefinedSet)
return buff.String()
}
-func show(v string, args []string) error {
+func showDefinedSet(v string, args []string) error {
var typ table.DefinedType
switch v {
case CMD_PREFIX:
@@ -370,7 +371,7 @@ var modPolicyUsageFormat = map[string]string{
CMD_EXTCOMMUNITY: "usage: policy extcommunity %s <name> [<regexp>...]",
}
-func mod(settype string, modtype string, args []string) error {
+func modDefinedSet(settype string, modtype string, args []string) error {
var d *api.DefinedSet
var err error
if len(args) < 1 {
@@ -573,7 +574,7 @@ func parseConditions() (*api.Conditions, error) {
if err != nil {
return nil, fmt.Errorf("invalid prefix option format\n%s", err)
}
- conditions.PrefixSet = &api.PrefixSet{
+ conditions.PrefixSet = &api.MatchSet{
Name: name,
Option: op,
}
@@ -781,7 +782,7 @@ func modPolicy(resource api.Resource, op api.Operation, data interface{}) error
co := &api.Conditions{}
switch resource {
case api.Resource_POLICY_PREFIX:
- co.PrefixSet = data.(*api.PrefixSet)
+ co.PrefixSet = data.(*api.MatchSet)
case api.Resource_POLICY_NEIGHBOR:
co.NeighborSet = data.(*api.MatchSet)
case api.Resource_POLICY_ASPATH:
@@ -908,6 +909,306 @@ func showStatement(args []string) error {
return nil
}
+func modStatement(op string, args []string) error {
+ if len(args) < 1 {
+ return fmt.Errorf("usage: gobgp policy statement %s <name>", op)
+ }
+ name := args[0]
+ var o api.Operation
+ switch op {
+ case CMD_ADD:
+ o = api.Operation_ADD
+ case CMD_DEL:
+ o = api.Operation_DEL
+ default:
+ return fmt.Errorf("invalid operation: %s", op)
+ }
+ stmt := &api.Statement{
+ Name: name,
+ }
+ arg := &api.ModStatementArguments{
+ Operation: o,
+ Statement: stmt,
+ }
+ _, err := client.ModStatement(context.Background(), arg)
+ return err
+}
+
+func modCondition(name, op string, args []string) error {
+ var o api.Operation
+ switch op {
+ case CMD_ADD:
+ o = api.Operation_ADD
+ case CMD_DEL:
+ o = api.Operation_DEL
+ case CMD_SET:
+ o = api.Operation_REPLACE
+ default:
+ return fmt.Errorf("invalid operation: %s", op)
+ }
+ stmt := &api.Statement{
+ Name: name,
+ Conditions: &api.Conditions{},
+ }
+ arg := &api.ModStatementArguments{
+ Operation: o,
+ Statement: stmt,
+ }
+ usage := fmt.Sprintf("usage: gobgp policy statement %s %s condition", name, op)
+ if len(args) < 1 {
+ return fmt.Errorf("%s { prefix | neighbor | as-path | community | ext-community | as-path-length | rpki }", usage)
+ }
+ typ := args[0]
+ args = args[1:]
+ switch typ {
+ case "prefix":
+ if len(args) < 1 {
+ return fmt.Errorf("%s prefix <set-name> [{ any | invert }]", usage)
+ }
+ stmt.Conditions.PrefixSet = &api.MatchSet{
+ Name: args[0],
+ }
+ if len(args) == 1 {
+ break
+ }
+ switch strings.ToLower(args[1]) {
+ case "any":
+ stmt.Conditions.PrefixSet.Option = int32(config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY)
+ case "invert":
+ stmt.Conditions.PrefixSet.Option = int32(config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT)
+ default:
+ return fmt.Errorf("%s prefix <set-name> [{ any | invert }]", usage)
+ }
+ case "neighbor":
+ if len(args) < 1 {
+ return fmt.Errorf("%s neighbor <set-name> [{ any | invert }]", usage)
+ }
+ stmt.Conditions.NeighborSet = &api.MatchSet{
+ Name: args[0],
+ }
+ if len(args) == 1 {
+ break
+ }
+ switch strings.ToLower(args[1]) {
+ case "any":
+ stmt.Conditions.NeighborSet.Option = int32(config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY)
+ case "invert":
+ stmt.Conditions.NeighborSet.Option = int32(config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT)
+ default:
+ return fmt.Errorf("%s neighbor <set-name> [{ any | invert }]", usage)
+ }
+ case "as-path":
+ if len(args) < 1 {
+ return fmt.Errorf("%s as-path <set-name> [{ any | all | invert }]", usage)
+ }
+ stmt.Conditions.AsPathSet = &api.MatchSet{
+ Name: args[0],
+ }
+ if len(args) == 1 {
+ break
+ }
+ switch strings.ToLower(args[1]) {
+ case "any":
+ stmt.Conditions.AsPathSet.Option = int32(config.MATCH_SET_OPTIONS_TYPE_ANY)
+ case "all":
+ stmt.Conditions.AsPathSet.Option = int32(config.MATCH_SET_OPTIONS_TYPE_ALL)
+ case "invert":
+ stmt.Conditions.AsPathSet.Option = int32(config.MATCH_SET_OPTIONS_TYPE_INVERT)
+ default:
+ return fmt.Errorf("%s as-path <set-name> [{ any | all | invert }]", usage)
+ }
+ case "community":
+ if len(args) < 1 {
+ return fmt.Errorf("%s community <set-name> [{ any | all | invert }]", usage)
+ }
+ stmt.Conditions.CommunitySet = &api.MatchSet{
+ Name: args[0],
+ }
+ if len(args) == 1 {
+ break
+ }
+ switch strings.ToLower(args[1]) {
+ case "any":
+ stmt.Conditions.CommunitySet.Option = int32(config.MATCH_SET_OPTIONS_TYPE_ANY)
+ case "all":
+ stmt.Conditions.CommunitySet.Option = int32(config.MATCH_SET_OPTIONS_TYPE_ALL)
+ case "invert":
+ stmt.Conditions.CommunitySet.Option = int32(config.MATCH_SET_OPTIONS_TYPE_INVERT)
+ default:
+ return fmt.Errorf("%s community <set-name> [{ any | all | invert }]", usage)
+ }
+ case "ext-community":
+ if len(args) < 1 {
+ return fmt.Errorf("%s ext-community <set-name> [{ any | all | invert }]", usage)
+ }
+ stmt.Conditions.ExtCommunitySet = &api.MatchSet{
+ Name: args[0],
+ }
+ if len(args) == 1 {
+ break
+ }
+ switch strings.ToLower(args[1]) {
+ case "any":
+ stmt.Conditions.ExtCommunitySet.Option = int32(config.MATCH_SET_OPTIONS_TYPE_ANY)
+ case "all":
+ stmt.Conditions.ExtCommunitySet.Option = int32(config.MATCH_SET_OPTIONS_TYPE_ALL)
+ case "invert":
+ stmt.Conditions.ExtCommunitySet.Option = int32(config.MATCH_SET_OPTIONS_TYPE_INVERT)
+ default:
+ return fmt.Errorf("%s ext-community <set-name> [{ any | all | invert }]", usage)
+ }
+ case "as-path-length":
+ if len(args) < 2 {
+ return fmt.Errorf("%s as-path-length <length> { eq | ge | le }", usage)
+ }
+ length, err := strconv.Atoi(args[0])
+ if err != nil {
+ return err
+ }
+ stmt.Conditions.AsPathLength = &api.AsPathLength{
+ Length: uint32(length),
+ }
+ switch strings.ToLower(args[1]) {
+ case "eq":
+ stmt.Conditions.AsPathLength.Type = int32(table.ATTRIBUTE_EQ)
+ case "ge":
+ stmt.Conditions.AsPathLength.Type = int32(table.ATTRIBUTE_GE)
+ case "le":
+ stmt.Conditions.AsPathLength.Type = int32(table.ATTRIBUTE_LE)
+ default:
+ return fmt.Errorf("%s as-path-length <length> { eq | ge | le }", usage)
+ }
+ case "rpki":
+ if len(args) < 1 {
+ return fmt.Errorf("%s rpki { valid | invalid | not-found }")
+ }
+ switch strings.ToLower(args[0]) {
+ case "valid":
+ stmt.Conditions.RpkiResult = int32(config.RPKI_VALIDATION_RESULT_TYPE_VALID)
+ case "invalid":
+ stmt.Conditions.RpkiResult = int32(config.RPKI_VALIDATION_RESULT_TYPE_INVALID)
+ case "not-found":
+ stmt.Conditions.RpkiResult = int32(config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND)
+ default:
+ return fmt.Errorf("%s rpki { valid | invalid | not-found }")
+ }
+ }
+ _, err := client.ModStatement(context.Background(), arg)
+ return err
+}
+
+func modAction(name, op string, args []string) error {
+ var o api.Operation
+ switch op {
+ case CMD_ADD:
+ o = api.Operation_ADD
+ case CMD_DEL:
+ o = api.Operation_DEL
+ case CMD_SET:
+ o = api.Operation_REPLACE
+ default:
+ return fmt.Errorf("invalid operation: %s", op)
+ }
+ stmt := &api.Statement{
+ Name: name,
+ Actions: &api.Actions{},
+ }
+ arg := &api.ModStatementArguments{
+ Operation: o,
+ Statement: stmt,
+ }
+ usage := fmt.Sprintf("usage: gobgp policy statement %s %s action", name, op)
+ if len(args) < 1 {
+ return fmt.Errorf("%s { reject | accept | community | ext-community | med | as-prepend }", usage)
+ }
+ typ := args[0]
+ args = args[1:]
+ switch typ {
+ case "reject":
+ stmt.Actions.RouteAction = api.RouteAction_REJECT
+ case "accept":
+ stmt.Actions.RouteAction = api.RouteAction_ACCEPT
+ case "community":
+ if len(args) < 1 {
+ return fmt.Errorf("%s community { add | remove | replace } <value>...", usage)
+ }
+ stmt.Actions.Community = &api.CommunityAction{
+ Communities: args[1:],
+ }
+ switch strings.ToLower(args[0]) {
+ case "add":
+ stmt.Actions.Community.Option = int32(config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD)
+ case "remove":
+ stmt.Actions.Community.Option = int32(config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE)
+ case "replace":
+ stmt.Actions.Community.Option = int32(config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE)
+ default:
+ return fmt.Errorf("%s community { add | remove | replace } <value>...", usage)
+ }
+ case "ext-community":
+ if len(args) < 1 {
+ return fmt.Errorf("%s ext-community { add | remove | replace } <value>...", usage)
+ }
+ stmt.Actions.ExtCommunity = &api.CommunityAction{
+ Communities: args[1:],
+ }
+ switch strings.ToLower(args[0]) {
+ case "add":
+ stmt.Actions.ExtCommunity.Option = int32(config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD)
+ case "remove":
+ stmt.Actions.ExtCommunity.Option = int32(config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE)
+ case "replace":
+ stmt.Actions.ExtCommunity.Option = int32(config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE)
+ default:
+ return fmt.Errorf("%s ext-community { add | remove | replace } <value>...", usage)
+ }
+ case "med":
+ if len(args) < 2 {
+ return fmt.Errorf("%s med { add | sub | set } <value>")
+ }
+ med, err := strconv.Atoi(args[1])
+ if err != nil {
+ return err
+ }
+ stmt.Actions.Med = &api.MedAction{
+ Value: int64(med),
+ }
+ switch strings.ToLower(args[0]) {
+ case "add":
+ stmt.Actions.Med.Type = int32(table.MED_ACTION_MOD)
+ case "sub":
+ stmt.Actions.Med.Type = int32(table.MED_ACTION_MOD)
+ stmt.Actions.Med.Value *= -1
+ case "set":
+ stmt.Actions.Med.Type = int32(table.MED_ACTION_REPLACE)
+ default:
+ return fmt.Errorf("%s med { add | sub | set } <value>")
+ }
+ case "as-prepend":
+ if len(args) < 2 {
+ return fmt.Errorf("%s as-prepend { <asn> | last-as } <repeat-value>", usage)
+ }
+ asn, err := strconv.Atoi(args[0])
+ last := false
+ if args[0] == "last-as" {
+ last = true
+ } else if err != nil {
+ return err
+ }
+ repeat, err := strconv.Atoi(args[1])
+ if err != nil {
+ return err
+ }
+ stmt.Actions.AsPrepend = &api.AsPrependAction{
+ Asn: uint32(asn),
+ Repeat: uint32(repeat),
+ UseLeftMost: last,
+ }
+ }
+ _, err := client.ModStatement(context.Background(), arg)
+ return err
+}
+
func NewPolicyCmd() *cobra.Command {
policyCmd := &cobra.Command{
Use: CMD_POLICY,
@@ -924,11 +1225,11 @@ func NewPolicyCmd() *cobra.Command {
},
}
- for _, v := range []string{CMD_PREFIX, CMD_NEIGHBOR, CMD_ASPATH, CMD_COMMUNITY, CMD_EXTCOMMUNITY, CMD_ROUTEPOLICY} {
+ for _, v := range []string{CMD_PREFIX, CMD_NEIGHBOR, CMD_ASPATH, CMD_COMMUNITY, CMD_EXTCOMMUNITY} {
cmd := &cobra.Command{
Use: v,
Run: func(cmd *cobra.Command, args []string) {
- if err := show(cmd.Use, args); err != nil {
+ if err := showDefinedSet(cmd.Use, args); err != nil {
fmt.Println(err)
}
},
@@ -937,7 +1238,7 @@ func NewPolicyCmd() *cobra.Command {
subcmd := &cobra.Command{
Use: w,
Run: func(c *cobra.Command, args []string) {
- if err := mod(cmd.Use, c.Use, args); err != nil {
+ if err := modDefinedSet(cmd.Use, c.Use, args); err != nil {
fmt.Println(err)
}
},
@@ -947,15 +1248,65 @@ func NewPolicyCmd() *cobra.Command {
policyCmd.AddCommand(cmd)
}
- cmd := &cobra.Command{
+ stmtCmdImpl := &cobra.Command{}
+ for _, v := range []string{CMD_ADD, CMD_DEL, CMD_SET} {
+ cmd := &cobra.Command{
+ Use: v,
+ }
+ for _, w := range []string{CMD_CONDITION, CMD_ACTION} {
+ subcmd := &cobra.Command{
+ Use: w,
+ Run: func(c *cobra.Command, args []string) {
+ name := args[len(args)-1]
+ args = args[:len(args)-1]
+ var err error
+ if c.Use == CMD_CONDITION {
+ err = modCondition(name, cmd.Use, args)
+ } else {
+ err = modAction(name, cmd.Use, args)
+ }
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ },
+ }
+ cmd.AddCommand(subcmd)
+ }
+ stmtCmdImpl.AddCommand(cmd)
+ }
+
+ stmtCmd := &cobra.Command{
Use: CMD_STATEMENT,
Run: func(cmd *cobra.Command, args []string) {
- if err := showStatement(args); err != nil {
+ var err error
+ if len(args) < 2 {
+ err = showStatement(args)
+ } else {
+ args = append(args[1:], args[0])
+ stmtCmdImpl.SetArgs(args)
+ err = stmtCmdImpl.Execute()
+ }
+ if err != nil {
fmt.Println(err)
+ os.Exit(1)
}
},
}
- policyCmd.AddCommand(cmd)
+ for _, v := range []string{CMD_ADD, CMD_DEL} {
+ cmd := &cobra.Command{
+ Use: v,
+ Run: func(c *cobra.Command, args []string) {
+ err := modStatement(c.Use, args)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ },
+ }
+ stmtCmd.AddCommand(cmd)
+ }
+ policyCmd.AddCommand(stmtCmd)
return policyCmd
}
diff --git a/table/policy.go b/table/policy.go
index 1d8cb161..4b146a0f 100644
--- a/table/policy.go
+++ b/table/policy.go
@@ -854,14 +854,17 @@ func (c *PrefixCondition) Evaluate(path *Path) bool {
return result
}
-func (c *PrefixCondition) ToApiStruct() *api.PrefixSet {
- return &api.PrefixSet{
+func (c *PrefixCondition) ToApiStruct() *api.MatchSet {
+ return &api.MatchSet{
Name: c.set.Name(),
Option: int32(c.option),
}
}
-func NewPrefixConditionFromApiStruct(a *api.PrefixSet, m map[string]DefinedSet) (*PrefixCondition, error) {
+func NewPrefixConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*PrefixCondition, error) {
+ if a == nil {
+ return nil, nil
+ }
c := config.MatchPrefixSet{
PrefixSet: a.Name,
MatchSetOptions: config.MatchSetOptionsRestrictedType(a.Option),
@@ -951,6 +954,9 @@ func (c *NeighborCondition) ToApiStruct() *api.MatchSet {
}
func NewNeighborConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*NeighborCondition, error) {
+ if a == nil {
+ return nil, nil
+ }
c := config.MatchNeighborSet{
NeighborSet: a.Name,
MatchSetOptions: config.MatchSetOptionsRestrictedType(a.Option),
@@ -1032,6 +1038,9 @@ func (c *AsPathCondition) Evaluate(path *Path) bool {
}
func NewAsPathConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*AsPathCondition, error) {
+ if a == nil {
+ return nil, nil
+ }
c := config.MatchAsPathSet{
AsPathSet: a.Name,
MatchSetOptions: config.MatchSetOptionsType(a.Option),
@@ -1116,6 +1125,9 @@ func (c *CommunityCondition) Evaluate(path *Path) bool {
}
func NewCommunityConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*CommunityCondition, error) {
+ if a == nil {
+ return nil, nil
+ }
c := config.MatchCommunitySet{
CommunitySet: a.Name,
MatchSetOptions: config.MatchSetOptionsType(a.Option),
@@ -1206,6 +1218,9 @@ func (c *ExtCommunityCondition) Evaluate(path *Path) bool {
}
func NewExtCommunityConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*ExtCommunityCondition, error) {
+ if a == nil {
+ return nil, nil
+ }
c := config.MatchExtCommunitySet{
ExtCommunitySet: a.Name,
MatchSetOptions: config.MatchSetOptionsType(a.Option),
@@ -1281,6 +1296,9 @@ func (c *AsPathLengthCondition) ToApiStruct() *api.AsPathLength {
}
func NewAsPathLengthConditionFromApiStruct(a *api.AsPathLength) (*AsPathLengthCondition, error) {
+ if a == nil {
+ return nil, nil
+ }
return &AsPathLengthCondition{
length: a.Length,
operator: AttributeComparison(a.Type),
@@ -1325,6 +1343,9 @@ func (c *RpkiValidationCondition) Set() DefinedSet {
}
func NewRpkiValidationConditionFromApiStruct(a int32) (*RpkiValidationCondition, error) {
+ if a == 0 {
+ return nil, nil
+ }
typ := config.RpkiValidationResultType(a)
return NewRpkiValidationCondition(typ)
}
@@ -1478,6 +1499,9 @@ func (a *CommunityAction) ToApiStruct() *api.CommunityAction {
}
func NewCommunityActionFromApiStruct(a *api.CommunityAction) (*CommunityAction, error) {
+ if a == nil {
+ return nil, nil
+ }
var list []uint32
var removeList []*regexp.Regexp
op := config.BgpSetCommunityOptionType(a.Option)
@@ -1593,6 +1617,9 @@ func (a *ExtCommunityAction) ToApiStruct() *api.CommunityAction {
}
func NewExtCommunityActionFromApiStruct(a *api.CommunityAction) (*ExtCommunityAction, error) {
+ if a == nil {
+ return nil, nil
+ }
var list []bgp.ExtendedCommunityInterface
var removeList []*regexp.Regexp
subtypeList := make([]bgp.ExtendedCommunityAttrSubType, 0, len(a.Communities))
@@ -1713,6 +1740,9 @@ func (a *MedAction) ToApiStruct() *api.MedAction {
}
func NewMedActionFromApiStruct(a *api.MedAction) (*MedAction, error) {
+ if a == nil {
+ return nil, nil
+ }
return &MedAction{
action: MedActionType(a.Type),
value: int(a.Value),
@@ -1793,6 +1823,9 @@ func (a *AsPathPrependAction) ToApiStruct() *api.AsPrependAction {
}
func NewAsPathPrependActionFromApiStruct(a *api.AsPrependAction) (*AsPathPrependAction, error) {
+ if a == nil {
+ return nil, nil
+ }
return &AsPathPrependAction{
asn: a.Asn,
useLeftMost: a.UseLeftMost,
@@ -1897,7 +1930,9 @@ func (s *Statement) ToApiStruct() *api.Statement {
}
}
as := &api.Actions{}
- as.RouteAction = s.RouteAction.(*RoutingAction).ToApiStruct()
+ if s.RouteAction != nil {
+ as.RouteAction = s.RouteAction.(*RoutingAction).ToApiStruct()
+ }
for _, a := range s.ModActions {
switch a.(type) {
case *CommunityAction:
@@ -1944,38 +1979,41 @@ func (lhs *Statement) mod(op opType, rhs *Statement) error {
switch op {
case ADD:
if c != nil {
- return fmt.Errorf("condition %d is already set", c.Type())
+ return fmt.Errorf("condition %d is already set", x.Type())
}
if cs == nil {
- cs = make([]Condition, len(rhs.Conditions))
+ cs = make([]Condition, 0, len(rhs.Conditions))
}
cs = append(cs, x)
case REMOVE:
if c == nil {
- return fmt.Errorf("condition %d is not set", c.Type())
+ return fmt.Errorf("condition %d is not set", x.Type())
}
cs = append(cs[:i], cs[i+1:]...)
+ if len(cs) == 0 {
+ cs = nil
+ }
case REPLACE:
if c == nil {
- return fmt.Errorf("condition %d is not set", c.Type())
+ return fmt.Errorf("condition %d is not set", x.Type())
}
cs[i] = x
}
}
- if rhs.RouteAction != nil {
+ if rhs.RouteAction != nil && !reflect.ValueOf(rhs.RouteAction).IsNil() {
switch op {
case ADD:
- if lhs.RouteAction != nil {
+ if lhs.RouteAction != nil && !reflect.ValueOf(lhs.RouteAction).IsNil() {
return fmt.Errorf("route action is already set")
}
ra = rhs.RouteAction
case REMOVE:
- if lhs.RouteAction == nil {
+ if lhs.RouteAction == nil || reflect.ValueOf(lhs.RouteAction).IsNil() {
return fmt.Errorf("route action is not set")
}
ra = nil
case REPLACE:
- if lhs.RouteAction == nil {
+ if lhs.RouteAction == nil || reflect.ValueOf(lhs.RouteAction).IsNil() {
return fmt.Errorf("route action is not set")
}
ra = rhs.RouteAction
@@ -1994,20 +2032,23 @@ func (lhs *Statement) mod(op opType, rhs *Statement) error {
switch op {
case ADD:
if a != nil {
- return fmt.Errorf("action %d is already set", a.Type())
+ return fmt.Errorf("action %d is already set", x.Type())
}
if as == nil {
- as = make([]Action, len(rhs.ModActions))
+ as = make([]Action, 0, len(rhs.ModActions))
}
- as = append(as, a)
+ as = append(as, x)
case REMOVE:
if a == nil {
- return fmt.Errorf("action %d is not set", a.Type())
+ return fmt.Errorf("action %d is not set", x.Type())
}
as = append(as[:i], as[i+1:]...)
+ if len(as) == 0 {
+ as = nil
+ }
case REPLACE:
if a == nil {
- return fmt.Errorf("action %d is not set", a.Type())
+ return fmt.Errorf("action %d is not set", x.Type())
}
as[i] = x
}