summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2015-10-18 13:14:41 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2015-10-20 10:33:10 +0900
commit16234ccbb3bbd88759012c95efb690aa2eaba542 (patch)
tree1c6cc5caa7a645e60e2049916857c43933aa1854
parentf61709a2a668f093a44badd127e412be8ed14b92 (diff)
cli: support defined-set configuration
prefix-set modification gobgp policy prefix add p0 10.0.0.0/24 10..15 neighbor-set modification gobgp policy neighbor add n0 10.0.0.1 as-path-set modification gobgp policy aspath add a0 '^100_200_300$' community-set modification gobgp policy community add c0 100:100 ext-community-set modification gobgp policy community add e0 rt:100:100 Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
-rw-r--r--gobgp/cmd/common.go1
-rw-r--r--gobgp/cmd/policy.go841
-rw-r--r--server/server.go12
-rw-r--r--table/policy.go82
4 files changed, 301 insertions, 635 deletions
diff --git a/gobgp/cmd/common.go b/gobgp/cmd/common.go
index 12f54008..0b6ca6ff 100644
--- a/gobgp/cmd/common.go
+++ b/gobgp/cmd/common.go
@@ -35,6 +35,7 @@ const (
CMD_ADD = "add"
CMD_DEL = "del"
CMD_ALL = "all"
+ CMD_SET = "set"
CMD_LOCAL = "local"
CMD_ADJ_IN = "adj-in"
CMD_ADJ_OUT = "adj-out"
diff --git a/gobgp/cmd/policy.go b/gobgp/cmd/policy.go
index f56b300e..2b4ecbc6 100644
--- a/gobgp/cmd/policy.go
+++ b/gobgp/cmd/policy.go
@@ -33,6 +33,9 @@ import (
)
func formatPolicyPrefix(head bool, indent int, psl []*api.DefinedSet) string {
+ if len(psl) == 0 {
+ return "Nothing defined yet\n"
+ }
buff := bytes.NewBuffer(make([]byte, 0, 64))
sIndent := strings.Repeat(" ", indent)
maxNameLen := 0
@@ -49,20 +52,24 @@ func formatPolicyPrefix(head bool, indent int, psl []*api.DefinedSet) string {
}
if head {
- if len("Name") > maxNameLen {
- maxNameLen = len("Name")
+ if len("NAME") > maxNameLen {
+ maxNameLen = len("NAME")
}
- if len("Prefix") > maxPrefixLen {
- maxPrefixLen = len("Prefix")
+ if len("PREFIX") > maxPrefixLen {
+ maxPrefixLen = len("PREFIX")
}
}
format := fmt.Sprintf("%%-%ds %%-%ds ", maxNameLen, maxPrefixLen)
if head {
- buff.WriteString(fmt.Sprintf(format, "Name", "Prefix"))
+ buff.WriteString(fmt.Sprintf(format, "NAME", "PREFIX"))
buff.WriteString("MaskLengthRange\n")
}
for _, ps := range psl {
+ if len(ps.Prefixes) == 0 {
+ buff.WriteString(fmt.Sprintf(format, ps.Name, ""))
+ buff.WriteString("\n")
+ }
for i, p := range ps.Prefixes {
if i == 0 {
buff.WriteString(fmt.Sprintf(format, ps.Name, p.IpPrefix))
@@ -77,168 +84,46 @@ func formatPolicyPrefix(head bool, indent int, psl []*api.DefinedSet) string {
return buff.String()
}
-func formatPolicyNeighbor(head bool, indent int, nsl []*api.DefinedSet) string {
- buff := bytes.NewBuffer(make([]byte, 0, 64))
- sIndent := strings.Repeat(" ", indent)
- maxNameLen := 0
- maxAddressLen := 0
- for _, ns := range nsl {
- if len(ns.Name) > maxNameLen {
- maxNameLen = len(ns.Name)
- }
- for _, n := range ns.List {
- if len(n) > maxAddressLen {
- maxAddressLen = len(n)
- }
- }
- }
-
- if head {
- if len("Name") > maxNameLen {
- maxNameLen = len("Name")
- }
- if len("Address") > maxAddressLen {
- maxAddressLen = len("Address")
- }
- }
-
- format := "%-" + fmt.Sprint(maxNameLen) + "s %-" + fmt.Sprint(maxAddressLen) + "s\n"
- if head {
- buff.WriteString(fmt.Sprintf(format, "Name", "Address"))
- }
- for _, ns := range nsl {
- for i, n := range ns.List {
- if i == 0 {
- buff.WriteString(fmt.Sprintf(format, ns.Name, n))
- } else {
- buff.WriteString(fmt.Sprintf(sIndent))
- buff.WriteString(fmt.Sprintf(format, "", n))
- }
- }
+func formatDefinedSet(head bool, typ string, indent int, list []*api.DefinedSet) string {
+ if len(list) == 0 {
+ return "Nothing defined yet\n"
}
- return buff.String()
-}
-
-func formatPolicyAsPath(haed bool, indent int, apsl []*api.DefinedSet) string {
buff := bytes.NewBuffer(make([]byte, 0, 64))
sIndent := strings.Repeat(" ", indent)
maxNameLen := 0
- maxPathLen := 0
- for _, aps := range apsl {
- if len(aps.Name) > maxNameLen {
- maxNameLen = len(aps.Name)
- }
- for _, m := range aps.List {
- if len(m) > maxPathLen {
- maxPathLen = len(m)
- }
- }
- }
-
- if haed {
- if len("Name") > maxNameLen {
- maxNameLen = len("Name")
- }
- if len("AsPath") > maxPathLen {
- maxPathLen = len("AsPath")
- }
- }
-
- format := "%-" + fmt.Sprint(maxNameLen) + "s %-" + fmt.Sprint(maxPathLen) + "s\n"
- if haed {
- buff.WriteString(fmt.Sprintf(format, "Name", "AsPath"))
- }
- for _, aps := range apsl {
- for i, a := range aps.List {
- if i == 0 {
- buff.WriteString(fmt.Sprintf(format, aps.Name, a))
- } else {
- buff.WriteString(fmt.Sprintf(sIndent))
- buff.WriteString(fmt.Sprintf(format, "", a))
- }
+ maxValueLen := 0
+ for _, s := range list {
+ if len(s.Name) > maxNameLen {
+ maxNameLen = len(s.Name)
}
- }
- return buff.String()
-}
-
-func formatPolicyCommunity(head bool, indent int, csl []*api.DefinedSet) string {
- buff := bytes.NewBuffer(make([]byte, 0, 64))
- sIndent := strings.Repeat(" ", indent)
- maxNameLen := 0
- maxCommunityLen := 0
- for _, cs := range csl {
- if len(cs.Name) > maxNameLen {
- maxNameLen = len(cs.Name)
- }
- for _, m := range cs.List {
- if len(m) > maxCommunityLen {
- maxCommunityLen = len(m)
+ for _, x := range s.List {
+ if len(x) > maxValueLen {
+ maxValueLen = len(x)
}
}
}
-
if head {
- if len("Name") > maxNameLen {
- maxNameLen = len("Name")
+ if len("NAME") > maxNameLen {
+ maxNameLen = len("NAME")
}
- if len("Community") > maxCommunityLen {
- maxCommunityLen = len("Community")
+ if len(typ) > maxValueLen {
+ maxValueLen = len(typ)
}
}
-
- format := "%-" + fmt.Sprint(maxNameLen) + "s %-" + fmt.Sprint(maxCommunityLen) + "s\n"
+ format := fmt.Sprintf("%%-%ds %%-%ds\n", maxNameLen, maxValueLen)
if head {
- buff.WriteString(fmt.Sprintf(format, "Name", "Community"))
+ buff.WriteString(fmt.Sprintf(format, "NAME", typ))
}
- for _, cs := range csl {
- for i, c := range cs.List {
- if i == 0 {
- buff.WriteString(fmt.Sprintf(format, cs.Name, c))
- } else {
- buff.WriteString(fmt.Sprintf(sIndent))
- buff.WriteString(fmt.Sprintf(format, "", c))
- }
- }
- }
- return buff.String()
-}
-
-func formatPolicyExtCommunity(head bool, indent int, ecsl []*api.DefinedSet) string {
- buff := bytes.NewBuffer(make([]byte, 0, 64))
- sIndent := strings.Repeat(" ", indent)
- maxNameLen := 0
- maxCommunityLen := 0
- for _, es := range ecsl {
- if len(es.Name) > maxNameLen {
- maxNameLen = len(es.Name)
- }
- for _, m := range es.List {
- if len(m) > maxCommunityLen {
- maxCommunityLen = len(m)
- }
- }
- }
-
- if head {
- if len("Name") > maxNameLen {
- maxNameLen = len("Name")
+ for _, s := range list {
+ if len(s.List) == 0 {
+ buff.WriteString(fmt.Sprintf(format, s.Name, ""))
}
- if len("ExtCommunity") > maxCommunityLen {
- maxCommunityLen = len("ExtCommunity")
- }
- }
-
- format := "%-" + fmt.Sprint(maxNameLen) + "s %-" + fmt.Sprint(maxCommunityLen) + "s\n"
- if head {
- buff.WriteString(fmt.Sprintf(format, "Name", "ExtCommunity"))
- }
- for _, ecs := range ecsl {
- for i, ec := range ecs.List {
+ for i, x := range s.List {
if i == 0 {
- buff.WriteString(fmt.Sprintf(format, ecs.Name, ec))
+ buff.WriteString(fmt.Sprintf(format, s.Name, x))
} else {
buff.WriteString(fmt.Sprintf(sIndent))
- buff.WriteString(fmt.Sprintf(format, "", ec))
+ buff.WriteString(fmt.Sprintf(format, "", x))
}
}
}
@@ -273,6 +158,9 @@ func show(v string, args []string) error {
}
m = append(m, p)
} else {
+ arg := &api.DefinedSet{
+ Type: int32(typ),
+ }
stream, e := client.GetDefinedSets(context.Background(), arg)
if e != nil {
return e
@@ -313,458 +201,202 @@ func show(v string, args []string) error {
case CMD_PREFIX:
output = formatPolicyPrefix(true, 0, m)
case CMD_NEIGHBOR:
- output = formatPolicyNeighbor(true, 0, m)
+ output = formatDefinedSet(true, "ADDRESS", 0, m)
case CMD_ASPATH:
- output = formatPolicyAsPath(true, 0, m)
+ output = formatDefinedSet(true, "AS-PATH", 0, m)
case CMD_COMMUNITY:
- output = formatPolicyCommunity(true, 0, m)
+ output = formatDefinedSet(true, "COMMUNITY", 0, m)
case CMD_EXTCOMMUNITY:
- output = formatPolicyExtCommunity(true, 0, m)
+ output = formatDefinedSet(true, "EXT-COMMUNITY", 0, m)
}
fmt.Print(output)
return nil
}
-func parsePrefixSet(eArgs []string) (*api.DefinedSet, error) {
- _, ipNet, e := net.ParseCIDR(eArgs[1])
- if e != nil {
- return nil, fmt.Errorf("invalid prefix: %s\nplease enter ipv4 or ipv6 format", eArgs[1])
+func parsePrefixSet(args []string) (*api.DefinedSet, error) {
+ if len(args) < 1 {
+ return nil, fmt.Errorf("empty neighbor set name")
}
- prefix := &api.Prefix{
- IpPrefix: eArgs[1],
- }
-
- if len(eArgs) == 3 {
- maskRange := eArgs[2]
- idx := strings.Index(maskRange, "..")
- if idx == -1 {
- 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 {
+ name := args[0]
+ args = args[1:]
+ var list []*api.Prefix
+ if len(args) > 0 {
+ _, ipNet, err := net.ParseCIDR(args[0])
+ if err != nil {
+ return nil, fmt.Errorf("invalid prefix: %s\nplease enter ipv4 or ipv6 format", args[1])
+ }
+ l, _ := ipNet.Mask.Size()
+ prefix := &api.Prefix{
+ IpPrefix: args[0],
+ MaskLengthMin: uint32(l),
+ MaskLengthMax: uint32(l),
+ }
+ if len(args) > 1 {
+ maskRange := args[1]
+ exp := regexp.MustCompile("(\\d+)\\.\\.(\\d+)")
+ elems := exp.FindStringSubmatch(maskRange)
+ if len(elems) != 3 {
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 {
+ // we've already checked the range is sane by regexp
+ min, _ := strconv.Atoi(elems[1])
+ max, _ := strconv.Atoi(elems[2])
+ if min > max {
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)
- }
- } else {
- if min < 0 || 128 < max {
- return nil, fmt.Errorf("ipv6 mask length range outside scope :%s", maskRange)
+ if ipv4 := ipNet.IP.To4(); ipv4 != nil {
+ f := func(i int) bool {
+ return i >= 0 && i <= 32
+ }
+ if !f(min) || !f(max) {
+ return nil, fmt.Errorf("ipv4 mask length range outside scope :%s", maskRange)
+ }
+ } else {
+ f := func(i int) bool {
+ return i >= 0 && i <= 128
+ }
+ if !f(min) || !f(max) {
+ return nil, fmt.Errorf("ipv6 mask length range outside scope :%s", maskRange)
+ }
}
+ prefix.MaskLengthMin = uint32(min)
+ prefix.MaskLengthMax = uint32(max)
}
- if min >= max {
- return nil, fmt.Errorf("invalid mask length range: %s\nlarge value to the right from the left", maskRange)
- }
- prefix.MaskLengthMin = uint32(min)
- prefix.MaskLengthMax = uint32(max)
+ list = []*api.Prefix{prefix}
}
- prefixList := []*api.Prefix{prefix}
return &api.DefinedSet{
Type: int32(table.DEFINED_TYPE_PREFIX),
- Name: eArgs[0],
- Prefixes: prefixList,
+ Name: name,
+ Prefixes: list,
}, nil
}
-func modPolicy(resource api.Resource, op api.Operation, data interface{}) error {
- pd := &api.PolicyDefinition{}
- if resource != api.Resource_POLICY_ROUTEPOLICY {
- co := &api.Conditions{}
- switch resource {
- case api.Resource_POLICY_PREFIX:
- co.PrefixSet = data.(*api.PrefixSet)
- case api.Resource_POLICY_NEIGHBOR:
- co.NeighborSet = data.(*api.MatchSet)
- case api.Resource_POLICY_ASPATH:
- co.AsPathSet = data.(*api.MatchSet)
- case api.Resource_POLICY_COMMUNITY:
- co.CommunitySet = data.(*api.MatchSet)
- case api.Resource_POLICY_EXTCOMMUNITY:
- co.ExtCommunitySet = data.(*api.MatchSet)
- }
- pd.Statements = []*api.Statement{{Conditions: co}}
- } else {
- pd = data.(*api.PolicyDefinition)
- }
- arg := &api.PolicyArguments{
- Resource: resource,
- Operation: op,
- PolicyDefinition: pd,
- }
- stream, err := client.ModPolicyRoutePolicy(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 modPolicyPrefix(modtype string, eArgs []string) error {
- prefixSet := &api.DefinedSet{}
- var e error
- var operation api.Operation
- switch modtype {
- case CMD_ADD:
- if len(eArgs) < 2 {
- return fmt.Errorf("usage: policy prefix add <prefix set name> <prefix> [<mask length renge>]")
- }
- if prefixSet, e = parsePrefixSet(eArgs); e != nil {
- return e
- }
- operation = api.Operation_ADD
- case CMD_DEL:
- if len(eArgs) == 0 {
- return fmt.Errorf("usage: policy prefix del <prefix set name> [<prefix> [<mask length renge>]]")
- } else if len(eArgs) == 1 {
- prefixSet = &api.DefinedSet{
- Name: eArgs[0],
- }
- } else {
- if prefixSet, e = parsePrefixSet(eArgs); e != nil {
- return e
- }
- }
- operation = api.Operation_DEL
- case CMD_ALL:
- if len(eArgs) > 0 {
- return fmt.Errorf("Argument can not be entered: %s", eArgs[0:])
- }
- operation = api.Operation_DEL_ALL
- default:
- return fmt.Errorf("invalid modType %s", modtype)
- }
- if e = modPolicy(api.Resource_POLICY_PREFIX, operation, prefixSet); e != nil {
- return e
- }
- return nil
-}
-
-func showPolicyNeighbor(args []string) error {
- arg := &api.DefinedSet{
- Type: int32(table.DEFINED_TYPE_NEIGHBOR),
- Name: args[0],
- }
- ns, e := client.GetDefinedSet(context.Background(), arg)
- if e != nil {
- return e
- }
- if globalOpts.Json {
- j, _ := json.Marshal(ns)
- fmt.Println(string(j))
- return nil
+func parseNeighborSet(args []string) (*api.DefinedSet, error) {
+ if len(args) < 1 {
+ return nil, fmt.Errorf("empty neighbor set name")
}
- if globalOpts.Quiet {
- for _, n := range ns.List {
- fmt.Println(n)
- }
- return nil
- }
- output := formatPolicyNeighbor(true, 0, []*api.DefinedSet{ns})
- fmt.Print(output)
- return nil
-}
-
-func parseNeighborSet(eArgs []string) (*api.DefinedSet, error) {
- address := net.ParseIP(eArgs[1])
- if address.To4() == nil {
- if address.To16() == nil {
- return nil, fmt.Errorf("invalid address: %s\nplease enter ipv4 or ipv6 format", eArgs[1])
+ name := args[0]
+ args = args[1:]
+ for _, arg := range args {
+ address := net.ParseIP(arg)
+ if address.To4() == nil && address.To16() == nil {
+ return nil, fmt.Errorf("invalid address: %s\nplease enter ipv4 or ipv6 format", arg)
}
}
-
return &api.DefinedSet{
Type: int32(table.DEFINED_TYPE_NEIGHBOR),
- Name: eArgs[0],
- List: []string{address.String()},
+ Name: name,
+ List: args,
}, nil
}
-func modPolicyNeighbor(modtype string, eArgs []string) error {
- neighborSet := &api.DefinedSet{}
- var e error
- var operation api.Operation
-
- switch modtype {
- case CMD_ADD:
- if len(eArgs) < 2 {
- return fmt.Errorf("usage: policy neighbor add <neighbor set name> <address>")
- }
- if neighborSet, e = parseNeighborSet(eArgs); e != nil {
- return e
- }
- operation = api.Operation_ADD
- case CMD_DEL:
- if len(eArgs) == 0 {
- return fmt.Errorf("usage: policy neighbor del <neighbor set name> [<address>]")
- } else if len(eArgs) == 1 {
- neighborSet = &api.DefinedSet{
- Name: eArgs[0],
- }
- } else {
- if neighborSet, e = parseNeighborSet(eArgs); e != nil {
- return e
- }
- }
- operation = api.Operation_DEL
- case CMD_ALL:
- if len(eArgs) > 0 {
- return fmt.Errorf("Argument can not be entered: %s", eArgs[0:])
- }
- operation = api.Operation_DEL_ALL
- default:
- return fmt.Errorf("invalid modType %s", modtype)
+func parseAsPathSet(args []string) (*api.DefinedSet, error) {
+ if len(args) < 1 {
+ return nil, fmt.Errorf("empty as-path set name")
}
- if e = modPolicy(api.Resource_POLICY_NEIGHBOR, operation, neighborSet); e != nil {
- return e
- }
- return nil
-}
-
-func parseAsPathSet(eArgs []string) (*api.DefinedSet, error) {
- as := eArgs[1]
- isTop := as[:1] == "^"
- if isTop {
- as = as[1:]
- }
- isEnd := as[len(as)-1:] == "$"
- if isEnd {
- as = as[:len(as)-1]
- }
- elems := strings.Split(as, "_")
- for _, el := range elems {
- if len(el) == 0 {
- return nil, fmt.Errorf("invalid aspath element: %s \ndo not enter a blank", eArgs[1])
- }
- _, err := regexp.Compile(el)
+ name := args[0]
+ args = args[1:]
+ for _, arg := range args {
+ _, err := regexp.Compile(arg)
if err != nil {
- return nil, fmt.Errorf("invalid aspath element: %s \n"+
- "can not comple aspath values to regular expressions.", eArgs[1])
+ return nil, err
}
}
return &api.DefinedSet{
- Name: eArgs[0],
- List: []string{eArgs[1]},
+ Type: int32(table.DEFINED_TYPE_AS_PATH),
+ Name: name,
+ List: args,
}, nil
}
-func modPolicyAsPath(modtype string, eArgs []string) error {
- asPathSet := &api.DefinedSet{}
- var e error
- var operation api.Operation
-
- switch modtype {
- case CMD_ADD:
- if len(eArgs) < 2 {
- return fmt.Errorf("usage: policy aspath add <aspath set name> <aspath>")
- }
- if asPathSet, e = parseAsPathSet(eArgs); e != nil {
- return e
- }
- operation = api.Operation_ADD
- case CMD_DEL:
- if len(eArgs) == 0 {
- return fmt.Errorf("usage: policy aspath del <aspath set name> [<aspath>]")
- } else if len(eArgs) == 1 {
- asPathSet = &api.DefinedSet{
- Name: eArgs[0],
- }
- } else {
- if asPathSet, e = parseAsPathSet(eArgs); e != nil {
- return e
- }
- }
- operation = api.Operation_DEL
- case CMD_ALL:
- if len(eArgs) > 0 {
- return fmt.Errorf("Argument can not be entered: %s", eArgs[0:])
- }
- operation = api.Operation_DEL_ALL
- default:
- return fmt.Errorf("invalid modType %s", modtype)
+func parseCommunitySet(args []string) (*api.DefinedSet, error) {
+ if len(args) < 1 {
+ return nil, fmt.Errorf("empty community set name")
}
- if e = modPolicy(api.Resource_POLICY_ASPATH, operation, asPathSet); e != nil {
- return e
+ name := args[0]
+ args = args[1:]
+ for _, arg := range args {
+ if _, err := table.ParseCommunityRegexp(arg); err != nil {
+ return nil, err
+ }
}
- return nil
+ return &api.DefinedSet{
+ Type: int32(table.DEFINED_TYPE_COMMUNITY),
+ Name: name,
+ List: args,
+ }, nil
}
-func checkCommunityFormat(comStr string) bool {
- _, e := table.ParseCommunity(comStr)
- if e == nil {
- return true
+func parseExtCommunitySet(args []string) (*api.DefinedSet, error) {
+ if len(args) < 1 {
+ return nil, fmt.Errorf("empty ext-community set name")
}
- return false
-}
-
-func parseCommunitySet(eArgs []string) (*api.DefinedSet, error) {
- if !checkCommunityFormat(eArgs[1]) {
- if _, err := regexp.Compile(eArgs[1]); err != nil {
- return nil, fmt.Errorf("invalid community: %s\nplease enter community format", eArgs[1])
+ name := args[0]
+ args = args[1:]
+ for _, arg := range args {
+ if _, _, err := table.ParseExtCommunityRegexp(arg); err != nil {
+ return nil, err
}
}
- communitySet := &api.DefinedSet{
- Name: eArgs[0],
- List: []string{eArgs[1]},
- }
- return communitySet, nil
+ return &api.DefinedSet{
+ Type: int32(table.DEFINED_TYPE_EXT_COMMUNITY),
+ Name: name,
+ List: args,
+ }, nil
}
-func modPolicyCommunity(modtype string, eArgs []string) error {
- communitySet := &api.DefinedSet{}
- var e error
- var operation api.Operation
-
- switch modtype {
- case CMD_ADD:
- if len(eArgs) < 2 {
- return fmt.Errorf("usage: policy community add <community set name> <community>")
- }
- if communitySet, e = parseCommunitySet(eArgs); e != nil {
- return e
- }
- operation = api.Operation_ADD
- case CMD_DEL:
- if len(eArgs) == 0 {
- return fmt.Errorf("usage: policy community add <community set name> [<community>]")
- } else if len(eArgs) == 1 {
- communitySet = &api.DefinedSet{
- Name: eArgs[0],
- }
- } else {
- if communitySet, e = parseCommunitySet(eArgs); e != nil {
- return e
- }
- }
- operation = api.Operation_DEL
- case CMD_ALL:
- if len(eArgs) > 0 {
- return fmt.Errorf("Argument can not be entered: %s", eArgs[0:])
- }
- operation = api.Operation_DEL_ALL
+func parseDefinedSet(settype string, args []string) (*api.DefinedSet, error) {
+ switch settype {
+ case CMD_PREFIX:
+ return parsePrefixSet(args)
+ case CMD_NEIGHBOR:
+ return parseNeighborSet(args)
+ case CMD_ASPATH:
+ return parseAsPathSet(args)
+ case CMD_COMMUNITY:
+ return parseCommunitySet(args)
+ case CMD_EXTCOMMUNITY:
+ return parseExtCommunitySet(args)
default:
- return fmt.Errorf("invalid modType %s", modtype)
- }
- if e = modPolicy(api.Resource_POLICY_COMMUNITY, operation, communitySet); e != nil {
- return e
+ return nil, fmt.Errorf("invalid setype: %s", settype)
}
- return nil
}
-func checkExtCommunityFormat(eComStr string) bool {
- // extended community regexp
- checkSubType := func(eComStr string) (bool, string) {
- regSubType, _ := regexp.Compile("^(RT|SoO):(.*)$")
- if regSubType.MatchString(eComStr) {
- regResult := regSubType.FindStringSubmatch(eComStr)
- return true, regResult[2]
- }
- return false, ""
- }
- checkValue := func(eComVal string) (bool, string) {
- regVal, _ := regexp.Compile("^([0-9\\.]+):([0-9]+)$")
- if regVal.MatchString(eComVal) {
- regResult := regVal.FindStringSubmatch(eComVal)
- return true, regResult[1]
- }
- return false, ""
- }
- checkElem := func(gAdmin string) bool {
- addr := net.ParseIP(gAdmin)
- if addr.To4() != nil {
- return true
- }
- regAs, _ := regexp.Compile("^([0-9]+)$")
- regAs4, _ := regexp.Compile("^([0-9]+).([0-9]+)$")
- if regAs.MatchString(gAdmin) || regAs4.MatchString(gAdmin) {
- return true
- }
- return false
- }
-
- if subTypeOk, eComVal := checkSubType(eComStr); subTypeOk {
- if valOk, gAdmin := checkValue(eComVal); valOk {
- if checkElem(gAdmin) {
- return true
- }
- }
- _, err := regexp.Compile(eComVal)
- if err == nil {
- return true
- }
- }
- return false
+var modPolicyUsageFormat = map[string]string{
+ CMD_PREFIX: "usage: policy prefix %s <name> [<prefix> [<mask range>]]",
+ CMD_NEIGHBOR: "usage: policy neighbor %s <name> [<neighbor address>...]",
+ CMD_ASPATH: "usage: policy aspath %s <name> [<regexp>...]",
+ CMD_COMMUNITY: "usage: policy community %s <name> [<regexp>...]",
+ CMD_EXTCOMMUNITY: "usage: policy extcommunity %s <name> [<regexp>...]",
}
-func parseExtCommunitySet(eArgs []string) (*api.DefinedSet, error) {
- if !checkExtCommunityFormat(eArgs[1]) {
- return nil, fmt.Errorf("invalid extended community: %s\nplease enter extended community format", eArgs[1])
+func mod(settype string, modtype string, args []string) error {
+ var d *api.DefinedSet
+ var err error
+ if len(args) < 1 {
+ return fmt.Errorf(modPolicyUsageFormat[settype], modtype)
}
- return &api.DefinedSet{
- Name: eArgs[0],
- List: []string{eArgs[1]},
- }, nil
-}
-
-func modPolicyExtCommunity(modtype string, eArgs []string) error {
- extCommunitySet := &api.DefinedSet{}
- var e error
- var operation api.Operation
-
+ if d, err = parseDefinedSet(settype, args); err != nil {
+ return err
+ }
+ var op api.Operation
switch modtype {
case CMD_ADD:
- if len(eArgs) < 2 {
- return fmt.Errorf("usage: policy extcommunity add <community set name> <community>")
- }
- if extCommunitySet, e = parseExtCommunitySet(eArgs); e != nil {
- return e
- }
- operation = api.Operation_ADD
+ op = api.Operation_ADD
case CMD_DEL:
- if len(eArgs) == 0 {
- return fmt.Errorf("usage: policy extcommunity add <community set name> [<community>]")
- } else if len(eArgs) == 1 {
- extCommunitySet = &api.DefinedSet{
- Name: eArgs[0],
- }
+ if len(args) < 2 {
+ op = api.Operation_DEL_ALL
} else {
- if extCommunitySet, e = parseExtCommunitySet(eArgs); e != nil {
- return e
- }
- }
- operation = api.Operation_DEL
- case CMD_ALL:
- if len(eArgs) > 0 {
- return fmt.Errorf("Argument can not be entered: %s", eArgs[0:])
+ op = api.Operation_DEL
}
- operation = api.Operation_DEL_ALL
- default:
- return fmt.Errorf("invalid modType %s", modtype)
+ case CMD_SET:
+ op = api.Operation_REPLACE
}
- if e = modPolicy(api.Resource_POLICY_EXTCOMMUNITY, operation, extCommunitySet); e != nil {
- return e
- }
- return nil
+ _, err = client.ModDefinedSet(context.Background(), &api.ModDefinedSetArguments{
+ Operation: op,
+ Set: d,
+ })
+ return err
}
func showPolicyStatement(indent int, pd *api.PolicyDefinition) {
@@ -1140,6 +772,51 @@ func parseActions() (*api.Actions, error) {
return actions, nil
}
+func modPolicy(resource api.Resource, op api.Operation, data interface{}) error {
+ pd := &api.PolicyDefinition{}
+ if resource != api.Resource_POLICY_ROUTEPOLICY {
+ co := &api.Conditions{}
+ switch resource {
+ case api.Resource_POLICY_PREFIX:
+ co.PrefixSet = data.(*api.PrefixSet)
+ case api.Resource_POLICY_NEIGHBOR:
+ co.NeighborSet = data.(*api.MatchSet)
+ case api.Resource_POLICY_ASPATH:
+ co.AsPathSet = data.(*api.MatchSet)
+ case api.Resource_POLICY_COMMUNITY:
+ co.CommunitySet = data.(*api.MatchSet)
+ case api.Resource_POLICY_EXTCOMMUNITY:
+ co.ExtCommunitySet = data.(*api.MatchSet)
+ }
+ pd.Statements = []*api.Statement{{Conditions: co}}
+ } else {
+ pd = data.(*api.PolicyDefinition)
+ }
+ arg := &api.PolicyArguments{
+ Resource: resource,
+ Operation: op,
+ PolicyDefinition: pd,
+ }
+ stream, err := client.ModPolicyRoutePolicy(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 modPolicyRoutePolicy(modtype string, eArgs []string) error {
var operation api.Operation
pd := &api.PolicyDefinition{}
@@ -1195,56 +872,6 @@ func modPolicyRoutePolicy(modtype string, eArgs []string) error {
return nil
}
-func NewPolicyAddCmd(v string, mod func(string, []string) error) *cobra.Command {
- policyAddCmd := &cobra.Command{
- Use: CMD_ADD,
- Run: func(cmd *cobra.Command, args []string) {
- err := mod(cmd.Use, args)
- if err != nil {
- fmt.Println(err)
- }
- },
- }
- if v == CMD_ROUTEPOLICY {
- policyAddCmd.Flags().StringVarP(&conditionOpts.Prefix, "c-prefix", "", "", "a prefix set name of policy condition")
- policyAddCmd.Flags().StringVarP(&conditionOpts.Neighbor, "c-neighbor", "", "", "a neighbor set name of policy condition")
- policyAddCmd.Flags().StringVarP(&conditionOpts.AsPath, "c-aspath", "", "", "an as path set name of policy condition")
- policyAddCmd.Flags().StringVarP(&conditionOpts.Community, "c-community", "", "", "a community set name of policy condition")
- policyAddCmd.Flags().StringVarP(&conditionOpts.ExtCommunity, "c-extcommunity", "", "", "a extended community set name of policy condition")
- policyAddCmd.Flags().StringVarP(&conditionOpts.AsPathLength, "c-aslen", "", "", "an as path length of policy condition (<operator>,<numeric>)")
- policyAddCmd.Flags().StringVarP(&actionOpts.RouteAction, "a-route", "", "", "a route action of policy action (accept | reject)")
- policyAddCmd.Flags().StringVarP(&actionOpts.CommunityAction, "a-community", "", "", "a community of policy action")
- policyAddCmd.Flags().StringVarP(&actionOpts.MedAction, "a-med", "", "", "a med of policy action")
- policyAddCmd.Flags().StringVarP(&actionOpts.AsPathPrependAction, "a-asprepend", "", "", "aspath prepend for policy action")
- }
-
- return policyAddCmd
-}
-
-func NewPolicyDelCmd(mod func(string, []string) error) *cobra.Command {
- policyDelCmd := &cobra.Command{
- Use: CMD_DEL,
- Run: func(cmd *cobra.Command, args []string) {
- err := mod(cmd.Use, args)
- if err != nil {
- fmt.Println(err)
- }
- },
- }
-
- subcmd := &cobra.Command{
- Use: CMD_ALL,
- Run: func(cmd *cobra.Command, args []string) {
- err := mod(cmd.Use, args)
- if err != nil {
- fmt.Println(err)
- }
- },
- }
- policyDelCmd.AddCommand(subcmd)
- return policyDelCmd
-}
-
func NewPolicyCmd() *cobra.Command {
policyCmd := &cobra.Command{
Use: CMD_POLICY,
@@ -1262,21 +889,6 @@ func NewPolicyCmd() *cobra.Command {
}
for _, v := range []string{CMD_PREFIX, CMD_NEIGHBOR, CMD_ASPATH, CMD_COMMUNITY, CMD_EXTCOMMUNITY, CMD_ROUTEPOLICY} {
- var mod func(string, []string) error
- switch v {
- case CMD_PREFIX:
- mod = modPolicyPrefix
- case CMD_NEIGHBOR:
- mod = modPolicyNeighbor
- case CMD_ASPATH:
- mod = modPolicyAsPath
- case CMD_COMMUNITY:
- mod = modPolicyCommunity
- case CMD_EXTCOMMUNITY:
- mod = modPolicyExtCommunity
- case CMD_ROUTEPOLICY:
- mod = modPolicyRoutePolicy
- }
cmd := &cobra.Command{
Use: v,
Run: func(cmd *cobra.Command, args []string) {
@@ -1285,10 +897,17 @@ func NewPolicyCmd() *cobra.Command {
}
},
}
- policyAddCmd := NewPolicyAddCmd(v, mod)
- cmd.AddCommand(policyAddCmd)
- policyDelCmd := NewPolicyDelCmd(mod)
- cmd.AddCommand(policyDelCmd)
+ for _, w := range []string{CMD_ADD, CMD_DEL, CMD_SET} {
+ subcmd := &cobra.Command{
+ Use: w,
+ Run: func(c *cobra.Command, args []string) {
+ if err := mod(cmd.Use, c.Use, args); err != nil {
+ fmt.Println(err)
+ }
+ },
+ }
+ cmd.AddCommand(subcmd)
+ }
policyCmd.AddCommand(cmd)
}
return policyCmd
diff --git a/server/server.go b/server/server.go
index 8867186c..18c2693e 100644
--- a/server/server.go
+++ b/server/server.go
@@ -1638,10 +1638,9 @@ 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,
- }
+ err := server.handleGrpcModDefinedSet(grpcReq)
+ grpcReq.ResponseCh <- &GrpcResponse{
+ ResponseErr: err,
}
close(grpcReq.ResponseCh)
case REQ_POLICY_ROUTEPOLICY, REQ_POLICY_ROUTEPOLICIES:
@@ -1698,6 +1697,7 @@ func (server *BgpServer) handleGrpcGetDefinedSet(grpcReq *GrpcRequest) error {
if !ok {
return fmt.Errorf("invalid defined-set type: %d", typ)
}
+ found := false
for _, s := range set {
if name != "" && name != s.Name() {
continue
@@ -1705,10 +1705,14 @@ func (server *BgpServer) handleGrpcGetDefinedSet(grpcReq *GrpcRequest) error {
grpcReq.ResponseCh <- &GrpcResponse{
Data: s.ToApiStruct(),
}
+ found = true
if name != "" {
break
}
}
+ if !found {
+ return fmt.Errorf("not found %s", name)
+ }
return nil
}
diff --git a/table/policy.go b/table/policy.go
index 5fd406f4..97277f6f 100644
--- a/table/policy.go
+++ b/table/policy.go
@@ -469,23 +469,43 @@ func (s *regExpSet) Type() DefinedType {
}
func (lhs *regExpSet) Append(arg DefinedSet) error {
- rhs, ok := arg.(*regExpSet)
- if !ok {
- return fmt.Errorf("type cast failed")
+ if lhs.Type() != arg.Type() {
+ return fmt.Errorf("can't append to different type of defined-set")
}
- lhs.list = append(lhs.list, rhs.list...)
+ var list []*regexp.Regexp
+ switch lhs.Type() {
+ case DEFINED_TYPE_AS_PATH:
+ list = arg.(*AsPathSet).list
+ case DEFINED_TYPE_COMMUNITY:
+ list = arg.(*CommunitySet).list
+ case DEFINED_TYPE_EXT_COMMUNITY:
+ list = arg.(*ExtCommunitySet).list
+ default:
+ return fmt.Errorf("invalid defined-set type: %d", lhs.Type())
+ }
+ lhs.list = append(lhs.list, list...)
return nil
}
func (lhs *regExpSet) Remove(arg DefinedSet) error {
- rhs, ok := arg.(*regExpSet)
- if !ok {
- return fmt.Errorf("type cast failed")
+ if lhs.Type() != arg.Type() {
+ return fmt.Errorf("can't append to different type of defined-set")
+ }
+ var list []*regexp.Regexp
+ switch lhs.Type() {
+ case DEFINED_TYPE_AS_PATH:
+ list = arg.(*AsPathSet).list
+ case DEFINED_TYPE_COMMUNITY:
+ list = arg.(*CommunitySet).list
+ case DEFINED_TYPE_EXT_COMMUNITY:
+ list = arg.(*ExtCommunitySet).list
+ default:
+ return fmt.Errorf("invalid defined-set type: %d", lhs.Type())
}
ps := make([]*regexp.Regexp, 0, len(lhs.list))
for _, x := range lhs.list {
found := false
- for _, y := range rhs.list {
+ for _, y := range list {
if x.String() == y.String() {
found = true
break
@@ -584,7 +604,7 @@ func ParseCommunity(arg string) (uint32, error) {
return 0, fmt.Errorf("failed to parse %s as community", arg)
}
-func parseExtCommunity(arg string) (bgp.ExtendedCommunityInterface, error) {
+func ParseExtCommunity(arg string) (bgp.ExtendedCommunityInterface, error) {
var subtype bgp.ExtendedCommunityAttrSubType
elems := strings.SplitN(arg, ":", 2)
if len(elems) < 2 {
@@ -601,7 +621,7 @@ func parseExtCommunity(arg string) (bgp.ExtendedCommunityInterface, error) {
return bgp.ParseExtendedCommunity(subtype, elems[1])
}
-func parseCommunityRegexp(arg string) (*regexp.Regexp, error) {
+func ParseCommunityRegexp(arg string) (*regexp.Regexp, error) {
i, err := strconv.Atoi(arg)
if err == nil {
return regexp.MustCompile(fmt.Sprintf("^%d:%d$", i>>16, i&0x0000ffff)), nil
@@ -621,7 +641,7 @@ func parseCommunityRegexp(arg string) (*regexp.Regexp, error) {
return exp, nil
}
-func parseExtCommunityRegexp(arg string) (bgp.ExtendedCommunityAttrSubType, *regexp.Regexp, error) {
+func ParseExtCommunityRegexp(arg string) (bgp.ExtendedCommunityAttrSubType, *regexp.Regexp, error) {
var subtype bgp.ExtendedCommunityAttrSubType
elems := strings.SplitN(arg, ":", 2)
if len(elems) < 2 {
@@ -635,7 +655,7 @@ func parseExtCommunityRegexp(arg string) (bgp.ExtendedCommunityAttrSubType, *reg
default:
return subtype, nil, fmt.Errorf("unknown ext-community subtype. rt, soo is supported")
}
- exp, err := parseCommunityRegexp(elems[1])
+ exp, err := ParseCommunityRegexp(elems[1])
return subtype, exp, err
}
@@ -660,7 +680,7 @@ func NewCommunitySet(c config.CommunitySet) (*CommunitySet, error) {
}
list := make([]*regexp.Regexp, 0, len(c.CommunityList))
for _, x := range c.CommunityList {
- exp, err := parseCommunityRegexp(x.Community)
+ exp, err := ParseCommunityRegexp(x.Community)
if err != nil {
return nil, err
}
@@ -680,6 +700,28 @@ type ExtCommunitySet struct {
subtypeList []bgp.ExtendedCommunityAttrSubType
}
+func (s *ExtCommunitySet) ToApiStruct() *api.DefinedSet {
+ list := make([]string, 0, len(s.list))
+ f := func(idx int, arg string) string {
+ switch s.subtypeList[idx] {
+ case bgp.EC_SUBTYPE_ROUTE_TARGET:
+ return fmt.Sprintf("rt:%s", arg)
+ case bgp.EC_SUBTYPE_ROUTE_ORIGIN:
+ return fmt.Sprintf("soo:%s", arg)
+ default:
+ return fmt.Sprintf("%d:%s", s.subtypeList[idx])
+ }
+ }
+ for idx, exp := range s.list {
+ list = append(list, f(idx, exp.String()))
+ }
+ return &api.DefinedSet{
+ Type: int32(s.typ),
+ Name: s.name,
+ List: list,
+ }
+}
+
func NewExtCommunitySetFromApiStruct(a *api.DefinedSet) (*ExtCommunitySet, error) {
c := config.ExtCommunitySet{
ExtCommunitySetName: a.Name,
@@ -702,7 +744,7 @@ func NewExtCommunitySet(c config.ExtCommunitySet) (*ExtCommunitySet, error) {
list := make([]*regexp.Regexp, 0, len(c.ExtCommunityList))
subtypeList := make([]bgp.ExtendedCommunityAttrSubType, 0, len(c.ExtCommunityList))
for _, x := range c.ExtCommunityList {
- subtype, exp, err := parseExtCommunityRegexp(x.ExtCommunity)
+ subtype, exp, err := ParseExtCommunityRegexp(x.ExtCommunity)
if err != nil {
return nil, err
}
@@ -1386,7 +1428,7 @@ func NewCommunityActionFromApiStruct(a *api.CommunityAction) (*CommunityAction,
}
for _, x := range a.Communities {
if op == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE {
- exp, err := parseCommunityRegexp(x)
+ exp, err := ParseCommunityRegexp(x)
if err != nil {
return nil, err
}
@@ -1423,7 +1465,7 @@ func NewCommunityAction(c config.SetCommunity) (*CommunityAction, error) {
}
for _, x := range c.SetCommunityMethod.Communities {
if a == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE {
- exp, err := parseCommunityRegexp(x)
+ exp, err := ParseCommunityRegexp(x)
if err != nil {
return nil, err
}
@@ -1498,14 +1540,14 @@ func NewExtCommunityActionFromApiStruct(a *api.CommunityAction) (*ExtCommunityAc
}
for _, x := range a.Communities {
if op == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE {
- subtype, exp, err := parseExtCommunityRegexp(x)
+ subtype, exp, err := ParseExtCommunityRegexp(x)
if err != nil {
return nil, err
}
removeList = append(removeList, exp)
subtypeList = append(subtypeList, subtype)
} else {
- comm, err := parseExtCommunity(x)
+ comm, err := ParseExtCommunity(x)
if err != nil {
return nil, err
}
@@ -1540,14 +1582,14 @@ func NewExtCommunityAction(c config.SetExtCommunity) (*ExtCommunityAction, error
}
for _, x := range c.SetExtCommunityMethod.Communities {
if a == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE {
- subtype, exp, err := parseExtCommunityRegexp(x)
+ subtype, exp, err := ParseExtCommunityRegexp(x)
if err != nil {
return nil, err
}
removeList = append(removeList, exp)
subtypeList = append(subtypeList, subtype)
} else {
- comm, err := parseExtCommunity(x)
+ comm, err := ParseExtCommunity(x)
if err != nil {
return nil, err
}