diff options
author | Naoto Hanaue <hanaue.naoto@po.ntts.co.jp> | 2015-05-27 14:48:02 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-05-28 20:28:28 +0900 |
commit | 7ea3a18ef5abffc3c1bb01366b0f7e274a42dcff (patch) | |
tree | 726f5b2a0c8dc6be6e03e01e875db68b86db7f35 | |
parent | 95e538791934a1a6226f4e6bdcc09453a77903a6 (diff) |
cli: change structure of the source file
split gobgp/main.go to main.go,global.go,neighbor.go,policy.go and common.go.
-rw-r--r-- | gobgp/common.go | 366 | ||||
-rw-r--r-- | gobgp/global.go | 280 | ||||
-rw-r--r-- | gobgp/main.go | 2294 | ||||
-rw-r--r-- | gobgp/neighbor.go | 793 | ||||
-rw-r--r-- | gobgp/policy.go | 957 |
5 files changed, 2397 insertions, 2293 deletions
diff --git a/gobgp/common.go b/gobgp/common.go new file mode 100644 index 00000000..5281b5ca --- /dev/null +++ b/gobgp/common.go @@ -0,0 +1,366 @@ +// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "bytes" + "fmt" + "github.com/osrg/gobgp/api" + "google.golang.org/grpc" + "net" + "os" + "sort" + "time" +) + +const ( + CMD_GLOBAL = "global" + CMD_NEIGHBOR = "neighbor" + CMD_POLICY = "policy" + CMD_RIB = "rib" + CMD_ADD = "add" + CMD_DEL = "del" + CMD_ALL = "all" + CMD_LOCAL = "local" + CMD_ADJ_IN = "adj-in" + CMD_ADJ_OUT = "adj-out" + CMD_RESET = "reset" + CMD_SOFT_RESET = "softreset" + CMD_SOFT_RESET_IN = "softresetin" + CMD_SOFT_RESET_OUT = "softresetout" + CMD_SHUTDOWN = "shutdown" + CMD_ENABLE = "enable" + CMD_DISABLE = "disable" + CMD_PREFIX = "prefix" + CMD_ROUTEPOLICY = "routepolicy" + CMD_CONDITIONS = "conditions" + CMD_ACTIONS = "actions" + CMD_IMPORT = "import" + CMD_EXPORT = "export" +) + +var subOpts struct { + AddressFamily string `short:"a" long:"address-family" description:"specifying an address family"` +} + +var neighborsOpts struct { + Transport string `short:"t" long:"transport" description:"specifying a transport protocol"` +} + +var conditionOpts struct { + Prefix string `long:"prefix" description:"specifying a prefix set name of policy"` + Neighbor string `long:"neighbor" description:"specifying a neighbor set name of policy"` + AsPathLength string `long:"aspath-len" description:"specifying an as path length of policy (<operator>,<numeric>)"` + Option string `long:"option" description:"specifying an option of policy (any | all | invert)"` +} + +var actionOpts struct { + RouteAction string `long:"route-action" description:"specifying a route action of policy (accept | reject)"` +} + +func formatTimedelta(d int64) string { + u := uint64(d) + neg := d < 0 + if neg { + u = -u + } + secs := u % 60 + u /= 60 + mins := u % 60 + u /= 60 + hours := u % 24 + days := u / 24 + + if days == 0 { + return fmt.Sprintf("%02d:%02d:%02d", hours, mins, secs) + } else { + return fmt.Sprintf("%dd ", days) + fmt.Sprintf("%02d:%02d:%02d", hours, mins, secs) + } +} + +func cidr2prefix(cidr string) string { + _, n, err := net.ParseCIDR(cidr) + if err != nil { + return cidr + } + var buffer bytes.Buffer + for i := 0; i < len(n.IP); i++ { + buffer.WriteString(fmt.Sprintf("%08b", n.IP[i])) + } + ones, _ := n.Mask.Size() + return buffer.String()[:ones] +} + +type paths []*api.Path + +func (p paths) Len() int { + return len(p) +} + +func (p paths) Swap(i, j int) { + p[i], p[j] = p[j], p[i] +} + +func (p paths) Less(i, j int) bool { + if p[i].Nlri.Prefix == p[j].Nlri.Prefix { + if p[i].Best { + return true + } + } + strings := sort.StringSlice{cidr2prefix(p[i].Nlri.Prefix), + cidr2prefix(p[j].Nlri.Prefix)} + return strings.Less(0, 1) +} + +type peers []*api.Peer + +func (p peers) Len() int { + return len(p) +} + +func (p peers) Swap(i, j int) { + p[i], p[j] = p[j], p[i] +} + +func (p peers) Less(i, j int) bool { + p1 := net.ParseIP(p[i].Conf.RemoteIp) + p2 := net.ParseIP(p[j].Conf.RemoteIp) + p1Isv4 := p1.To4() != nil + p2Isv4 := p2.To4() != nil + if p1Isv4 != p2Isv4 { + if p1Isv4 { + return true + } + return false + } + addrlen := 128 + if p1Isv4 { + addrlen = 32 + } + strings := sort.StringSlice{cidr2prefix(fmt.Sprintf("%s/%d", p1.String(), addrlen)), + cidr2prefix(fmt.Sprintf("%s/%d", p2.String(), addrlen))} + return strings.Less(0, 1) +} + +type capabilities []*api.Capability + +func (c capabilities) Len() int { + return len(c) +} + +func (c capabilities) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +func (c capabilities) Less(i, j int) bool { + return c[i].Code < c[j].Code +} + +type prefixes []*api.PrefixSet + +func (p prefixes) Len() int { + return len(p) +} + +func (p prefixes) Swap(i, j int) { + p[i], p[j] = p[j], p[i] +} + +func (p prefixes) Less(i, j int) bool { + return p[i].PrefixSetName < p[j].PrefixSetName +} + +type neighbors []*api.NeighborSet + +func (n neighbors) Len() int { + return len(n) +} + +func (n neighbors) Swap(i, j int) { + n[i], n[j] = n[j], n[i] +} + +func (n neighbors) Less(i, j int) bool { + return n[i].NeighborSetName < n[j].NeighborSetName +} + +type policyDefinitions []*api.PolicyDefinition + +func (p policyDefinitions) Len() int { + return len(p) +} + +func (p policyDefinitions) Swap(i, j int) { + p[i], p[j] = p[j], p[i] +} + +func (p policyDefinitions) Less(i, j int) bool { + return p[i].PolicyDefinitionName < p[j].PolicyDefinitionName +} + +var client api.GrpcClient + +func connGrpc() *grpc.ClientConn { + timeout := grpc.WithTimeout(time.Second) + + // determine IP address version + host := net.ParseIP(globalOpts.Host) + target := fmt.Sprintf("%s:%d", globalOpts.Host, globalOpts.Port) + if host.To4() == nil { + target = fmt.Sprintf("[%s]:%d", globalOpts.Host, globalOpts.Port) + } + + conn, err := grpc.Dial(target, timeout) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return conn +} + +func requestGrpc(cmd string, eArgs []string, request interface{}) error { + conn := connGrpc() + defer conn.Close() + client = api.NewGrpcClient(conn) + + switch cmd { + case CMD_GLOBAL + "_" + CMD_RIB: + return showGlobalRib() + case CMD_GLOBAL + "_" + CMD_RIB + "_" + CMD_ADD: + return modPath(CMD_ADD, eArgs) + case CMD_GLOBAL + "_" + CMD_RIB + "_" + CMD_DEL: + return modPath(CMD_DEL, eArgs) + case CMD_NEIGHBOR: + if len(eArgs) == 0 { + return showNeighbors() + } else { + return showNeighbor(eArgs) + } + case CMD_NEIGHBOR + "_" + CMD_LOCAL: + return showNeighborRib(api.Resource_LOCAL, request.(*NeighborRibCommand)) + case CMD_NEIGHBOR + "_" + CMD_ADJ_IN: + return showNeighborRib(api.Resource_ADJ_IN, request.(*NeighborRibCommand)) + case CMD_NEIGHBOR + "_" + CMD_ADJ_OUT: + return showNeighborRib(api.Resource_ADJ_OUT, request.(*NeighborRibCommand)) + case CMD_NEIGHBOR + "_" + CMD_RESET: + return resetNeighbor(request.(*NeighborResetCommand)) + case CMD_NEIGHBOR + "_" + CMD_SOFT_RESET: + return resetNeighbor(request.(*NeighborResetCommand)) + case CMD_NEIGHBOR + "_" + CMD_SOFT_RESET_IN: + return resetNeighbor(request.(*NeighborResetCommand)) + case CMD_NEIGHBOR + "_" + CMD_SOFT_RESET_OUT: + return resetNeighbor(request.(*NeighborResetCommand)) + case CMD_NEIGHBOR + "_" + CMD_SHUTDOWN: + return stateChangeNeighbor(request.(*NeighborChangeStateCommand)) + case CMD_NEIGHBOR + "_" + CMD_ENABLE: + return stateChangeNeighbor(request.(*NeighborChangeStateCommand)) + case CMD_NEIGHBOR + "_" + CMD_DISABLE: + return stateChangeNeighbor(request.(*NeighborChangeStateCommand)) + case CMD_NEIGHBOR + "_" + CMD_POLICY: + return showNeighborPolicy(request.(*NeighborPolicyCommand)) + case CMD_NEIGHBOR + "_" + CMD_POLICY + "_" + CMD_ADD: + return modNeighborPolicy(eArgs, request.(*NeighborPolicyChangeCommand)) + case CMD_NEIGHBOR + "_" + CMD_POLICY + "_" + CMD_DEL: + return modNeighborPolicy(eArgs, request.(*NeighborPolicyChangeCommand)) + case CMD_POLICY + "_" + CMD_PREFIX: + if len(eArgs) == 0 { + return showPolicyPrefixes() + } else { + return showPolicyPrefix(eArgs) + } + case CMD_POLICY + "_" + CMD_PREFIX + "_" + CMD_ADD: + return modPolicyPrefix(CMD_ADD, eArgs) + case CMD_POLICY + "_" + CMD_PREFIX + "_" + CMD_DEL: + return modPolicyPrefix(CMD_DEL, eArgs) + case CMD_POLICY + "_" + CMD_NEIGHBOR: + if len(eArgs) == 0 { + return showPolicyNeighbors() + } else { + return showPolicyNeighbor(eArgs) + } + case CMD_POLICY + "_" + CMD_NEIGHBOR + "_" + CMD_ADD: + return modPolicyNeighbor(CMD_ADD, eArgs) + case CMD_POLICY + "_" + CMD_NEIGHBOR + "_" + CMD_DEL: + return modPolicyNeighbor(CMD_DEL, eArgs) + case CMD_POLICY + "_" + CMD_ROUTEPOLICY: + if len(eArgs) == 0 { + return showPolicyRoutePolicies() + } else { + return showPolicyRoutePolicy(eArgs) + } + case CMD_POLICY + "_" + CMD_ROUTEPOLICY + "_" + CMD_ADD + "_" + CMD_CONDITIONS: + return modPolicyRoutePolicy(CMD_ADD, CMD_CONDITIONS, eArgs, request) + case CMD_POLICY + "_" + CMD_ROUTEPOLICY + "_" + CMD_ADD + "_" + CMD_ACTIONS: + return modPolicyRoutePolicy(CMD_ADD, CMD_ACTIONS, eArgs, request) + case CMD_POLICY + "_" + CMD_ROUTEPOLICY + "_" + CMD_DEL: + return modPolicyRoutePolicy(CMD_DEL, "", eArgs, nil) + } + return nil +} + +func extractArgs(head string) []string { + eArgs := make([]string, 0) + existHead := false + existRear := false + if head == "" { + existHead = true + } + for _, arg := range os.Args { + if existHead { + eArgs = append(eArgs, arg) + for _, cmd := range cmds { + if arg == cmd { + existRear = true + break + } + } + if existRear { + break + } + } else { + if arg == head { + existHead = true + } + } + } + return eArgs +} + +func checkAddressFamily(ip net.IP) (*api.AddressFamily, error) { + var rf *api.AddressFamily + var e error + switch subOpts.AddressFamily { + case "ipv4", "v4", "4": + rf = api.AF_IPV4_UC + case "ipv6", "v6", "6": + rf = api.AF_IPV6_UC + case "evpn": + rf = api.AF_EVPN + case "encap": + rf = api.AF_ENCAP + case "rtc": + rf = api.AF_RTC + case "": + if len(ip) == 0 || ip.To4() != nil { + rf = api.AF_IPV4_UC + } else { + rf = api.AF_IPV6_UC + } + default: + e = fmt.Errorf("unsupported address family: %s", subOpts.AddressFamily) + } + return rf, e +} diff --git a/gobgp/global.go b/gobgp/global.go new file mode 100644 index 00000000..d39785bf --- /dev/null +++ b/gobgp/global.go @@ -0,0 +1,280 @@ +// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "encoding/json" + "fmt" + "github.com/jessevdk/go-flags" + "github.com/osrg/gobgp/api" + "golang.org/x/net/context" + "io" + "net" + "os" + "sort" + "strconv" +) + +type GlobalCommand struct{} + +func (x *GlobalCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_GLOBAL) + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "global" + parser.AddCommand(CMD_RIB, "subcommand for rib of global", "", &GlobalRibCommand{}) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + return nil +} + +type GlobalRibCommand struct{} + +func showGlobalRib() error { + rt, err := checkAddressFamily(net.IP{}) + if err != nil { + return err + } + arg := &api.Arguments{ + Resource: api.Resource_GLOBAL, + Af: rt, + } + + stream, e := client.GetRib(context.Background(), arg) + if e != nil { + return e + } + ds := []*api.Destination{} + for { + d, e := stream.Recv() + if e == io.EOF { + break + } else if e != nil { + return e + } + ds = append(ds, d) + } + + if globalOpts.Json { + j, _ := json.Marshal(ds) + fmt.Println(string(j)) + return nil + } + + ps := paths{} + for _, d := range ds { + for idx, p := range d.Paths { + if idx == int(d.BestPathIdx) { + p.Best = true + } + ps = append(ps, p) + } + } + + sort.Sort(ps) + + showRoute(ps, true, true) + return nil +} +func (x *GlobalRibCommand) Execute(args []string) error { + + eArgs := extractArgs(CMD_RIB) + parser := flags.NewParser(&subOpts, flags.Default) + if len(eArgs) == 0 || (len(eArgs) < 3 && eArgs[0] == "-a") { + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + if err := requestGrpc(CMD_GLOBAL+"_"+CMD_RIB, eArgs, nil); err != nil { + return err + } + } else { + parser.Usage = "global rib [OPTIONS]\n gobgp global rib" + parser.AddCommand(CMD_ADD, "subcommand to add route to global rib", "", &GlobalRibAddCommand{}) + parser.AddCommand(CMD_DEL, "subcommand to delete route from global rib", "", &GlobalRibDelCommand{}) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + } + return nil +} + +type GlobalRibAddCommand struct{} + +func modPath(modtype string, eArgs []string) error { + rf, err := checkAddressFamily(net.IP{}) + if err != nil { + return err + } + + path := &api.Path{} + var prefix, macAddr, ipAddr string + switch rf { + case api.AF_IPV4_UC, api.AF_IPV6_UC: + if len(eArgs) == 1 || len(eArgs) == 3 { + prefix = eArgs[0] + } else { + return fmt.Errorf("usage: global rib %s <prefix> -a { ipv4 | ipv6 }", modtype) + } + path.Nlri = &api.Nlri{ + Af: rf, + Prefix: prefix, + } + case api.AF_EVPN: + if len(eArgs) == 4 { + macAddr = eArgs[0] + ipAddr = eArgs[1] + } else { + return fmt.Errorf("usage: global rib %s <mac address> <ip address> -a evpn", modtype) + } + path.Nlri = &api.Nlri{ + Af: rf, + EvpnNlri: &api.EVPNNlri{ + Type: api.EVPN_TYPE_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, + MacIpAdv: &api.EvpnMacIpAdvertisement{ + MacAddr: macAddr, + IpAddr: ipAddr, + }, + }, + } + case api.AF_ENCAP: + if len(eArgs) < 3 { + return fmt.Errorf("usage: global rib %s <end point ip address> [<vni>] -a encap", modtype) + } + prefix = eArgs[0] + + path.Nlri = &api.Nlri{ + Af: rf, + Prefix: prefix, + } + + if len(eArgs) > 3 { + vni, err := strconv.Atoi(eArgs[1]) + if err != nil { + return fmt.Errorf("invalid vni: %s", eArgs[1]) + } + subTlv := &api.TunnelEncapSubTLV{ + Type: api.ENCAP_SUBTLV_TYPE_COLOR, + Color: uint32(vni), + } + tlv := &api.TunnelEncapTLV{ + Type: api.TUNNEL_TYPE_VXLAN, + SubTlv: []*api.TunnelEncapSubTLV{subTlv}, + } + attr := &api.PathAttr{ + Type: api.BGP_ATTR_TYPE_TUNNEL_ENCAP, + TunnelEncap: []*api.TunnelEncapTLV{tlv}, + } + + path.Attrs = append(path.Attrs, attr) + } + case api.AF_RTC: + if !(len(eArgs) == 3 && eArgs[0] == "default") && len(eArgs) < 4 { + return fmt.Errorf("usage: global rib add <asn> <local admin> -a rtc") + } + var asn, admin int + + if eArgs[0] != "default" { + asn, err = strconv.Atoi(eArgs[0]) + if err != nil { + return fmt.Errorf("invalid asn: %s", eArgs[0]) + } + admin, err = strconv.Atoi(eArgs[1]) + if err != nil { + return fmt.Errorf("invalid local admin: %s", eArgs[1]) + } + } + path.Nlri = &api.Nlri{ + Af: rf, + RtNlri: &api.RTNlri{ + Target: &api.ExtendedCommunity{ + Type: api.EXTENDED_COMMUNITIE_TYPE_TWO_OCTET_AS_SPECIFIC, + Subtype: api.EXTENDED_COMMUNITIE_SUBTYPE_ROUTE_TARGET, + Asn: uint32(asn), + LocalAdmin: uint32(admin), + }, + }, + } + } + switch modtype { + case CMD_ADD: + path.IsWithdraw = false + case CMD_DEL: + path.IsWithdraw = true + } + + arg := &api.ModPathArguments{ + Resource: api.Resource_GLOBAL, + Path: path, + } + stream, err := client.ModPath(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 *GlobalRibAddCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ADD) + parser := flags.NewParser(&subOpts, flags.Default) + parser.Usage = "global rib add <prefix> -a { ipv4 | ipv6 }\n" + + " -> if -a option is ipv4 or ipv6\n" + + " gobgp global rib add <mac address> <ip address> -a evpn\n" + + " -> if -a option is evpn" + parser.ParseArgs(eArgs) + if len(eArgs) == 1 { + if eArgs[0] == "-h" || eArgs[0] == "--help" { + return nil + } + } + if err := requestGrpc(CMD_GLOBAL+"_"+CMD_RIB+"_"+CMD_ADD, eArgs, nil); err != nil { + return err + } + return nil +} + +type GlobalRibDelCommand struct{} + +func (x *GlobalRibDelCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_DEL) + parser := flags.NewParser(&subOpts, flags.Default) + parser.Usage = "global rib del <prefix> -a { ipv4 | ipv6 }\n" + + " -> if -a option is ipv4 or ipv6\n" + + " gobgp global rib del <mac address> <ip address> -a evpn\n" + + " -> if -a option is evpn" + parser.ParseArgs(eArgs) + if len(eArgs) == 1 { + if eArgs[0] == "-h" || eArgs[0] == "--help" { + return nil + } + } + if err := requestGrpc(CMD_GLOBAL+"_"+CMD_RIB+"_"+CMD_DEL, eArgs, nil); err != nil { + return err + } + return nil +} diff --git a/gobgp/main.go b/gobgp/main.go index 96e47a72..d44be981 100644 --- a/gobgp/main.go +++ b/gobgp/main.go @@ -16,2285 +16,10 @@ package main import ( - "bytes" - "encoding/json" - "fmt" "github.com/jessevdk/go-flags" - "github.com/osrg/gobgp/api" - "github.com/osrg/gobgp/policy" - "golang.org/x/net/context" - "google.golang.org/grpc" - "io" - "net" "os" - "sort" - "strconv" - "strings" - "time" ) -const ( - CMD_GLOBAL = "global" - CMD_NEIGHBOR = "neighbor" - CMD_POLICY = "policy" - CMD_RIB = "rib" - CMD_ADD = "add" - CMD_DEL = "del" - CMD_ALL = "all" - CMD_LOCAL = "local" - CMD_ADJ_IN = "adj-in" - CMD_ADJ_OUT = "adj-out" - CMD_RESET = "reset" - CMD_SOFT_RESET = "softreset" - CMD_SOFT_RESET_IN = "softresetin" - CMD_SOFT_RESET_OUT = "softresetout" - CMD_SHUTDOWN = "shutdown" - CMD_ENABLE = "enable" - CMD_DISABLE = "disable" - CMD_PREFIX = "prefix" - CMD_ROUTEPOLICY = "routepolicy" - CMD_CONDITIONS = "conditions" - CMD_ACTIONS = "actions" - CMD_IMPORT = "import" - CMD_EXPORT = "export" -) - -func formatTimedelta(d int64) string { - u := uint64(d) - neg := d < 0 - if neg { - u = -u - } - secs := u % 60 - u /= 60 - mins := u % 60 - u /= 60 - hours := u % 24 - days := u / 24 - - if days == 0 { - return fmt.Sprintf("%02d:%02d:%02d", hours, mins, secs) - } else { - return fmt.Sprintf("%dd ", days) + fmt.Sprintf("%02d:%02d:%02d", hours, mins, secs) - } -} - -func cidr2prefix(cidr string) string { - _, n, err := net.ParseCIDR(cidr) - if err != nil { - return cidr - } - var buffer bytes.Buffer - for i := 0; i < len(n.IP); i++ { - buffer.WriteString(fmt.Sprintf("%08b", n.IP[i])) - } - ones, _ := n.Mask.Size() - return buffer.String()[:ones] -} - -type paths []*api.Path - -func (p paths) Len() int { - return len(p) -} - -func (p paths) Swap(i, j int) { - p[i], p[j] = p[j], p[i] -} - -func (p paths) Less(i, j int) bool { - if p[i].Nlri.Prefix == p[j].Nlri.Prefix { - if p[i].Best { - return true - } - } - strings := sort.StringSlice{cidr2prefix(p[i].Nlri.Prefix), - cidr2prefix(p[j].Nlri.Prefix)} - return strings.Less(0, 1) -} - -type peers []*api.Peer - -func (p peers) Len() int { - return len(p) -} - -func (p peers) Swap(i, j int) { - p[i], p[j] = p[j], p[i] -} - -func (p peers) Less(i, j int) bool { - p1 := net.ParseIP(p[i].Conf.RemoteIp) - p2 := net.ParseIP(p[j].Conf.RemoteIp) - p1Isv4 := p1.To4() != nil - p2Isv4 := p2.To4() != nil - if p1Isv4 != p2Isv4 { - if p1Isv4 { - return true - } - return false - } - addrlen := 128 - if p1Isv4 { - addrlen = 32 - } - strings := sort.StringSlice{cidr2prefix(fmt.Sprintf("%s/%d", p1.String(), addrlen)), - cidr2prefix(fmt.Sprintf("%s/%d", p2.String(), addrlen))} - return strings.Less(0, 1) -} - -type prefixes []*api.PrefixSet - -func (p prefixes) Len() int { - return len(p) -} - -func (p prefixes) Swap(i, j int) { - p[i], p[j] = p[j], p[i] -} - -func (p prefixes) Less(i, j int) bool { - return p[i].PrefixSetName < p[j].PrefixSetName -} - -type neighbors []*api.NeighborSet - -func (n neighbors) Len() int { - return len(n) -} - -func (n neighbors) Swap(i, j int) { - n[i], n[j] = n[j], n[i] -} - -func (n neighbors) Less(i, j int) bool { - return n[i].NeighborSetName < n[j].NeighborSetName -} - -type policyDefinitions []*api.PolicyDefinition - -func (p policyDefinitions) Len() int { - return len(p) -} - -func (p policyDefinitions) Swap(i, j int) { - p[i], p[j] = p[j], p[i] -} - -func (p policyDefinitions) Less(i, j int) bool { - return p[i].PolicyDefinitionName < p[j].PolicyDefinitionName -} - -func connGrpc() *grpc.ClientConn { - timeout := grpc.WithTimeout(time.Second) - - // determine IP address version - host := net.ParseIP(globalOpts.Host) - target := fmt.Sprintf("%s:%d", globalOpts.Host, globalOpts.Port) - if host.To4() == nil { - target = fmt.Sprintf("[%s]:%d", globalOpts.Host, globalOpts.Port) - } - - conn, err := grpc.Dial(target, timeout) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return conn -} - -func requestGrpc(cmd string, eArgs []string, request interface{}) error { - conn := connGrpc() - defer conn.Close() - client = api.NewGrpcClient(conn) - - switch cmd { - case CMD_GLOBAL + "_" + CMD_RIB: - return showGlobalRib() - case CMD_GLOBAL + "_" + CMD_RIB + "_" + CMD_ADD: - return modPath(CMD_ADD, eArgs) - case CMD_GLOBAL + "_" + CMD_RIB + "_" + CMD_DEL: - return modPath(CMD_DEL, eArgs) - case CMD_NEIGHBOR: - if len(eArgs) == 0 { - return showNeighbors() - } else { - return showNeighbor(eArgs) - } - case CMD_NEIGHBOR + "_" + CMD_LOCAL: - return showNeighborRib(api.Resource_LOCAL, request.(*NeighborRibCommand)) - case CMD_NEIGHBOR + "_" + CMD_ADJ_IN: - return showNeighborRib(api.Resource_ADJ_IN, request.(*NeighborRibCommand)) - case CMD_NEIGHBOR + "_" + CMD_ADJ_OUT: - return showNeighborRib(api.Resource_ADJ_OUT, request.(*NeighborRibCommand)) - case CMD_NEIGHBOR + "_" + CMD_RESET: - return resetNeighbor(request.(*NeighborResetCommand)) - case CMD_NEIGHBOR + "_" + CMD_SOFT_RESET: - return resetNeighbor(request.(*NeighborResetCommand)) - case CMD_NEIGHBOR + "_" + CMD_SOFT_RESET_IN: - return resetNeighbor(request.(*NeighborResetCommand)) - case CMD_NEIGHBOR + "_" + CMD_SOFT_RESET_OUT: - return resetNeighbor(request.(*NeighborResetCommand)) - case CMD_NEIGHBOR + "_" + CMD_SHUTDOWN: - return stateChangeNeighbor(request.(*NeighborChangeStateCommand)) - case CMD_NEIGHBOR + "_" + CMD_ENABLE: - return stateChangeNeighbor(request.(*NeighborChangeStateCommand)) - case CMD_NEIGHBOR + "_" + CMD_DISABLE: - return stateChangeNeighbor(request.(*NeighborChangeStateCommand)) - case CMD_NEIGHBOR + "_" + CMD_POLICY: - return showNeighborPolicy(request.(*NeighborPolicyCommand)) - case CMD_NEIGHBOR + "_" + CMD_POLICY + "_" + CMD_ADD: - return modNeighborPolicy(eArgs, request.(*NeighborPolicyChangeCommand)) - case CMD_NEIGHBOR + "_" + CMD_POLICY + "_" + CMD_DEL: - return modNeighborPolicy(eArgs, request.(*NeighborPolicyChangeCommand)) - case CMD_POLICY + "_" + CMD_PREFIX: - if len(eArgs) == 0 { - return showPolicyPrefixes() - } else { - return showPolicyPrefix(eArgs) - } - case CMD_POLICY + "_" + CMD_PREFIX + "_" + CMD_ADD: - return modPolicyPrefix(CMD_ADD, eArgs) - case CMD_POLICY + "_" + CMD_PREFIX + "_" + CMD_DEL: - return modPolicyPrefix(CMD_DEL, eArgs) - case CMD_POLICY + "_" + CMD_NEIGHBOR: - if len(eArgs) == 0 { - return showPolicyNeighbors() - } else { - return showPolicyNeighbor(eArgs) - } - case CMD_POLICY + "_" + CMD_NEIGHBOR + "_" + CMD_ADD: - return modPolicyNeighbor(CMD_ADD, eArgs) - case CMD_POLICY + "_" + CMD_NEIGHBOR + "_" + CMD_DEL: - return modPolicyNeighbor(CMD_DEL, eArgs) - case CMD_POLICY + "_" + CMD_ROUTEPOLICY: - if len(eArgs) == 0 { - return showPolicyRoutePolicies() - } else { - return showPolicyRoutePolicy(eArgs) - } - case CMD_POLICY + "_" + CMD_ROUTEPOLICY + "_" + CMD_ADD + "_" + CMD_CONDITIONS: - return modPolicyRoutePolicy(CMD_ADD, CMD_CONDITIONS, eArgs, request) - case CMD_POLICY + "_" + CMD_ROUTEPOLICY + "_" + CMD_ADD + "_" + CMD_ACTIONS: - return modPolicyRoutePolicy(CMD_ADD, CMD_ACTIONS, eArgs, request) - case CMD_POLICY + "_" + CMD_ROUTEPOLICY + "_" + CMD_DEL: - return modPolicyRoutePolicy(CMD_DEL, "", eArgs, nil) - } - return nil -} - -var cmds []string - -func extractArgs(head string) []string { - eArgs := make([]string, 0) - existHead := false - existRear := false - if head == "" { - existHead = true - } - for _, arg := range os.Args { - if existHead { - eArgs = append(eArgs, arg) - for _, cmd := range cmds { - if arg == cmd { - existRear = true - break - } - } - if existRear { - break - } - } else { - if arg == head { - existHead = true - } - } - } - return eArgs -} - -func checkAddressFamily(ip net.IP) (*api.AddressFamily, error) { - var rf *api.AddressFamily - var e error - switch subOpts.AddressFamily { - case "ipv4", "v4", "4": - rf = api.AF_IPV4_UC - case "ipv6", "v6", "6": - rf = api.AF_IPV6_UC - case "evpn": - rf = api.AF_EVPN - case "encap": - rf = api.AF_ENCAP - case "rtc": - rf = api.AF_RTC - case "": - if len(ip) == 0 || ip.To4() != nil { - rf = api.AF_IPV4_UC - } else { - rf = api.AF_IPV6_UC - } - default: - e = fmt.Errorf("unsupported address family: %s", subOpts.AddressFamily) - } - return rf, e -} - -var client api.GrpcClient - -type GlobalCommand struct{} - -func (x *GlobalCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_GLOBAL) - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "global" - parser.AddCommand(CMD_RIB, "subcommand for rib of global", "", &GlobalRibCommand{}) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - return nil -} - -type GlobalRibCommand struct{} - -func showGlobalRib() error { - rt, err := checkAddressFamily(net.IP{}) - if err != nil { - return err - } - arg := &api.Arguments{ - Resource: api.Resource_GLOBAL, - Af: rt, - } - - stream, e := client.GetRib(context.Background(), arg) - if e != nil { - return e - } - ds := []*api.Destination{} - for { - d, e := stream.Recv() - if e == io.EOF { - break - } else if e != nil { - return e - } - ds = append(ds, d) - } - - if globalOpts.Json { - j, _ := json.Marshal(ds) - fmt.Println(string(j)) - return nil - } - - ps := paths{} - for _, d := range ds { - for idx, p := range d.Paths { - if idx == int(d.BestPathIdx) { - p.Best = true - } - ps = append(ps, p) - } - } - - sort.Sort(ps) - - showRoute(ps, true, true) - return nil -} -func (x *GlobalRibCommand) Execute(args []string) error { - - eArgs := extractArgs(CMD_RIB) - parser := flags.NewParser(&subOpts, flags.Default) - if len(eArgs) == 0 || (len(eArgs) < 3 && eArgs[0] == "-a") { - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - if err := requestGrpc(CMD_GLOBAL+"_"+CMD_RIB, eArgs, nil); err != nil { - return err - } - } else { - parser.Usage = "global rib [OPTIONS]\n gobgp global rib" - parser.AddCommand(CMD_ADD, "subcommand to add route to global rib", "", &GlobalRibAddCommand{}) - parser.AddCommand(CMD_DEL, "subcommand to delete route from global rib", "", &GlobalRibDelCommand{}) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - } - return nil -} - -type GlobalRibAddCommand struct{} - -func modPath(modtype string, eArgs []string) error { - rf, err := checkAddressFamily(net.IP{}) - if err != nil { - return err - } - - path := &api.Path{} - var prefix, macAddr, ipAddr string - switch rf { - case api.AF_IPV4_UC, api.AF_IPV6_UC: - if len(eArgs) == 1 || len(eArgs) == 3 { - prefix = eArgs[0] - } else { - return fmt.Errorf("usage: global rib %s <prefix> -a { ipv4 | ipv6 }", modtype) - } - path.Nlri = &api.Nlri{ - Af: rf, - Prefix: prefix, - } - case api.AF_EVPN: - if len(eArgs) == 4 { - macAddr = eArgs[0] - ipAddr = eArgs[1] - } else { - return fmt.Errorf("usage: global rib %s <mac address> <ip address> -a evpn", modtype) - } - path.Nlri = &api.Nlri{ - Af: rf, - EvpnNlri: &api.EVPNNlri{ - Type: api.EVPN_TYPE_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, - MacIpAdv: &api.EvpnMacIpAdvertisement{ - MacAddr: macAddr, - IpAddr: ipAddr, - }, - }, - } - case api.AF_ENCAP: - if len(eArgs) < 3 { - return fmt.Errorf("usage: global rib %s <end point ip address> [<vni>] -a encap", modtype) - } - prefix = eArgs[0] - - path.Nlri = &api.Nlri{ - Af: rf, - Prefix: prefix, - } - - if len(eArgs) > 3 { - vni, err := strconv.Atoi(eArgs[1]) - if err != nil { - return fmt.Errorf("invalid vni: %s", eArgs[1]) - } - subTlv := &api.TunnelEncapSubTLV{ - Type: api.ENCAP_SUBTLV_TYPE_COLOR, - Color: uint32(vni), - } - tlv := &api.TunnelEncapTLV{ - Type: api.TUNNEL_TYPE_VXLAN, - SubTlv: []*api.TunnelEncapSubTLV{subTlv}, - } - attr := &api.PathAttr{ - Type: api.BGP_ATTR_TYPE_TUNNEL_ENCAP, - TunnelEncap: []*api.TunnelEncapTLV{tlv}, - } - - path.Attrs = append(path.Attrs, attr) - } - case api.AF_RTC: - if !(len(eArgs) == 3 && eArgs[0] == "default") && len(eArgs) < 4 { - return fmt.Errorf("usage: global rib add <asn> <local admin> -a rtc") - } - var asn, admin int - - if eArgs[0] != "default" { - asn, err = strconv.Atoi(eArgs[0]) - if err != nil { - return fmt.Errorf("invalid asn: %s", eArgs[0]) - } - admin, err = strconv.Atoi(eArgs[1]) - if err != nil { - return fmt.Errorf("invalid local admin: %s", eArgs[1]) - } - } - path.Nlri = &api.Nlri{ - Af: rf, - RtNlri: &api.RTNlri{ - Target: &api.ExtendedCommunity{ - Type: api.EXTENDED_COMMUNITIE_TYPE_TWO_OCTET_AS_SPECIFIC, - Subtype: api.EXTENDED_COMMUNITIE_SUBTYPE_ROUTE_TARGET, - Asn: uint32(asn), - LocalAdmin: uint32(admin), - }, - }, - } - } - switch modtype { - case CMD_ADD: - path.IsWithdraw = false - case CMD_DEL: - path.IsWithdraw = true - } - - arg := &api.ModPathArguments{ - Resource: api.Resource_GLOBAL, - Path: path, - } - stream, err := client.ModPath(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 *GlobalRibAddCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_ADD) - parser := flags.NewParser(&subOpts, flags.Default) - parser.Usage = "global rib add <prefix> -a { ipv4 | ipv6 }\n" + - " -> if -a option is ipv4 or ipv6\n" + - " gobgp global rib add <mac address> <ip address> -a evpn\n" + - " -> if -a option is evpn" - parser.ParseArgs(eArgs) - if len(eArgs) == 1 { - if eArgs[0] == "-h" || eArgs[0] == "--help" { - return nil - } - } - if err := requestGrpc(CMD_GLOBAL+"_"+CMD_RIB+"_"+CMD_ADD, eArgs, nil); err != nil { - return err - } - return nil -} - -type GlobalRibDelCommand struct{} - -func (x *GlobalRibDelCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_DEL) - parser := flags.NewParser(&subOpts, flags.Default) - parser.Usage = "global rib del <prefix> -a { ipv4 | ipv6 }\n" + - " -> if -a option is ipv4 or ipv6\n" + - " gobgp global rib del <mac address> <ip address> -a evpn\n" + - " -> if -a option is evpn" - parser.ParseArgs(eArgs) - if len(eArgs) == 1 { - if eArgs[0] == "-h" || eArgs[0] == "--help" { - return nil - } - } - if err := requestGrpc(CMD_GLOBAL+"_"+CMD_RIB+"_"+CMD_DEL, eArgs, nil); err != nil { - return err - } - return nil -} - -type NeighborCommand struct { -} - -func showNeighbors() error { - arg := &api.Arguments{} - stream, e := client.GetNeighbors(context.Background(), arg) - if e != nil { - fmt.Println(e) - return e - } - m := peers{} - for { - p, e := stream.Recv() - if e == io.EOF { - break - } else if e != nil { - return e - } - if neighborsOpts.Transport != "" { - addr := net.ParseIP(p.Conf.RemoteIp) - if addr.To4() != nil { - if neighborsOpts.Transport != "ipv4" { - continue - } - } else { - if neighborsOpts.Transport != "ipv6" { - continue - } - } - } - m = append(m, p) - } - - if globalOpts.Json { - j, _ := json.Marshal(m) - fmt.Println(string(j)) - return nil - } - - if globalOpts.Quiet { - for _, p := range m { - fmt.Println(p.Conf.RemoteIp) - } - return nil - } - maxaddrlen := 0 - maxaslen := 0 - maxtimelen := len("Up/Down") - timedelta := []string{} - - sort.Sort(m) - - for _, p := range m { - if len(p.Conf.RemoteIp) > maxaddrlen { - maxaddrlen = len(p.Conf.RemoteIp) - } - - if len(fmt.Sprint(p.Conf.RemoteAs)) > maxaslen { - maxaslen = len(fmt.Sprint(p.Conf.RemoteAs)) - } - var t string - if p.Info.Uptime == 0 { - t = "never" - } else if p.Info.BgpState == "BGP_FSM_ESTABLISHED" { - t = formatTimedelta(p.Info.Uptime) - } else { - t = formatTimedelta(p.Info.Downtime) - } - if len(t) > maxtimelen { - maxtimelen = len(t) - } - timedelta = append(timedelta, t) - } - var format string - format = "%-" + fmt.Sprint(maxaddrlen) + "s" + " %" + fmt.Sprint(maxaslen) + "s" + " %" + fmt.Sprint(maxtimelen) + "s" - format += " %-11s |%11s %8s %8s\n" - fmt.Printf(format, "Peer", "AS", "Up/Down", "State", "#Advertised", "Received", "Accepted") - format_fsm := func(admin, fsm string) string { - if admin == "ADMIN_STATE_DOWN" { - return "Idle(Admin)" - } - - if fsm == "BGP_FSM_IDLE" { - return "Idle" - } else if fsm == "BGP_FSM_CONNECT" { - return "Connect" - } else if fsm == "BGP_FSM_ACTIVE" { - return "Active" - } else if fsm == "BGP_FSM_OPENSENT" { - return "Sent" - } else if fsm == "BGP_FSM_OPENCONFIRM" { - return "Confirm" - } else { - return "Establ" - } - } - - for i, p := range m { - fmt.Printf(format, p.Conf.RemoteIp, fmt.Sprint(p.Conf.RemoteAs), timedelta[i], format_fsm(p.Info.AdminState, p.Info.BgpState), fmt.Sprint(p.Info.Advertized), fmt.Sprint(p.Info.Received), fmt.Sprint(p.Info.Accepted)) - } - - return nil -} - -type capabilities []*api.Capability - -func (c capabilities) Len() int { - return len(c) -} - -func (c capabilities) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} - -func (c capabilities) Less(i, j int) bool { - return c[i].Code < c[j].Code -} - -func showNeighbor(args []string) error { - id := &api.Arguments{ - RouterId: args[0], - } - p, e := client.GetNeighbor(context.Background(), id) - if e != nil { - fmt.Println(e) - return e - } - - if globalOpts.Json { - j, _ := json.Marshal(p) - fmt.Println(string(j)) - return nil - } - - fmt.Printf("BGP neighbor is %s, remote AS %d\n", p.Conf.RemoteIp, p.Conf.RemoteAs) - fmt.Printf(" BGP version 4, remote router ID %s\n", p.Conf.Id) - fmt.Printf(" BGP state = %s, up for %s\n", p.Info.BgpState, formatTimedelta(p.Info.Uptime)) - fmt.Printf(" BGP OutQ = %d, Flops = %d\n", p.Info.OutQ, p.Info.Flops) - fmt.Printf(" Hold time is %d, keepalive interval is %d seconds\n", p.Info.NegotiatedHoldtime, p.Info.KeepaliveInterval) - fmt.Printf(" Configured hold time is %d, keepalive interval is %d seconds\n", p.Conf.Holdtime, p.Conf.KeepaliveInterval) - - fmt.Printf(" Neighbor capabilities:\n") - caps := capabilities{} - lookup := func(val *api.Capability, l capabilities) *api.Capability { - for _, v := range l { - if v.Code == val.Code { - if v.Code == api.BGP_CAPABILITY_MULTIPROTOCOL { - if v.MultiProtocol.Equal(val.MultiProtocol) { - return v - } - continue - } - return v - } - } - return nil - } - caps = append(caps, p.Conf.LocalCap...) - for _, v := range p.Conf.RemoteCap { - if lookup(v, caps) == nil { - caps = append(caps, v) - } - } - - sort.Sort(caps) - - for _, c := range caps { - support := "" - if m := lookup(c, p.Conf.LocalCap); m != nil { - support += "advertised" - } - if lookup(c, p.Conf.RemoteCap) != nil { - if len(support) != 0 { - support += " and " - } - support += "received" - } - - if c.Code != api.BGP_CAPABILITY_MULTIPROTOCOL { - fmt.Printf(" %s: %s\n", c.Code, support) - } else { - fmt.Printf(" %s(%s,%s): %s\n", c.Code, c.MultiProtocol.Afi, c.MultiProtocol.Safi, support) - } - } - fmt.Print(" Message statistics:\n") - fmt.Print(" Sent Rcvd\n") - fmt.Printf(" Opens: %10d %10d\n", p.Info.OpenMessageOut, p.Info.OpenMessageIn) - fmt.Printf(" Notifications: %10d %10d\n", p.Info.NotificationOut, p.Info.NotificationIn) - fmt.Printf(" Updates: %10d %10d\n", p.Info.UpdateMessageOut, p.Info.UpdateMessageIn) - fmt.Printf(" Keepalives: %10d %10d\n", p.Info.KeepAliveMessageOut, p.Info.KeepAliveMessageIn) - fmt.Printf(" Route Refesh: %10d %10d\n", p.Info.RefreshMessageOut, p.Info.RefreshMessageIn) - fmt.Printf(" Discarded: %10d %10d\n", p.Info.DiscardedOut, p.Info.DiscardedIn) - fmt.Printf(" Total: %10d %10d\n", p.Info.TotalMessageOut, p.Info.TotalMessageIn) - - return nil -} - -func (x *NeighborCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_NEIGHBOR) - - if len(eArgs) == 0 || (strings.HasPrefix(eArgs[0], "-") && !(eArgs[0] == "-h" || eArgs[0] == "--help")) { - parser := flags.NewParser(&neighborsOpts, flags.Default) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - if err := requestGrpc(CMD_NEIGHBOR, []string{}, nil); err != nil { - return err - } - } else if len(eArgs) == 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help") { - if err := requestGrpc(CMD_NEIGHBOR, eArgs, nil); err != nil { - return err - } - } else { - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "neighbor [ <neighbor address> ]\n gobgp neighbor" - parser.AddCommand(CMD_LOCAL, "subcommand for local-rib of neighbor", "", NewNeighborRibCommand(eArgs[0], api.Resource_LOCAL, CMD_LOCAL)) - parser.AddCommand(CMD_ADJ_IN, "subcommand for adj-rib-in of neighbor", "", NewNeighborRibCommand(eArgs[0], api.Resource_ADJ_IN, CMD_ADJ_IN)) - parser.AddCommand(CMD_ADJ_OUT, "subcommand for adj-rib-out of neighbor", "", NewNeighborRibCommand(eArgs[0], api.Resource_ADJ_OUT, CMD_ADJ_OUT)) - parser.AddCommand(CMD_RESET, "subcommand for reset the rib of neighbor", "", NewNeighborResetCommand(eArgs[0], CMD_RESET)) - parser.AddCommand(CMD_SOFT_RESET, "subcommand for softreset the rib of neighbor", "", NewNeighborResetCommand(eArgs[0], CMD_SOFT_RESET)) - parser.AddCommand(CMD_SOFT_RESET_IN, "subcommand for softreset the adj-rib-in of neighbor", "", NewNeighborResetCommand(eArgs[0], CMD_SOFT_RESET_IN)) - parser.AddCommand(CMD_SOFT_RESET_OUT, "subcommand for softreset the adj-rib-out of neighbor", "", NewNeighborResetCommand(eArgs[0], CMD_SOFT_RESET_OUT)) - parser.AddCommand(CMD_SHUTDOWN, "subcommand for shutdown to neighbor", "", NewNeighborChangeStateCommand(eArgs[0], CMD_SHUTDOWN)) - parser.AddCommand(CMD_ENABLE, "subcommand for enable to neighbor", "", NewNeighborChangeStateCommand(eArgs[0], CMD_ENABLE)) - parser.AddCommand(CMD_DISABLE, "subcommand for disable to neighbor", "", NewNeighborChangeStateCommand(eArgs[0], CMD_DISABLE)) - parser.AddCommand(CMD_POLICY, "subcommand for policy of neighbor", "", NewNeighborPolicyCommand(eArgs[0])) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - } - return nil -} - -type NeighborRibCommand struct { - remoteIP net.IP - resource api.Resource - command string -} - -func NewNeighborRibCommand(addr string, resource api.Resource, cmd string) *NeighborRibCommand { - return &NeighborRibCommand{ - remoteIP: net.ParseIP(addr), - resource: resource, - command: cmd, - } -} - -func showRoute(pathList []*api.Path, showAge bool, showBest bool) { - - var pathStrs [][]interface{} - maxPrefixLen := len("Network") - maxNexthopLen := len("Next Hop") - maxAsPathLen := len("AS_PATH") - - for _, p := range pathList { - aspath := func(attrs []*api.PathAttr) string { - s := bytes.NewBuffer(make([]byte, 0, 64)) - s.WriteString("[") - for _, a := range attrs { - if a.Type == api.BGP_ATTR_TYPE_AS_PATH { - var ss []string - for _, as := range a.AsPath { - ss = append(ss, fmt.Sprintf("%d", as)) - } - s.WriteString(strings.Join(ss, " ")) - } - } - s.WriteString("]") - return s.String() - } - formatAttrs := func(attrs []*api.PathAttr) string { - s := []string{} - for _, a := range attrs { - switch a.Type { - case api.BGP_ATTR_TYPE_ORIGIN: - s = append(s, fmt.Sprintf("{Origin: %s}", a.Origin)) - case api.BGP_ATTR_TYPE_MULTI_EXIT_DISC: - s = append(s, fmt.Sprintf("{Med: %d}", a.Metric)) - case api.BGP_ATTR_TYPE_LOCAL_PREF: - s = append(s, fmt.Sprintf("{LocalPref: %v}", a.Pref)) - case api.BGP_ATTR_TYPE_ATOMIC_AGGREGATE: - s = append(s, "AtomicAggregate") - case api.BGP_ATTR_TYPE_AGGREGATOR: - s = append(s, fmt.Sprintf("{Aggregate: {AS: %d, Address: %s}", a.GetAggregator().As, a.GetAggregator().Address)) - case api.BGP_ATTR_TYPE_COMMUNITIES: - l := []string{} - known := map[uint32]string{ - 0xffff0000: "planned-shut", - 0xffff0001: "accept-own", - 0xffff0002: "ROUTE_FILTER_TRANSLATED_v4", - 0xffff0003: "ROUTE_FILTER_v4", - 0xffff0004: "ROUTE_FILTER_TRANSLATED_v6", - 0xffff0005: "ROUTE_FILTER_v6", - 0xffff0006: "LLGR_STALE", - 0xffff0007: "NO_LLGR", - 0xFFFFFF01: "NO_EXPORT", - 0xFFFFFF02: "NO_ADVERTISE", - 0xFFFFFF03: "NO_EXPORT_SUBCONFED", - 0xFFFFFF04: "NOPEER"} - - for _, v := range a.Communites { - k, found := known[v] - if found { - l = append(l, fmt.Sprint(k)) - } else { - l = append(l, fmt.Sprintf("%d:%d", (0xffff0000&v)>>16, 0xffff&v)) - } - } - s = append(s, fmt.Sprintf("{Community: %v}", l)) - case api.BGP_ATTR_TYPE_ORIGINATOR_ID: - s = append(s, fmt.Sprintf("{Originator: %v}", a.Originator)) - case api.BGP_ATTR_TYPE_CLUSTER_LIST: - s = append(s, fmt.Sprintf("{Cluster: %v}", a.Cluster)) - case api.BGP_ATTR_TYPE_TUNNEL_ENCAP: - s1 := bytes.NewBuffer(make([]byte, 0, 64)) - s1.WriteString("{Encap: ") - var s2 []string - for _, tlv := range a.TunnelEncap { - s3 := bytes.NewBuffer(make([]byte, 0, 64)) - s3.WriteString(fmt.Sprintf("< %s | ", tlv.Type)) - var s4 []string - for _, subTlv := range tlv.SubTlv { - if subTlv.Type == api.ENCAP_SUBTLV_TYPE_COLOR { - s4 = append(s4, fmt.Sprintf("color: %d", subTlv.Color)) - } - } - s3.WriteString(strings.Join(s4, ",")) - s3.WriteString(" >") - s2 = append(s2, s3.String()) - } - s1.WriteString(strings.Join(s2, "|")) - s1.WriteString("}") - s = append(s, s1.String()) - case api.BGP_ATTR_TYPE_AS4_PATH, api.BGP_ATTR_TYPE_MP_REACH_NLRI, api.BGP_ATTR_TYPE_MP_UNREACH_NLRI, api.BGP_ATTR_TYPE_NEXT_HOP, api.BGP_ATTR_TYPE_AS_PATH: - default: - s = append(s, fmt.Sprintf("{%v: %v}", a.Type, a.Value)) - } - } - return fmt.Sprint(s) - } - best := "" - if showBest { - if p.Best { - best = "*>" - } else { - best = "* " - } - } - - if maxPrefixLen < len(p.Nlri.Prefix) { - maxPrefixLen = len(p.Nlri.Prefix) - } - - if maxNexthopLen < len(p.Nexthop) { - maxNexthopLen = len(p.Nexthop) - } - - if maxAsPathLen < len(aspath(p.Attrs)) { - maxAsPathLen = len(aspath(p.Attrs)) - } - - if showAge { - pathStrs = append(pathStrs, []interface{}{best, p.Nlri.Prefix, p.Nexthop, aspath(p.Attrs), formatTimedelta(p.Age), formatAttrs(p.Attrs)}) - } else { - pathStrs = append(pathStrs, []interface{}{best, p.Nlri.Prefix, p.Nexthop, aspath(p.Attrs), formatAttrs(p.Attrs)}) - } - } - - var format string - if showAge { - format = fmt.Sprintf("%%-2s %%-%ds %%-%ds %%-%ds %%-10s %%-s\n", maxPrefixLen, maxNexthopLen, maxAsPathLen) - fmt.Printf(format, "", "Network", "Next Hop", "AS_PATH", "Age", "Attrs") - } else { - format = fmt.Sprintf("%%-2s %%-%ds %%-%ds %%-%ds %%-s\n", maxPrefixLen, maxNexthopLen, maxAsPathLen) - fmt.Printf(format, "", "Network", "Next Hop", "AS_PATH", "Attrs") - } - - for _, pathStr := range pathStrs { - fmt.Printf(format, pathStr...) - } -} - -func showNeighborRib(resource api.Resource, request *NeighborRibCommand) error { - remoteIP := request.remoteIP - rt, err := checkAddressFamily(remoteIP) - if err != nil { - return err - } - arg := &api.Arguments{ - Resource: resource, - Af: rt, - RouterId: remoteIP.String(), - } - - ps := paths{} - showBest := false - showAge := true - switch resource { - case api.Resource_LOCAL: - showBest = true - stream, e := client.GetRib(context.Background(), arg) - if e != nil { - return e - } - - ds := []*api.Destination{} - for { - d, e := stream.Recv() - if e == io.EOF { - break - } else if e != nil { - return e - } - ds = append(ds, d) - } - - if globalOpts.Json { - j, _ := json.Marshal(ds) - fmt.Println(string(j)) - return nil - } - - for _, d := range ds { - for idx, p := range d.Paths { - if idx == int(d.BestPathIdx) { - p.Best = true - } - ps = append(ps, p) - } - } - case api.Resource_ADJ_OUT: - showAge = false - fallthrough - case api.Resource_ADJ_IN: - stream, e := client.GetAdjRib(context.Background(), arg) - if e != nil { - return e - } - for { - p, e := stream.Recv() - if e == io.EOF { - break - } else if e != nil { - return e - } - ps = append(ps, p) - } - if globalOpts.Json { - j, _ := json.Marshal(ps) - fmt.Println(string(j)) - return nil - } - } - - sort.Sort(ps) - showRoute(ps, showAge, showBest) - return nil -} - -func (x *NeighborRibCommand) Execute(args []string) error { - eArgs := extractArgs(x.command) - parser := flags.NewParser(&subOpts, flags.Default) - parser.Usage = fmt.Sprintf("neighbor <neighbor address> %s [OPTIONS]", x.command) - parser.ParseArgs(eArgs) - if len(eArgs) != 0 && (eArgs[0] == "-h" || eArgs[0] == "--help") { - return nil - } - if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x); err != nil { - return err - } - return nil -} - -type NeighborResetCommand struct { - remoteIP net.IP - command string -} - -func NewNeighborResetCommand(addr string, cmd string) *NeighborResetCommand { - return &NeighborResetCommand{ - remoteIP: net.ParseIP(addr), - command: cmd, - } -} - -func resetNeighbor(request *NeighborResetCommand) error { - remoteIP := request.remoteIP - cmd := request.command - rt, err := checkAddressFamily(remoteIP) - if err != nil { - return err - } - arg := &api.Arguments{ - RouterId: remoteIP.String(), - Af: rt, - } - switch cmd { - case CMD_RESET: - client.Reset(context.Background(), arg) - case CMD_SOFT_RESET: - client.SoftReset(context.Background(), arg) - case CMD_SOFT_RESET_IN: - client.SoftResetIn(context.Background(), arg) - case CMD_SOFT_RESET_OUT: - client.SoftResetOut(context.Background(), arg) - } - return nil -} - -func (x *NeighborResetCommand) Execute(args []string) error { - eArgs := extractArgs(x.command) - parser := flags.NewParser(&subOpts, flags.Default) - parser.Usage = fmt.Sprintf("neighbor <neighbor address> %s [OPTIONS]", x.command) - parser.ParseArgs(eArgs) - if len(eArgs) != 0 && (eArgs[0] == "-h" || eArgs[0] == "--help") { - return nil - } - if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x); err != nil { - return err - } - return nil -} - -type NeighborChangeStateCommand struct { - remoteIP net.IP - command string -} - -func NewNeighborChangeStateCommand(addr string, cmd string) *NeighborChangeStateCommand { - return &NeighborChangeStateCommand{ - remoteIP: net.ParseIP(addr), - command: cmd, - } -} - -func stateChangeNeighbor(request *NeighborChangeStateCommand) error { - remoteIP := request.remoteIP - cmd := request.command - arg := &api.Arguments{ - RouterId: remoteIP.String(), - } - switch cmd { - case CMD_SHUTDOWN: - client.Shutdown(context.Background(), arg) - case CMD_ENABLE: - client.Enable(context.Background(), arg) - case CMD_DISABLE: - client.Disable(context.Background(), arg) - } - return nil -} - -func (x *NeighborChangeStateCommand) Execute(args []string) error { - eArgs := extractArgs(x.command) - if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x); err != nil { - return err - } - return nil -} - -type NeighborPolicyCommand struct { - remoteIP net.IP -} - -func NewNeighborPolicyCommand(addr string) *NeighborPolicyCommand { - return &NeighborPolicyCommand{ - remoteIP: net.ParseIP(addr), - } -} - -func showNeighborPolicy(request *NeighborPolicyCommand) error { - remoteIP := request.remoteIP - rt, err := checkAddressFamily(net.IP{}) - if err != nil { - return err - } - arg := &api.Arguments{ - Af: rt, - RouterId: remoteIP.String(), - } - - ap, e := client.GetNeighborPolicy(context.Background(), arg) - if e != nil { - return e - } - - if globalOpts.Json { - j, _ := json.Marshal(ap) - fmt.Println(string(j)) - return nil - } - - fmt.Printf("DefaultImportPolicy: %s\n", ap.DefaultImportPolicy) - fmt.Printf("DefaultExportPolicy: %s\n", ap.DefaultExportPolicy) - fmt.Printf("ImportPolicies:\n") - - for _, inPolicy := range ap.ImportPolicies { - fmt.Printf(" PolicyName %s:\n", inPolicy.PolicyDefinitionName) - showPolicyStatement(" ", inPolicy) - } - fmt.Printf("ExportPolicies:\n") - for _, outPolicy := range ap.ExportPolicies { - fmt.Printf(" PolicyName %s:\n", outPolicy.PolicyDefinitionName) - showPolicyStatement(" ", outPolicy) - } - return nil -} - -func (x *NeighborPolicyCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_POLICY) - parser := flags.NewParser(nil, flags.Default) - if len(eArgs) == 0 { - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - if err := requestGrpc(CMD_NEIGHBOR+"_"+CMD_POLICY, eArgs, x); err != nil { - return err - } - } else { - parser.Usage = "neighbor <neighbor address> policy \n gobgp neighbor <neighbor address> policy" - parser.AddCommand(CMD_ADD, "subcommand to add routing policy", "", NewNeighborPolicyAddCommand(x.remoteIP)) - parser.AddCommand(CMD_DEL, "subcommand to delete routing policy", "", NewNeighborPolicyDelCommand(x.remoteIP)) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - } - return nil -} - -type NeighborPolicyAddCommand struct { - remoteIP net.IP -} - -func NewNeighborPolicyAddCommand(addr net.IP) *NeighborPolicyAddCommand { - return &NeighborPolicyAddCommand{ - remoteIP: addr, - } -} -func (x *NeighborPolicyAddCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_ADD) - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "neighbor <neighbor address> policy add" - parser.AddCommand(CMD_IMPORT, "subcommand to add import policies to neighbor", "", NewNeighborPolicyChangeCommand(CMD_ADD, CMD_IMPORT, x.remoteIP)) - parser.AddCommand(CMD_EXPORT, "subcommand to add export policies to neighbor", "", NewNeighborPolicyChangeCommand(CMD_ADD, CMD_EXPORT, x.remoteIP)) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - return nil -} - -type NeighborPolicyDelCommand struct { - remoteIP net.IP -} - -func NewNeighborPolicyDelCommand(addr net.IP) *NeighborPolicyDelCommand { - return &NeighborPolicyDelCommand{ - remoteIP: addr, - } -} - -func (x *NeighborPolicyDelCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_DEL) - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "neighbor <neighbor address> policy del" - parser.AddCommand(CMD_IMPORT, "subcommand to delete import policies from neighbor", "", NewNeighborPolicyChangeCommand(CMD_DEL, CMD_IMPORT, x.remoteIP)) - parser.AddCommand(CMD_EXPORT, "subcommand to delete export policies from neighbor", "", NewNeighborPolicyChangeCommand(CMD_DEL, CMD_EXPORT, x.remoteIP)) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - return nil -} - -type NeighborPolicyChangeCommand struct { - operation string - policyOperation string - remoteIP net.IP -} - -func NewNeighborPolicyChangeCommand(operation string, pOperation string, addr net.IP) *NeighborPolicyChangeCommand { - return &NeighborPolicyChangeCommand{ - operation: operation, - policyOperation: pOperation, - remoteIP: addr, - } -} - -func parseRouteAction(rType string) (string, error) { - routeActionUpper := strings.ToUpper(rType) - var routeAction string - switch routeActionUpper { - case policy.ROUTE_ACCEPT, policy.ROUTE_REJECT: - routeAction = routeActionUpper - default: - return "", fmt.Errorf("invalid route action: %s\nPlease enter the accept or reject", rType) - } - return routeAction, nil -} - -func parsePolicy(pNames string) []*api.PolicyDefinition { - pList := strings.Split(pNames, ",") - policyList := make([]*api.PolicyDefinition, 0) - for _, p := range pList { - if p != "" { - policy := &api.PolicyDefinition{ - PolicyDefinitionName: p, - } - policyList = append(policyList, policy) - } - } - return policyList -} - -func modNeighborPolicy(eArg []string, request *NeighborPolicyChangeCommand) error { - var operation api.Operation - pol := &api.ApplyPolicy{} - switch request.operation { - case CMD_ADD: - policies := parsePolicy(eArg[0]) - defaultPolicy, err := parseRouteAction(eArg[1]) - if err != nil { - return err - } - switch request.policyOperation { - case CMD_IMPORT: - pol.ImportPolicies = policies - pol.DefaultImportPolicy = defaultPolicy - case CMD_EXPORT: - pol.ExportPolicies = policies - pol.DefaultExportPolicy = defaultPolicy - } - operation = api.Operation_ADD - - case CMD_DEL: - operation = api.Operation_DEL - } - arg := &api.PolicyArguments{ - Resource: api.Resource_POLICY_ROUTEPOLICY, - Operation: operation, - RouterId: request.remoteIP.String(), - Name: request.policyOperation, - ApplyPolicy: pol, - } - stream, err := client.ModNeighborPolicy(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 *NeighborPolicyChangeCommand) Execute(args []string) error { - eArgs := extractArgs(x.policyOperation) - if x.operation == CMD_ADD && len(eArgs) != 2 { - return fmt.Errorf("usage: neighbor <neighbor address> policy %s %s <%s policy name> <default %s policy>", - x.operation, x.policyOperation, x.policyOperation, x.policyOperation) - } else if x.operation == CMD_DEL && len(eArgs) != 0 { - return fmt.Errorf("usage: neighbor <neighbor address> policy %s %s", x.operation, x.policyOperation) - } else { - if err := requestGrpc(CMD_NEIGHBOR+"_"+CMD_POLICY+"_"+x.operation, eArgs, x); err != nil { - return err - } - } - return nil -} - -type PolicyCommand struct{} - -func (x *PolicyCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_POLICY) - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "policy" - parser.AddCommand(CMD_PREFIX, "subcommand for prefix of policy", "", &PolicyPrefixCommand{}) - parser.AddCommand(CMD_NEIGHBOR, "subcommand for neighbor of policy", "", &PolicyNeighborCommand{}) - parser.AddCommand(CMD_ROUTEPOLICY, "subcommand for routepolicy of policy", "", &PolicyRoutePolicyCommand{}) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - return nil -} - -type PolicyPrefixCommand struct{} - -func formatPolicyPrefix(prefixSetList []*api.PrefixSet) (string, string) { - maxNameLen := len("Name") - maxPrefixLen := len("Prefix") - maxRangeLen := len("MaskRange") - for _, ps := range prefixSetList { - if len(ps.PrefixSetName) > maxNameLen { - maxNameLen = len(ps.PrefixSetName) - } - for _, p := range ps.PrefixList { - if len(p.Address)+len(fmt.Sprint(p.MaskLength))+1 > maxPrefixLen { - maxPrefixLen = len(p.Address) + len(fmt.Sprint(p.MaskLength)) + 1 - } - if len(p.MaskLengthRange) > maxRangeLen { - maxRangeLen = len(p.MaskLengthRange) - } - } - } - formatPrefixSet := "%-" + fmt.Sprint(maxNameLen) + "s %-" + fmt.Sprint(maxPrefixLen) + "s %-" + fmt.Sprint(maxRangeLen) + "s\n" - formatPrefixListOnly := "%-" + fmt.Sprint(maxPrefixLen) + "s %-" + fmt.Sprint(maxRangeLen) + "s\n" - return formatPrefixSet, formatPrefixListOnly -} - -func showPolicyPrefixes() error { - arg := &api.PolicyArguments{ - Resource: api.Resource_POLICY_PREFIX, - } - stream, e := client.GetPolicyPrefixes(context.Background(), arg) - if e != nil { - fmt.Println(e) - return e - } - m := prefixes{} - for { - p, e := stream.Recv() - if e == io.EOF { - break - } else if e != nil { - return e - } - m = append(m, p) - } - - if globalOpts.Json { - j, _ := json.Marshal(m) - fmt.Println(string(j)) - return nil - } - - if globalOpts.Quiet { - for _, p := range m { - fmt.Println(p.PrefixSetName) - } - return nil - } - sort.Sort(m) - - format, _ := formatPolicyPrefix(m) - fmt.Printf(format, "Name", "Prefix", "MaskRange") - for _, ps := range m { - for i, p := range ps.PrefixList { - prefix := fmt.Sprintf("%s/%d", p.Address, p.MaskLength) - if i == 0 { - fmt.Printf(format, ps.PrefixSetName, prefix, p.MaskLengthRange) - } else { - fmt.Printf(format, "", prefix, p.MaskLengthRange) - } - } - } - return nil -} - -func showPolicyPrefix(args []string) error { - arg := &api.PolicyArguments{ - Resource: api.Resource_POLICY_PREFIX, - Name: args[0], - } - ps, e := client.GetPolicyPrefix(context.Background(), arg) - if e != nil { - return e - } - - if globalOpts.Json { - j, _ := json.Marshal(ps) - fmt.Println(string(j)) - return nil - } - if globalOpts.Quiet { - for _, p := range ps.PrefixList { - fmt.Printf("%s/%d %s\n", p.Address, p.MaskLength, p.MaskLengthRange) - } - return nil - } - format, _ := formatPolicyPrefix([]*api.PrefixSet{ps}) - fmt.Printf(format, "Name", "Prefix", "MaskRange") - for i, p := range ps.PrefixList { - prefix := fmt.Sprintf("%s/%d", p.Address, p.MaskLength) - if i == 0 { - fmt.Printf(format, ps.PrefixSetName, prefix, p.MaskLengthRange) - } else { - fmt.Printf(format, "", prefix, p.MaskLengthRange) - } - } - return nil -} - -func (x *PolicyPrefixCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_PREFIX) - if len(eArgs) == 0 { - if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX, eArgs, nil); err != nil { - return err - } - return nil - } else if len(eArgs) >= 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == CMD_ADD || eArgs[0] == CMD_DEL) { - if len(eArgs) != 1 { - return fmt.Errorf("Argument can not be entered: %s", eArgs[1:]) - } - if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX, eArgs, nil); err != nil { - return err - } - return nil - } - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "policy prefix [<prefix set name>],\n gobgp policy prefix" - parser.AddCommand(CMD_ADD, "subcommand to add prefix condition to policy", "", &PolicyPrefixAddCommand{}) - parser.AddCommand(CMD_DEL, "subcommand to delete prefix condition from policy", "", &PolicyPrefixDelCommand{}) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - return nil -} - -type PolicyPrefixAddCommand struct{} - -func parsePrefixSet(eArgs []string) (*api.PrefixSet, 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]) - } - mask, _ := ipNet.Mask.Size() - prefix := &api.Prefix{ - Address: ipNet.IP.String(), - MaskLength: uint32(mask), - } - - 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 { - 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("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 min >= max { - return nil, fmt.Errorf("invalid mask length range: %s\nlarge value to the right from the left", maskRange) - } - prefix.MaskLengthRange = maskRange - } - prefixList := []*api.Prefix{prefix} - prefixSet := &api.PrefixSet{ - PrefixSetName: eArgs[0], - PrefixList: prefixList, - } - return prefixSet, nil -} - -func modPolicyPrefix(modtype string, eArgs []string) error { - prefixSet := &api.PrefixSet{} - 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 { - operation = api.Operation_DEL_ALL - } else if len(eArgs) == 1 { - prefixSet = &api.PrefixSet{ - PrefixSetName: eArgs[0], - PrefixList: nil, - } - operation = api.Operation_DEL - } else { - if prefixSet, e = parsePrefixSet(eArgs); e != nil { - return e - } - operation = api.Operation_DEL - } - } - - arg := &api.PolicyArguments{ - Resource: api.Resource_POLICY_PREFIX, - Operation: operation, - PrefixSet: prefixSet, - } - stream, err := client.ModPolicyPrefix(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 *PolicyPrefixAddCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_ADD) - if len(eArgs) == 0 || len(eArgs) > 3 { - return fmt.Errorf("usage: policy prefix add <prefix set name> <prefix> [<mask length renge> ]") - } else { - if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX+"_"+CMD_ADD, eArgs, nil); err != nil { - return err - } - } - return nil -} - -type PolicyPrefixDelCommand struct{} - -func (x *PolicyPrefixDelCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_DEL) - if len(eArgs) > 3 { - return fmt.Errorf("usage: policy prefix del <prefix set name> [<prefix> [<mask length range>]] ") - } else if len(eArgs) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "all") { - if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX+"_"+CMD_DEL, eArgs, nil); err != nil { - return err - } - return nil - } - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "policy prefix del <prefix set name> [<prefix> [<mask length range>]],\n gobgp policy prefix del" - parser.AddCommand(CMD_ALL, "subcommand to delete all prefix condition from policy", "", &PolicyPrefixDelAllCommand{}) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - return nil -} - -type PolicyPrefixDelAllCommand struct{} - -func (x *PolicyPrefixDelAllCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_ALL) - if len(eArgs) > 0 { - return fmt.Errorf("Argument can not be entered: %s", eArgs) - } - if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX+"_"+CMD_DEL, eArgs, nil); err != nil { - return err - } - return nil -} - -type PolicyNeighborCommand struct{} - -func formatPolicyNeighbor(neighborSetList []*api.NeighborSet) string { - maxNameLen := len("Name") - maxAddressLen := len("Address") - for _, ns := range neighborSetList { - if len(ns.NeighborSetName) > maxNameLen { - maxNameLen = len(ns.NeighborSetName) - } - for _, n := range ns.NeighborList { - if len(n.Address) > maxAddressLen { - maxAddressLen = len(n.Address) - } - } - } - format := "%-" + fmt.Sprint(maxNameLen) + "s %-" + fmt.Sprint(maxAddressLen) + "s\n" - return format -} - -func showPolicyNeighbors() error { - arg := &api.PolicyArguments{ - Resource: api.Resource_POLICY_NEIGHBOR, - } - stream, e := client.GetPolicyNeighbors(context.Background(), arg) - if e != nil { - fmt.Println(e) - return e - } - m := neighbors{} - for { - n, e := stream.Recv() - if e == io.EOF { - break - } else if e != nil { - return e - } - m = append(m, n) - } - - if globalOpts.Json { - j, _ := json.Marshal(m) - fmt.Println(string(j)) - return nil - } - - if globalOpts.Quiet { - for _, n := range m { - fmt.Println(n.NeighborSetName) - } - return nil - } - sort.Sort(m) - - format := formatPolicyNeighbor(m) - fmt.Printf(format, "Name", "Address") - for _, ns := range m { - for i, n := range ns.NeighborList { - if i == 0 { - fmt.Printf(format, ns.NeighborSetName, n.Address) - } else { - fmt.Printf(format, "", n.Address) - } - } - } - return nil -} - -func showPolicyNeighbor(args []string) error { - arg := &api.PolicyArguments{ - Resource: api.Resource_POLICY_NEIGHBOR, - Name: args[0], - } - ns, e := client.GetPolicyNeighbor(context.Background(), arg) - if e != nil { - return e - } - - if globalOpts.Json { - j, _ := json.Marshal(ns) - fmt.Println(string(j)) - return nil - } - if globalOpts.Quiet { - for _, n := range ns.NeighborList { - fmt.Println(n.Address) - } - return nil - } - format := formatPolicyNeighbor([]*api.NeighborSet{ns}) - fmt.Printf(format, "Name", "Address") - for i, n := range ns.NeighborList { - if i == 0 { - fmt.Printf(format, ns.NeighborSetName, n.Address) - } else { - fmt.Printf(format, "", n.Address) - - } - } - return nil -} - -func (x *PolicyNeighborCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_NEIGHBOR) - if len(eArgs) == 0 { - if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR, eArgs, nil); err != nil { - return err - } - return nil - } else if len(eArgs) >= 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == CMD_ADD || eArgs[0] == CMD_DEL) { - if len(eArgs) != 1 { - return fmt.Errorf("Argument can not be entered: %s", eArgs[1:]) - } - if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR, eArgs, nil); err != nil { - return err - } - return nil - } - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "policy neighbor [<neighbor set name>],\n gobgp policy neighbor" - parser.AddCommand(CMD_ADD, "subcommand to add neighbor condition to policy", "", &PolicyNeighborAddCommand{}) - parser.AddCommand(CMD_DEL, "subcommand to delete neighbor condition from policy", "", &PolicyNeighborDelCommand{}) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - return nil -} - -type PolicyNeighborAddCommand struct{} - -func parseNeighborSet(eArgs []string) (*api.NeighborSet, 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]) - } - } - - neighbor := &api.Neighbor{ - Address: address.String(), - } - neighborList := []*api.Neighbor{neighbor} - neighborSet := &api.NeighborSet{ - NeighborSetName: eArgs[0], - NeighborList: neighborList, - } - return neighborSet, nil -} - -func modPolicyNeighbor(modtype string, eArgs []string) error { - neighborSet := &api.NeighborSet{} - 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 { - operation = api.Operation_DEL_ALL - } else if len(eArgs) == 1 { - neighborSet = &api.NeighborSet{ - NeighborSetName: eArgs[0], - NeighborList: nil, - } - operation = api.Operation_DEL - } else { - if neighborSet, e = parseNeighborSet(eArgs); e != nil { - return e - } - operation = api.Operation_DEL - } - } - - arg := &api.PolicyArguments{ - Resource: api.Resource_POLICY_NEIGHBOR, - Operation: operation, - NeighborSet: neighborSet, - } - 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 *PolicyNeighborAddCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_ADD) - if len(eArgs) == 0 || len(eArgs) > 2 { - return fmt.Errorf("usage: policy neighbor add <neighbor set name> <address>") - } else { - if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR+"_"+CMD_ADD, eArgs, nil); err != nil { - return err - } - } - return nil -} - -type PolicyNeighborDelCommand struct{} - -func (x *PolicyNeighborDelCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_DEL) - if len(eArgs) > 3 { - return fmt.Errorf("usage: policy neighbor del [<neighbor set name> [<address>]]") - } else if len(eArgs) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "all") { - if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR+"_"+CMD_DEL, eArgs, nil); err != nil { - return err - } - return nil - } - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "policy neighbor del [<neighbor set name> [<address>]],\n gobgp policy neighbor del" - parser.AddCommand(CMD_ALL, "subcommand to delete all neighbor condition from policy", "", &PolicyNeighborDelAllCommand{}) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - return nil -} - -type PolicyNeighborDelAllCommand struct{} - -func (x *PolicyNeighborDelAllCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_ALL) - if len(eArgs) > 0 { - return fmt.Errorf("Argument can not be entered: %s", eArgs) - } - if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR+"_"+CMD_DEL, eArgs, nil); err != nil { - return err - } - return nil -} - -type PolicyRoutePolicyCommand struct{} - -func showPolicyStatement(head string, pd *api.PolicyDefinition) { - for _, st := range pd.StatementList { - fmt.Printf("%s StatementName %s:\n", head, st.StatementNeme) - fmt.Printf("%s Conditions:\n", head) - prefixSet := st.Conditions.MatchPrefixSet - fmt.Printf("%s PrefixSet: %s ", head, prefixSet.PrefixSetName) - if len(prefixSet.PrefixList) != 0 { - nameFormat := "%-" + fmt.Sprint(len(prefixSet.PrefixSetName)+2) + "s" - _, format := formatPolicyPrefix([]*api.PrefixSet{st.Conditions.MatchPrefixSet}) - for i, prefix := range prefixSet.PrefixList { - p := fmt.Sprintf("%s/%d", prefix.Address, prefix.MaskLength) - if i != 0 { - fmt.Printf("%s ", head) - fmt.Printf(nameFormat, "") - } - fmt.Printf(format, p, prefix.MaskLengthRange) - } - } else { - fmt.Print("\n") - } - neighborSet := st.Conditions.MatchNeighborSet - fmt.Printf("%s NeighborSet: %s ", head, neighborSet.NeighborSetName) - if len(neighborSet.NeighborList) != 0 { - nameFormat := "%-" + fmt.Sprint(len(neighborSet.NeighborSetName)+2) + "s" - for i, neighbor := range neighborSet.NeighborList { - if i != 0 { - fmt.Printf("%s ", head) - fmt.Printf(nameFormat, "") - } - fmt.Println(neighbor.Address) - } - } else { - fmt.Print("\n") - } - asPathLentgh := st.Conditions.MatchAsPathLength - fmt.Printf("%s AsPathLength: %s %s\n", head, asPathLentgh.Operator, asPathLentgh.Value) - fmt.Printf("%s MatchOption: %s\n", head, st.Conditions.MatchSetOptions) - fmt.Printf("%s Actions:\n", head) - fmt.Printf("%s %s\n", head, st.Actions.RouteAction) - } - -} - -func showPolicyRoutePolicies() error { - arg := &api.PolicyArguments{ - Resource: api.Resource_POLICY_ROUTEPOLICY, - } - stream, e := client.GetPolicyRoutePolicies(context.Background(), arg) - if e != nil { - fmt.Println(e) - return e - } - m := policyDefinitions{} - for { - n, e := stream.Recv() - if e == io.EOF { - break - } else if e != nil { - return e - } - m = append(m, n) - } - - if globalOpts.Json { - j, _ := json.Marshal(m) - fmt.Println(string(j)) - return nil - } - if globalOpts.Quiet { - for _, p := range m { - fmt.Println(p.PolicyDefinitionName) - } - return nil - } - sort.Sort(m) - - for _, pd := range m { - fmt.Printf("PolicyName %s:\n", pd.PolicyDefinitionName) - showPolicyStatement("", pd) - } - return nil -} - -func showPolicyRoutePolicy(args []string) error { - arg := &api.PolicyArguments{ - Resource: api.Resource_POLICY_ROUTEPOLICY, - Name: args[0], - } - pd, e := client.GetPolicyRoutePolicy(context.Background(), arg) - if e != nil { - return e - } - - if globalOpts.Json { - j, _ := json.Marshal(pd) - fmt.Println(string(j)) - return nil - } - - if globalOpts.Quiet { - for _, st := range pd.StatementList { - fmt.Println(st.StatementNeme) - } - return nil - } - - fmt.Printf("PolicyName %s:\n", pd.PolicyDefinitionName) - showPolicyStatement("", pd) - return nil -} - -func (x *PolicyRoutePolicyCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_ROUTEPOLICY) - if len(eArgs) == 0 { - if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY, eArgs, nil); err != nil { - return err - } - return nil - } else if len(eArgs) >= 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == CMD_ADD || eArgs[0] == CMD_DEL) { - if len(eArgs) != 1 { - return fmt.Errorf("Argument can not be entered: %s", eArgs[1:]) - } - if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY, eArgs, nil); err != nil { - return err - } - return nil - } - parser := flags.NewParser(nil, flags.Default) - parser.Usage = "policy routepolicy [<policy name>],\n gobgp policy routepolicy" - parser.AddCommand(CMD_ADD, "subcommand to add routing policy", "", &PolicyRoutePolicyAddCommand{}) - parser.AddCommand(CMD_DEL, "subcommand to delete routing policy", "", &PolicyRoutePolicyDelCommand{}) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - 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) - } - operator := asPathLen[:idx] - value := asPathLen[idx+1:] - if _, err := strconv.ParseUint(value, 10, 32); err != nil { - return nil, fmt.Errorf("invalid as path length: %s\nPlease enter a numeric", value) - } - conditions.MatchAsPathLength = &api.AsPathLength{ - Value: value, - Operator: operator, - } - } - if conditionOpts.Option != "" { - optionUpper := strings.ToUpper(conditionOpts.Option) - var option string - switch optionUpper { - case policy.OPTIONS_ANY, policy.OPTIONS_ALL, policy.OPTIONS_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.RouteAction != "" { - routeAction, e := parseRouteAction(actionOpts.RouteAction) - if e != nil { - return nil, e - } - actions.RouteAction = routeAction - } - return actions, nil -} - -func modPolicyRoutePolicy(modtype string, stmtType string, eArgs []string, request interface{}) error { - var e error - var operation api.Operation - pd := &api.PolicyDefinition{} - switch modtype { - case CMD_ADD: - stmt := &api.Statement{} - switch stmtType { - case CMD_CONDITIONS: - conditions, err := parseConditions() - if err != nil { - return err - } - stmt.StatementNeme = request.(*PolicyRoutePolicyAddConditionsCommand).statementName - stmt.Conditions = conditions - pd.PolicyDefinitionName = request.(*PolicyRoutePolicyAddConditionsCommand).policyName - case CMD_ACTIONS: - actions, err := parseActions() - if err != nil { - return err - } - stmt.StatementNeme = request.(*PolicyRoutePolicyAddActionsCommand).statementName - stmt.Actions = actions - pd.PolicyDefinitionName = request.(*PolicyRoutePolicyAddActionsCommand).policyName - } - 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) - parser := flags.NewParser(nil, flags.Default) - if len(eArgs) < 2 { - return fmt.Errorf("usage: policy routepolicy add <routing policy name> <statement name>") - } - parser.Usage = "policy routepolicy add <routing policy name> <statement 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])) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - 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]" - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - if len(eArgs) == 0 { - return fmt.Errorf("usage: 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]" - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - if len(eArgs) == 0 { - return fmt.Errorf("usage: 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) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "all") { - if len(eArgs) > 2 { - return fmt.Errorf("Argument can not be entered: %s", eArgs[2:]) - } - 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>],\n gobgp policy routepolicy del" - parser.AddCommand(CMD_ALL, "subcommand to delete all routing policy", "", &PolicyRoutePolicyDelAllCommand{}) - if _, err := parser.ParseArgs(eArgs); err != nil { - os.Exit(1) - } - return nil -} - -type PolicyRoutePolicyDelAllCommand struct{} - -func (x *PolicyRoutePolicyDelAllCommand) Execute(args []string) error { - eArgs := extractArgs(CMD_ALL) - if len(eArgs) > 0 { - return fmt.Errorf("Argument can not be entered: %s", eArgs) - } - if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY+"_"+CMD_DEL, eArgs, nil); err != nil { - return err - } - return nil -} - var globalOpts struct { Host string `short:"u" long:"url" description:"specifying an url" default:"127.0.0.1"` Port int `short:"p" long:"port" description:"specifying a port" default:"8080"` @@ -2303,24 +28,7 @@ var globalOpts struct { Json bool `short:"j" long:"json" description:"use json format to output format"` } -var subOpts struct { - AddressFamily string `short:"a" long:"address-family" description:"specifying an address family"` -} - -var neighborsOpts struct { - Transport string `short:"t" long:"transport" description:"specifying a transport protocol"` -} - -var conditionOpts struct { - Prefix string `long:"prefix" description:"specifying a prefix set name of policy"` - Neighbor string `long:"neighbor" description:"specifying a neighbor set name of policy"` - AsPathLength string `long:"aspath-len" description:"specifying an as path length of policy (<operator>,<numeric>)"` - Option string `long:"option" description:"specifying an option of policy (any | all | invert)"` -} - -var actionOpts struct { - RouteAction string `long:"route-action" description:"specifying a route action of policy (accept | reject)"` -} +var cmds []string func main() { cmds = []string{CMD_GLOBAL, CMD_NEIGHBOR, CMD_POLICY, CMD_RIB, CMD_ADD, CMD_DEL, CMD_ALL, CMD_LOCAL, CMD_ADJ_IN, diff --git a/gobgp/neighbor.go b/gobgp/neighbor.go new file mode 100644 index 00000000..71044386 --- /dev/null +++ b/gobgp/neighbor.go @@ -0,0 +1,793 @@ +// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "github.com/jessevdk/go-flags" + "github.com/osrg/gobgp/api" + "github.com/osrg/gobgp/policy" + "golang.org/x/net/context" + "io" + "net" + "os" + "sort" + "strings" +) + +type NeighborCommand struct { +} + +func showNeighbors() error { + arg := &api.Arguments{} + stream, e := client.GetNeighbors(context.Background(), arg) + if e != nil { + fmt.Println(e) + return e + } + m := peers{} + for { + p, e := stream.Recv() + if e == io.EOF { + break + } else if e != nil { + return e + } + if neighborsOpts.Transport != "" { + addr := net.ParseIP(p.Conf.RemoteIp) + if addr.To4() != nil { + if neighborsOpts.Transport != "ipv4" { + continue + } + } else { + if neighborsOpts.Transport != "ipv6" { + continue + } + } + } + m = append(m, p) + } + + if globalOpts.Json { + j, _ := json.Marshal(m) + fmt.Println(string(j)) + return nil + } + + if globalOpts.Quiet { + for _, p := range m { + fmt.Println(p.Conf.RemoteIp) + } + return nil + } + maxaddrlen := 0 + maxaslen := 0 + maxtimelen := len("Up/Down") + timedelta := []string{} + + sort.Sort(m) + + for _, p := range m { + if len(p.Conf.RemoteIp) > maxaddrlen { + maxaddrlen = len(p.Conf.RemoteIp) + } + + if len(fmt.Sprint(p.Conf.RemoteAs)) > maxaslen { + maxaslen = len(fmt.Sprint(p.Conf.RemoteAs)) + } + var t string + if p.Info.Uptime == 0 { + t = "never" + } else if p.Info.BgpState == "BGP_FSM_ESTABLISHED" { + t = formatTimedelta(p.Info.Uptime) + } else { + t = formatTimedelta(p.Info.Downtime) + } + if len(t) > maxtimelen { + maxtimelen = len(t) + } + timedelta = append(timedelta, t) + } + var format string + format = "%-" + fmt.Sprint(maxaddrlen) + "s" + " %" + fmt.Sprint(maxaslen) + "s" + " %" + fmt.Sprint(maxtimelen) + "s" + format += " %-11s |%11s %8s %8s\n" + fmt.Printf(format, "Peer", "AS", "Up/Down", "State", "#Advertised", "Received", "Accepted") + format_fsm := func(admin, fsm string) string { + if admin == "ADMIN_STATE_DOWN" { + return "Idle(Admin)" + } + + if fsm == "BGP_FSM_IDLE" { + return "Idle" + } else if fsm == "BGP_FSM_CONNECT" { + return "Connect" + } else if fsm == "BGP_FSM_ACTIVE" { + return "Active" + } else if fsm == "BGP_FSM_OPENSENT" { + return "Sent" + } else if fsm == "BGP_FSM_OPENCONFIRM" { + return "Confirm" + } else { + return "Establ" + } + } + + for i, p := range m { + fmt.Printf(format, p.Conf.RemoteIp, fmt.Sprint(p.Conf.RemoteAs), timedelta[i], format_fsm(p.Info.AdminState, p.Info.BgpState), fmt.Sprint(p.Info.Advertized), fmt.Sprint(p.Info.Received), fmt.Sprint(p.Info.Accepted)) + } + + return nil +} + +func showNeighbor(args []string) error { + id := &api.Arguments{ + RouterId: args[0], + } + p, e := client.GetNeighbor(context.Background(), id) + if e != nil { + return e + } + + if globalOpts.Json { + j, _ := json.Marshal(p) + fmt.Println(string(j)) + return nil + } + + fmt.Printf("BGP neighbor is %s, remote AS %d\n", p.Conf.RemoteIp, p.Conf.RemoteAs) + fmt.Printf(" BGP version 4, remote router ID %s\n", p.Conf.Id) + fmt.Printf(" BGP state = %s, up for %s\n", p.Info.BgpState, formatTimedelta(p.Info.Uptime)) + fmt.Printf(" BGP OutQ = %d, Flops = %d\n", p.Info.OutQ, p.Info.Flops) + fmt.Printf(" Hold time is %d, keepalive interval is %d seconds\n", p.Info.NegotiatedHoldtime, p.Info.KeepaliveInterval) + fmt.Printf(" Configured hold time is %d, keepalive interval is %d seconds\n", p.Conf.Holdtime, p.Conf.KeepaliveInterval) + + fmt.Printf(" Neighbor capabilities:\n") + caps := capabilities{} + lookup := func(val *api.Capability, l capabilities) *api.Capability { + for _, v := range l { + if v.Code == val.Code { + if v.Code == api.BGP_CAPABILITY_MULTIPROTOCOL { + if v.MultiProtocol.Equal(val.MultiProtocol) { + return v + } + continue + } + return v + } + } + return nil + } + caps = append(caps, p.Conf.LocalCap...) + for _, v := range p.Conf.RemoteCap { + if lookup(v, caps) == nil { + caps = append(caps, v) + } + } + + sort.Sort(caps) + + for _, c := range caps { + support := "" + if m := lookup(c, p.Conf.LocalCap); m != nil { + support += "advertised" + } + if lookup(c, p.Conf.RemoteCap) != nil { + if len(support) != 0 { + support += " and " + } + support += "received" + } + + if c.Code != api.BGP_CAPABILITY_MULTIPROTOCOL { + fmt.Printf(" %s: %s\n", c.Code, support) + } else { + fmt.Printf(" %s(%s,%s): %s\n", c.Code, c.MultiProtocol.Afi, c.MultiProtocol.Safi, support) + } + } + fmt.Print(" Message statistics:\n") + fmt.Print(" Sent Rcvd\n") + fmt.Printf(" Opens: %10d %10d\n", p.Info.OpenMessageOut, p.Info.OpenMessageIn) + fmt.Printf(" Notifications: %10d %10d\n", p.Info.NotificationOut, p.Info.NotificationIn) + fmt.Printf(" Updates: %10d %10d\n", p.Info.UpdateMessageOut, p.Info.UpdateMessageIn) + fmt.Printf(" Keepalives: %10d %10d\n", p.Info.KeepAliveMessageOut, p.Info.KeepAliveMessageIn) + fmt.Printf(" Route Refesh: %10d %10d\n", p.Info.RefreshMessageOut, p.Info.RefreshMessageIn) + fmt.Printf(" Discarded: %10d %10d\n", p.Info.DiscardedOut, p.Info.DiscardedIn) + fmt.Printf(" Total: %10d %10d\n", p.Info.TotalMessageOut, p.Info.TotalMessageIn) + + return nil +} + +func (x *NeighborCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_NEIGHBOR) + + if len(eArgs) == 0 || (strings.HasPrefix(eArgs[0], "-") && !(eArgs[0] == "-h" || eArgs[0] == "--help")) { + parser := flags.NewParser(&neighborsOpts, flags.Default) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + if err := requestGrpc(CMD_NEIGHBOR, []string{}, nil); err != nil { + return err + } + } else if len(eArgs) == 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help") { + if err := requestGrpc(CMD_NEIGHBOR, eArgs, nil); err != nil { + return err + } + } else { + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "neighbor [ <neighbor address> ]\n gobgp neighbor" + parser.AddCommand(CMD_LOCAL, "subcommand for local-rib of neighbor", "", NewNeighborRibCommand(eArgs[0], api.Resource_LOCAL, CMD_LOCAL)) + parser.AddCommand(CMD_ADJ_IN, "subcommand for adj-rib-in of neighbor", "", NewNeighborRibCommand(eArgs[0], api.Resource_ADJ_IN, CMD_ADJ_IN)) + parser.AddCommand(CMD_ADJ_OUT, "subcommand for adj-rib-out of neighbor", "", NewNeighborRibCommand(eArgs[0], api.Resource_ADJ_OUT, CMD_ADJ_OUT)) + parser.AddCommand(CMD_RESET, "subcommand for reset the rib of neighbor", "", NewNeighborResetCommand(eArgs[0], CMD_RESET)) + parser.AddCommand(CMD_SOFT_RESET, "subcommand for softreset the rib of neighbor", "", NewNeighborResetCommand(eArgs[0], CMD_SOFT_RESET)) + parser.AddCommand(CMD_SOFT_RESET_IN, "subcommand for softreset the adj-rib-in of neighbor", "", NewNeighborResetCommand(eArgs[0], CMD_SOFT_RESET_IN)) + parser.AddCommand(CMD_SOFT_RESET_OUT, "subcommand for softreset the adj-rib-out of neighbor", "", NewNeighborResetCommand(eArgs[0], CMD_SOFT_RESET_OUT)) + parser.AddCommand(CMD_SHUTDOWN, "subcommand for shutdown to neighbor", "", NewNeighborChangeStateCommand(eArgs[0], CMD_SHUTDOWN)) + parser.AddCommand(CMD_ENABLE, "subcommand for enable to neighbor", "", NewNeighborChangeStateCommand(eArgs[0], CMD_ENABLE)) + parser.AddCommand(CMD_DISABLE, "subcommand for disable to neighbor", "", NewNeighborChangeStateCommand(eArgs[0], CMD_DISABLE)) + parser.AddCommand(CMD_POLICY, "subcommand for policy of neighbor", "", NewNeighborPolicyCommand(eArgs[0])) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + } + return nil +} + +type NeighborRibCommand struct { + remoteIP net.IP + resource api.Resource + command string +} + +func NewNeighborRibCommand(addr string, resource api.Resource, cmd string) *NeighborRibCommand { + return &NeighborRibCommand{ + remoteIP: net.ParseIP(addr), + resource: resource, + command: cmd, + } +} + +func showRoute(pathList []*api.Path, showAge bool, showBest bool) { + + var pathStrs [][]interface{} + maxPrefixLen := len("Network") + maxNexthopLen := len("Next Hop") + maxAsPathLen := len("AS_PATH") + + for _, p := range pathList { + aspath := func(attrs []*api.PathAttr) string { + s := bytes.NewBuffer(make([]byte, 0, 64)) + s.WriteString("[") + for _, a := range attrs { + if a.Type == api.BGP_ATTR_TYPE_AS_PATH { + var ss []string + for _, as := range a.AsPath { + ss = append(ss, fmt.Sprintf("%d", as)) + } + s.WriteString(strings.Join(ss, " ")) + } + } + s.WriteString("]") + return s.String() + } + formatAttrs := func(attrs []*api.PathAttr) string { + s := []string{} + for _, a := range attrs { + switch a.Type { + case api.BGP_ATTR_TYPE_ORIGIN: + s = append(s, fmt.Sprintf("{Origin: %s}", a.Origin)) + case api.BGP_ATTR_TYPE_MULTI_EXIT_DISC: + s = append(s, fmt.Sprintf("{Med: %d}", a.Metric)) + case api.BGP_ATTR_TYPE_LOCAL_PREF: + s = append(s, fmt.Sprintf("{LocalPref: %v}", a.Pref)) + case api.BGP_ATTR_TYPE_ATOMIC_AGGREGATE: + s = append(s, "AtomicAggregate") + case api.BGP_ATTR_TYPE_AGGREGATOR: + s = append(s, fmt.Sprintf("{Aggregate: {AS: %d, Address: %s}", a.GetAggregator().As, a.GetAggregator().Address)) + case api.BGP_ATTR_TYPE_COMMUNITIES: + l := []string{} + known := map[uint32]string{ + 0xffff0000: "planned-shut", + 0xffff0001: "accept-own", + 0xffff0002: "ROUTE_FILTER_TRANSLATED_v4", + 0xffff0003: "ROUTE_FILTER_v4", + 0xffff0004: "ROUTE_FILTER_TRANSLATED_v6", + 0xffff0005: "ROUTE_FILTER_v6", + 0xffff0006: "LLGR_STALE", + 0xffff0007: "NO_LLGR", + 0xFFFFFF01: "NO_EXPORT", + 0xFFFFFF02: "NO_ADVERTISE", + 0xFFFFFF03: "NO_EXPORT_SUBCONFED", + 0xFFFFFF04: "NOPEER"} + + for _, v := range a.Communites { + k, found := known[v] + if found { + l = append(l, fmt.Sprint(k)) + } else { + l = append(l, fmt.Sprintf("%d:%d", (0xffff0000&v)>>16, 0xffff&v)) + } + } + s = append(s, fmt.Sprintf("{Community: %v}", l)) + case api.BGP_ATTR_TYPE_ORIGINATOR_ID: + s = append(s, fmt.Sprintf("{Originator: %v}", a.Originator)) + case api.BGP_ATTR_TYPE_CLUSTER_LIST: + s = append(s, fmt.Sprintf("{Cluster: %v}", a.Cluster)) + case api.BGP_ATTR_TYPE_TUNNEL_ENCAP: + s1 := bytes.NewBuffer(make([]byte, 0, 64)) + s1.WriteString("{Encap: ") + var s2 []string + for _, tlv := range a.TunnelEncap { + s3 := bytes.NewBuffer(make([]byte, 0, 64)) + s3.WriteString(fmt.Sprintf("< %s | ", tlv.Type)) + var s4 []string + for _, subTlv := range tlv.SubTlv { + if subTlv.Type == api.ENCAP_SUBTLV_TYPE_COLOR { + s4 = append(s4, fmt.Sprintf("color: %d", subTlv.Color)) + } + } + s3.WriteString(strings.Join(s4, ",")) + s3.WriteString(" >") + s2 = append(s2, s3.String()) + } + s1.WriteString(strings.Join(s2, "|")) + s1.WriteString("}") + s = append(s, s1.String()) + case api.BGP_ATTR_TYPE_AS4_PATH, api.BGP_ATTR_TYPE_MP_REACH_NLRI, api.BGP_ATTR_TYPE_MP_UNREACH_NLRI, api.BGP_ATTR_TYPE_NEXT_HOP, api.BGP_ATTR_TYPE_AS_PATH: + default: + s = append(s, fmt.Sprintf("{%v: %v}", a.Type, a.Value)) + } + } + return fmt.Sprint(s) + } + best := "" + if showBest { + if p.Best { + best = "*>" + } else { + best = "* " + } + } + + if maxPrefixLen < len(p.Nlri.Prefix) { + maxPrefixLen = len(p.Nlri.Prefix) + } + + if maxNexthopLen < len(p.Nexthop) { + maxNexthopLen = len(p.Nexthop) + } + + if maxAsPathLen < len(aspath(p.Attrs)) { + maxAsPathLen = len(aspath(p.Attrs)) + } + + if showAge { + pathStrs = append(pathStrs, []interface{}{best, p.Nlri.Prefix, p.Nexthop, aspath(p.Attrs), formatTimedelta(p.Age), formatAttrs(p.Attrs)}) + } else { + pathStrs = append(pathStrs, []interface{}{best, p.Nlri.Prefix, p.Nexthop, aspath(p.Attrs), formatAttrs(p.Attrs)}) + } + } + + var format string + if showAge { + format = fmt.Sprintf("%%-2s %%-%ds %%-%ds %%-%ds %%-10s %%-s\n", maxPrefixLen, maxNexthopLen, maxAsPathLen) + fmt.Printf(format, "", "Network", "Next Hop", "AS_PATH", "Age", "Attrs") + } else { + format = fmt.Sprintf("%%-2s %%-%ds %%-%ds %%-%ds %%-s\n", maxPrefixLen, maxNexthopLen, maxAsPathLen) + fmt.Printf(format, "", "Network", "Next Hop", "AS_PATH", "Attrs") + } + + for _, pathStr := range pathStrs { + fmt.Printf(format, pathStr...) + } +} + +func showNeighborRib(resource api.Resource, request *NeighborRibCommand) error { + remoteIP := request.remoteIP + rt, err := checkAddressFamily(remoteIP) + if err != nil { + return err + } + arg := &api.Arguments{ + Resource: resource, + Af: rt, + RouterId: remoteIP.String(), + } + + ps := paths{} + showBest := false + showAge := true + switch resource { + case api.Resource_LOCAL: + showBest = true + stream, e := client.GetRib(context.Background(), arg) + if e != nil { + return e + } + + ds := []*api.Destination{} + for { + d, e := stream.Recv() + if e == io.EOF { + break + } else if e != nil { + return e + } + ds = append(ds, d) + } + + if globalOpts.Json { + j, _ := json.Marshal(ds) + fmt.Println(string(j)) + return nil + } + + for _, d := range ds { + for idx, p := range d.Paths { + if idx == int(d.BestPathIdx) { + p.Best = true + } + ps = append(ps, p) + } + } + case api.Resource_ADJ_OUT: + showAge = false + fallthrough + case api.Resource_ADJ_IN: + stream, e := client.GetAdjRib(context.Background(), arg) + if e != nil { + return e + } + for { + p, e := stream.Recv() + if e == io.EOF { + break + } else if e != nil { + return e + } + ps = append(ps, p) + } + if globalOpts.Json { + j, _ := json.Marshal(ps) + fmt.Println(string(j)) + return nil + } + } + + sort.Sort(ps) + showRoute(ps, showAge, showBest) + return nil +} + +func (x *NeighborRibCommand) Execute(args []string) error { + eArgs := extractArgs(x.command) + parser := flags.NewParser(&subOpts, flags.Default) + parser.Usage = fmt.Sprintf("neighbor <neighbor address> %s [OPTIONS]", x.command) + parser.ParseArgs(eArgs) + if len(eArgs) != 0 && (eArgs[0] == "-h" || eArgs[0] == "--help") { + return nil + } + if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x); err != nil { + return err + } + return nil +} + +type NeighborResetCommand struct { + remoteIP net.IP + command string +} + +func NewNeighborResetCommand(addr string, cmd string) *NeighborResetCommand { + return &NeighborResetCommand{ + remoteIP: net.ParseIP(addr), + command: cmd, + } +} + +func resetNeighbor(request *NeighborResetCommand) error { + remoteIP := request.remoteIP + cmd := request.command + rt, err := checkAddressFamily(remoteIP) + if err != nil { + return err + } + arg := &api.Arguments{ + RouterId: remoteIP.String(), + Af: rt, + } + switch cmd { + case CMD_RESET: + client.Reset(context.Background(), arg) + case CMD_SOFT_RESET: + client.SoftReset(context.Background(), arg) + case CMD_SOFT_RESET_IN: + client.SoftResetIn(context.Background(), arg) + case CMD_SOFT_RESET_OUT: + client.SoftResetOut(context.Background(), arg) + } + return nil +} + +func (x *NeighborResetCommand) Execute(args []string) error { + eArgs := extractArgs(x.command) + parser := flags.NewParser(&subOpts, flags.Default) + parser.Usage = fmt.Sprintf("neighbor <neighbor address> %s [OPTIONS]", x.command) + parser.ParseArgs(eArgs) + if len(eArgs) != 0 && (eArgs[0] == "-h" || eArgs[0] == "--help") { + return nil + } + if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x); err != nil { + return err + } + return nil +} + +type NeighborChangeStateCommand struct { + remoteIP net.IP + command string +} + +func NewNeighborChangeStateCommand(addr string, cmd string) *NeighborChangeStateCommand { + return &NeighborChangeStateCommand{ + remoteIP: net.ParseIP(addr), + command: cmd, + } +} + +func stateChangeNeighbor(request *NeighborChangeStateCommand) error { + remoteIP := request.remoteIP + cmd := request.command + arg := &api.Arguments{ + RouterId: remoteIP.String(), + } + switch cmd { + case CMD_SHUTDOWN: + client.Shutdown(context.Background(), arg) + case CMD_ENABLE: + client.Enable(context.Background(), arg) + case CMD_DISABLE: + client.Disable(context.Background(), arg) + } + return nil +} + +func (x *NeighborChangeStateCommand) Execute(args []string) error { + eArgs := extractArgs(x.command) + if err := requestGrpc(CMD_NEIGHBOR+"_"+x.command, eArgs, x); err != nil { + return err + } + return nil +} + +type NeighborPolicyCommand struct { + remoteIP net.IP +} + +func NewNeighborPolicyCommand(addr string) *NeighborPolicyCommand { + return &NeighborPolicyCommand{ + remoteIP: net.ParseIP(addr), + } +} + +func showNeighborPolicy(request *NeighborPolicyCommand) error { + remoteIP := request.remoteIP + rt, err := checkAddressFamily(net.IP{}) + if err != nil { + return err + } + arg := &api.Arguments{ + Af: rt, + RouterId: remoteIP.String(), + } + + ap, e := client.GetNeighborPolicy(context.Background(), arg) + if e != nil { + return e + } + + if globalOpts.Json { + j, _ := json.Marshal(ap) + fmt.Println(string(j)) + return nil + } + + fmt.Printf("DefaultImportPolicy: %s\n", ap.DefaultImportPolicy) + fmt.Printf("DefaultExportPolicy: %s\n", ap.DefaultExportPolicy) + fmt.Printf("ImportPolicies:\n") + + for _, inPolicy := range ap.ImportPolicies { + fmt.Printf(" PolicyName %s:\n", inPolicy.PolicyDefinitionName) + showPolicyStatement(" ", inPolicy) + } + fmt.Printf("ExportPolicies:\n") + for _, outPolicy := range ap.ExportPolicies { + fmt.Printf(" PolicyName %s:\n", outPolicy.PolicyDefinitionName) + showPolicyStatement(" ", outPolicy) + } + return nil +} + +func (x *NeighborPolicyCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_POLICY) + parser := flags.NewParser(nil, flags.Default) + if len(eArgs) == 0 { + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + if err := requestGrpc(CMD_NEIGHBOR+"_"+CMD_POLICY, eArgs, x); err != nil { + return err + } + } else { + parser.Usage = "neighbor <neighbor address> policy \n gobgp neighbor <neighbor address> policy" + parser.AddCommand(CMD_ADD, "subcommand to add routing policy", "", NewNeighborPolicyAddCommand(x.remoteIP)) + parser.AddCommand(CMD_DEL, "subcommand to delete routing policy", "", NewNeighborPolicyDelCommand(x.remoteIP)) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + } + return nil +} + +type NeighborPolicyAddCommand struct { + remoteIP net.IP +} + +func NewNeighborPolicyAddCommand(addr net.IP) *NeighborPolicyAddCommand { + return &NeighborPolicyAddCommand{ + remoteIP: addr, + } +} +func (x *NeighborPolicyAddCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ADD) + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "neighbor <neighbor address> policy add" + parser.AddCommand(CMD_IMPORT, "subcommand to add import policies to neighbor", "", NewNeighborPolicyChangeCommand(CMD_ADD, CMD_IMPORT, x.remoteIP)) + parser.AddCommand(CMD_EXPORT, "subcommand to add export policies to neighbor", "", NewNeighborPolicyChangeCommand(CMD_ADD, CMD_EXPORT, x.remoteIP)) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + return nil +} + +type NeighborPolicyDelCommand struct { + remoteIP net.IP +} + +func NewNeighborPolicyDelCommand(addr net.IP) *NeighborPolicyDelCommand { + return &NeighborPolicyDelCommand{ + remoteIP: addr, + } +} + +func (x *NeighborPolicyDelCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_DEL) + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "neighbor <neighbor address> policy del" + parser.AddCommand(CMD_IMPORT, "subcommand to delete import policies from neighbor", "", NewNeighborPolicyChangeCommand(CMD_DEL, CMD_IMPORT, x.remoteIP)) + parser.AddCommand(CMD_EXPORT, "subcommand to delete export policies from neighbor", "", NewNeighborPolicyChangeCommand(CMD_DEL, CMD_EXPORT, x.remoteIP)) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + return nil +} + +type NeighborPolicyChangeCommand struct { + operation string + policyOperation string + remoteIP net.IP +} + +func NewNeighborPolicyChangeCommand(operation string, pOperation string, addr net.IP) *NeighborPolicyChangeCommand { + return &NeighborPolicyChangeCommand{ + operation: operation, + policyOperation: pOperation, + remoteIP: addr, + } +} + +func parseRouteAction(rType string) (string, error) { + routeActionUpper := strings.ToUpper(rType) + var routeAction string + switch routeActionUpper { + case policy.ROUTE_ACCEPT, policy.ROUTE_REJECT: + routeAction = routeActionUpper + default: + return "", fmt.Errorf("invalid route action: %s\nPlease enter the accept or reject", rType) + } + return routeAction, nil +} + +func parsePolicy(pNames string) []*api.PolicyDefinition { + pList := strings.Split(pNames, ",") + policyList := make([]*api.PolicyDefinition, 0) + for _, p := range pList { + if p != "" { + policy := &api.PolicyDefinition{ + PolicyDefinitionName: p, + } + policyList = append(policyList, policy) + } + } + return policyList +} + +func modNeighborPolicy(eArg []string, request *NeighborPolicyChangeCommand) error { + var operation api.Operation + pol := &api.ApplyPolicy{} + switch request.operation { + case CMD_ADD: + policies := parsePolicy(eArg[0]) + defaultPolicy, err := parseRouteAction(eArg[1]) + if err != nil { + return err + } + switch request.policyOperation { + case CMD_IMPORT: + pol.ImportPolicies = policies + pol.DefaultImportPolicy = defaultPolicy + case CMD_EXPORT: + pol.ExportPolicies = policies + pol.DefaultExportPolicy = defaultPolicy + } + operation = api.Operation_ADD + + case CMD_DEL: + operation = api.Operation_DEL + } + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_ROUTEPOLICY, + Operation: operation, + RouterId: request.remoteIP.String(), + Name: request.policyOperation, + ApplyPolicy: pol, + } + stream, err := client.ModNeighborPolicy(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 *NeighborPolicyChangeCommand) Execute(args []string) error { + eArgs := extractArgs(x.policyOperation) + if x.operation == CMD_ADD && len(eArgs) != 2 { + return fmt.Errorf("usage: neighbor <neighbor address> policy %s %s <%s policy name> <default %s policy>", + x.operation, x.policyOperation, x.policyOperation, x.policyOperation) + } else if x.operation == CMD_DEL && len(eArgs) != 0 { + return fmt.Errorf("usage: neighbor <neighbor address> policy %s %s", x.operation, x.policyOperation) + } else { + if err := requestGrpc(CMD_NEIGHBOR+"_"+CMD_POLICY+"_"+x.operation, eArgs, x); err != nil { + return err + } + } + return nil +} diff --git a/gobgp/policy.go b/gobgp/policy.go new file mode 100644 index 00000000..f0f6acf4 --- /dev/null +++ b/gobgp/policy.go @@ -0,0 +1,957 @@ +// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "encoding/json" + "fmt" + "github.com/jessevdk/go-flags" + "github.com/osrg/gobgp/api" + "github.com/osrg/gobgp/policy" + "golang.org/x/net/context" + "io" + "net" + "os" + "sort" + "strconv" + "strings" +) + +type PolicyCommand struct{} + +func (x *PolicyCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_POLICY) + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "policy" + parser.AddCommand(CMD_PREFIX, "subcommand for prefix of policy", "", &PolicyPrefixCommand{}) + parser.AddCommand(CMD_NEIGHBOR, "subcommand for neighbor of policy", "", &PolicyNeighborCommand{}) + parser.AddCommand(CMD_ROUTEPOLICY, "subcommand for routepolicy of policy", "", &PolicyRoutePolicyCommand{}) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + return nil +} + +type PolicyPrefixCommand struct{} + +func formatPolicyPrefix(prefixSetList []*api.PrefixSet) (string, string) { + maxNameLen := len("Name") + maxPrefixLen := len("Prefix") + maxRangeLen := len("MaskRange") + for _, ps := range prefixSetList { + if len(ps.PrefixSetName) > maxNameLen { + maxNameLen = len(ps.PrefixSetName) + } + for _, p := range ps.PrefixList { + if len(p.Address)+len(fmt.Sprint(p.MaskLength))+1 > maxPrefixLen { + maxPrefixLen = len(p.Address) + len(fmt.Sprint(p.MaskLength)) + 1 + } + if len(p.MaskLengthRange) > maxRangeLen { + maxRangeLen = len(p.MaskLengthRange) + } + } + } + formatPrefixSet := "%-" + fmt.Sprint(maxNameLen) + "s %-" + fmt.Sprint(maxPrefixLen) + "s %-" + fmt.Sprint(maxRangeLen) + "s\n" + formatPrefixListOnly := "%-" + fmt.Sprint(maxPrefixLen) + "s %-" + fmt.Sprint(maxRangeLen) + "s\n" + return formatPrefixSet, formatPrefixListOnly +} + +func showPolicyPrefixes() error { + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_PREFIX, + } + stream, e := client.GetPolicyPrefixes(context.Background(), arg) + if e != nil { + fmt.Println(e) + return e + } + m := prefixes{} + for { + p, e := stream.Recv() + if e == io.EOF { + break + } else if e != nil { + return e + } + m = append(m, p) + } + + if globalOpts.Json { + j, _ := json.Marshal(m) + fmt.Println(string(j)) + return nil + } + + if globalOpts.Quiet { + for _, p := range m { + fmt.Println(p.PrefixSetName) + } + return nil + } + sort.Sort(m) + + format, _ := formatPolicyPrefix(m) + fmt.Printf(format, "Name", "Prefix", "MaskRange") + for _, ps := range m { + for i, p := range ps.PrefixList { + prefix := fmt.Sprintf("%s/%d", p.Address, p.MaskLength) + if i == 0 { + fmt.Printf(format, ps.PrefixSetName, prefix, p.MaskLengthRange) + } else { + fmt.Printf(format, "", prefix, p.MaskLengthRange) + } + } + } + return nil +} + +func showPolicyPrefix(args []string) error { + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_PREFIX, + Name: args[0], + } + ps, e := client.GetPolicyPrefix(context.Background(), arg) + if e != nil { + return e + } + + if globalOpts.Json { + j, _ := json.Marshal(ps) + fmt.Println(string(j)) + return nil + } + if globalOpts.Quiet { + for _, p := range ps.PrefixList { + fmt.Printf("%s/%d %s\n", p.Address, p.MaskLength, p.MaskLengthRange) + } + return nil + } + format, _ := formatPolicyPrefix([]*api.PrefixSet{ps}) + fmt.Printf(format, "Name", "Prefix", "MaskRange") + for i, p := range ps.PrefixList { + prefix := fmt.Sprintf("%s/%d", p.Address, p.MaskLength) + if i == 0 { + fmt.Printf(format, ps.PrefixSetName, prefix, p.MaskLengthRange) + } else { + fmt.Printf(format, "", prefix, p.MaskLengthRange) + } + } + return nil +} + +func (x *PolicyPrefixCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_PREFIX) + if len(eArgs) == 0 { + if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX, eArgs, nil); err != nil { + return err + } + return nil + } else if len(eArgs) >= 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == CMD_ADD || eArgs[0] == CMD_DEL) { + if len(eArgs) != 1 { + return fmt.Errorf("Argument can not be entered: %s", eArgs[1:]) + } + if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX, eArgs, nil); err != nil { + return err + } + return nil + } + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "policy prefix [<prefix set name>],\n gobgp policy prefix" + parser.AddCommand(CMD_ADD, "subcommand to add prefix condition to policy", "", &PolicyPrefixAddCommand{}) + parser.AddCommand(CMD_DEL, "subcommand to delete prefix condition from policy", "", &PolicyPrefixDelCommand{}) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + return nil +} + +type PolicyPrefixAddCommand struct{} + +func parsePrefixSet(eArgs []string) (*api.PrefixSet, 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]) + } + mask, _ := ipNet.Mask.Size() + prefix := &api.Prefix{ + Address: ipNet.IP.String(), + MaskLength: uint32(mask), + } + + 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 { + 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("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 min >= max { + return nil, fmt.Errorf("invalid mask length range: %s\nlarge value to the right from the left", maskRange) + } + prefix.MaskLengthRange = maskRange + } + prefixList := []*api.Prefix{prefix} + prefixSet := &api.PrefixSet{ + PrefixSetName: eArgs[0], + PrefixList: prefixList, + } + return prefixSet, nil +} + +func modPolicyPrefix(modtype string, eArgs []string) error { + prefixSet := &api.PrefixSet{} + 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 { + operation = api.Operation_DEL_ALL + } else if len(eArgs) == 1 { + prefixSet = &api.PrefixSet{ + PrefixSetName: eArgs[0], + PrefixList: nil, + } + operation = api.Operation_DEL + } else { + if prefixSet, e = parsePrefixSet(eArgs); e != nil { + return e + } + operation = api.Operation_DEL + } + } + + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_PREFIX, + Operation: operation, + PrefixSet: prefixSet, + } + stream, err := client.ModPolicyPrefix(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 *PolicyPrefixAddCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ADD) + if len(eArgs) == 0 || len(eArgs) > 3 { + return fmt.Errorf("usage: policy prefix add <prefix set name> <prefix> [<mask length renge> ]") + } else { + if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX+"_"+CMD_ADD, eArgs, nil); err != nil { + return err + } + } + return nil +} + +type PolicyPrefixDelCommand struct{} + +func (x *PolicyPrefixDelCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_DEL) + if len(eArgs) > 3 { + return fmt.Errorf("usage: policy prefix del <prefix set name> [<prefix> [<mask length range>]] ") + } else if len(eArgs) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "all") { + if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX+"_"+CMD_DEL, eArgs, nil); err != nil { + return err + } + return nil + } + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "policy prefix del <prefix set name> [<prefix> [<mask length range>]],\n gobgp policy prefix del" + parser.AddCommand(CMD_ALL, "subcommand to delete all prefix condition from policy", "", &PolicyPrefixDelAllCommand{}) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + return nil +} + +type PolicyPrefixDelAllCommand struct{} + +func (x *PolicyPrefixDelAllCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ALL) + if len(eArgs) > 0 { + return fmt.Errorf("Argument can not be entered: %s", eArgs) + } + if err := requestGrpc(CMD_POLICY+"_"+CMD_PREFIX+"_"+CMD_DEL, eArgs, nil); err != nil { + return err + } + return nil +} + +type PolicyNeighborCommand struct{} + +func formatPolicyNeighbor(neighborSetList []*api.NeighborSet) string { + maxNameLen := len("Name") + maxAddressLen := len("Address") + for _, ns := range neighborSetList { + if len(ns.NeighborSetName) > maxNameLen { + maxNameLen = len(ns.NeighborSetName) + } + for _, n := range ns.NeighborList { + if len(n.Address) > maxAddressLen { + maxAddressLen = len(n.Address) + } + } + } + format := "%-" + fmt.Sprint(maxNameLen) + "s %-" + fmt.Sprint(maxAddressLen) + "s\n" + return format +} + +func showPolicyNeighbors() error { + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_NEIGHBOR, + } + stream, e := client.GetPolicyNeighbors(context.Background(), arg) + if e != nil { + fmt.Println(e) + return e + } + m := neighbors{} + for { + n, e := stream.Recv() + if e == io.EOF { + break + } else if e != nil { + return e + } + m = append(m, n) + } + + if globalOpts.Json { + j, _ := json.Marshal(m) + fmt.Println(string(j)) + return nil + } + + if globalOpts.Quiet { + for _, n := range m { + fmt.Println(n.NeighborSetName) + } + return nil + } + sort.Sort(m) + + format := formatPolicyNeighbor(m) + fmt.Printf(format, "Name", "Address") + for _, ns := range m { + for i, n := range ns.NeighborList { + if i == 0 { + fmt.Printf(format, ns.NeighborSetName, n.Address) + } else { + fmt.Printf(format, "", n.Address) + } + } + } + return nil +} + +func showPolicyNeighbor(args []string) error { + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_NEIGHBOR, + Name: args[0], + } + ns, e := client.GetPolicyNeighbor(context.Background(), arg) + if e != nil { + return e + } + + if globalOpts.Json { + j, _ := json.Marshal(ns) + fmt.Println(string(j)) + return nil + } + if globalOpts.Quiet { + for _, n := range ns.NeighborList { + fmt.Println(n.Address) + } + return nil + } + format := formatPolicyNeighbor([]*api.NeighborSet{ns}) + fmt.Printf(format, "Name", "Address") + for i, n := range ns.NeighborList { + if i == 0 { + fmt.Printf(format, ns.NeighborSetName, n.Address) + } else { + fmt.Printf(format, "", n.Address) + + } + } + return nil +} + +func (x *PolicyNeighborCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_NEIGHBOR) + if len(eArgs) == 0 { + if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR, eArgs, nil); err != nil { + return err + } + return nil + } else if len(eArgs) >= 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == CMD_ADD || eArgs[0] == CMD_DEL) { + if len(eArgs) != 1 { + return fmt.Errorf("Argument can not be entered: %s", eArgs[1:]) + } + if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR, eArgs, nil); err != nil { + return err + } + return nil + } + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "policy neighbor [<neighbor set name>],\n gobgp policy neighbor" + parser.AddCommand(CMD_ADD, "subcommand to add neighbor condition to policy", "", &PolicyNeighborAddCommand{}) + parser.AddCommand(CMD_DEL, "subcommand to delete neighbor condition from policy", "", &PolicyNeighborDelCommand{}) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + return nil +} + +type PolicyNeighborAddCommand struct{} + +func parseNeighborSet(eArgs []string) (*api.NeighborSet, 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]) + } + } + + neighbor := &api.Neighbor{ + Address: address.String(), + } + neighborList := []*api.Neighbor{neighbor} + neighborSet := &api.NeighborSet{ + NeighborSetName: eArgs[0], + NeighborList: neighborList, + } + return neighborSet, nil +} + +func modPolicyNeighbor(modtype string, eArgs []string) error { + neighborSet := &api.NeighborSet{} + 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 { + operation = api.Operation_DEL_ALL + } else if len(eArgs) == 1 { + neighborSet = &api.NeighborSet{ + NeighborSetName: eArgs[0], + NeighborList: nil, + } + operation = api.Operation_DEL + } else { + if neighborSet, e = parseNeighborSet(eArgs); e != nil { + return e + } + operation = api.Operation_DEL + } + } + + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_NEIGHBOR, + Operation: operation, + NeighborSet: neighborSet, + } + 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 *PolicyNeighborAddCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ADD) + if len(eArgs) == 0 || len(eArgs) > 2 { + return fmt.Errorf("usage: policy neighbor add <neighbor set name> <address>") + } else { + if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR+"_"+CMD_ADD, eArgs, nil); err != nil { + return err + } + } + return nil +} + +type PolicyNeighborDelCommand struct{} + +func (x *PolicyNeighborDelCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_DEL) + if len(eArgs) > 3 { + return fmt.Errorf("usage: policy neighbor del [<neighbor set name> [<address>]]") + } else if len(eArgs) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "all") { + if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR+"_"+CMD_DEL, eArgs, nil); err != nil { + return err + } + return nil + } + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "policy neighbor del [<neighbor set name> [<address>]],\n gobgp policy neighbor del" + parser.AddCommand(CMD_ALL, "subcommand to delete all neighbor condition from policy", "", &PolicyNeighborDelAllCommand{}) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + return nil +} + +type PolicyNeighborDelAllCommand struct{} + +func (x *PolicyNeighborDelAllCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ALL) + if len(eArgs) > 0 { + return fmt.Errorf("Argument can not be entered: %s", eArgs) + } + if err := requestGrpc(CMD_POLICY+"_"+CMD_NEIGHBOR+"_"+CMD_DEL, eArgs, nil); err != nil { + return err + } + return nil +} + +type PolicyRoutePolicyCommand struct{} + +func showPolicyStatement(head string, pd *api.PolicyDefinition) { + for _, st := range pd.StatementList { + fmt.Printf("%s StatementName %s:\n", head, st.StatementNeme) + fmt.Printf("%s Conditions:\n", head) + prefixSet := st.Conditions.MatchPrefixSet + fmt.Printf("%s PrefixSet: %s ", head, prefixSet.PrefixSetName) + if len(prefixSet.PrefixList) != 0 { + nameFormat := "%-" + fmt.Sprint(len(prefixSet.PrefixSetName)+2) + "s" + _, format := formatPolicyPrefix([]*api.PrefixSet{st.Conditions.MatchPrefixSet}) + for i, prefix := range prefixSet.PrefixList { + p := fmt.Sprintf("%s/%d", prefix.Address, prefix.MaskLength) + if i != 0 { + fmt.Printf("%s ", head) + fmt.Printf(nameFormat, "") + } + fmt.Printf(format, p, prefix.MaskLengthRange) + } + } else { + fmt.Print("\n") + } + neighborSet := st.Conditions.MatchNeighborSet + fmt.Printf("%s NeighborSet: %s ", head, neighborSet.NeighborSetName) + if len(neighborSet.NeighborList) != 0 { + nameFormat := "%-" + fmt.Sprint(len(neighborSet.NeighborSetName)+2) + "s" + for i, neighbor := range neighborSet.NeighborList { + if i != 0 { + fmt.Printf("%s ", head) + fmt.Printf(nameFormat, "") + } + fmt.Println(neighbor.Address) + } + } else { + fmt.Print("\n") + } + asPathLentgh := st.Conditions.MatchAsPathLength + fmt.Printf("%s AsPathLength: %s %s\n", head, asPathLentgh.Operator, asPathLentgh.Value) + fmt.Printf("%s MatchOption: %s\n", head, st.Conditions.MatchSetOptions) + fmt.Printf("%s Actions:\n", head) + fmt.Printf("%s %s\n", head, st.Actions.RouteAction) + } + +} + +func showPolicyRoutePolicies() error { + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_ROUTEPOLICY, + } + stream, e := client.GetPolicyRoutePolicies(context.Background(), arg) + if e != nil { + fmt.Println(e) + return e + } + m := policyDefinitions{} + for { + n, e := stream.Recv() + if e == io.EOF { + break + } else if e != nil { + return e + } + m = append(m, n) + } + + if globalOpts.Json { + j, _ := json.Marshal(m) + fmt.Println(string(j)) + return nil + } + if globalOpts.Quiet { + for _, p := range m { + fmt.Println(p.PolicyDefinitionName) + } + return nil + } + sort.Sort(m) + + for _, pd := range m { + fmt.Printf("PolicyName %s:\n", pd.PolicyDefinitionName) + showPolicyStatement("", pd) + } + return nil +} + +func showPolicyRoutePolicy(args []string) error { + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_ROUTEPOLICY, + Name: args[0], + } + pd, e := client.GetPolicyRoutePolicy(context.Background(), arg) + if e != nil { + return e + } + + if globalOpts.Json { + j, _ := json.Marshal(pd) + fmt.Println(string(j)) + return nil + } + + if globalOpts.Quiet { + for _, st := range pd.StatementList { + fmt.Println(st.StatementNeme) + } + return nil + } + + fmt.Printf("PolicyName %s:\n", pd.PolicyDefinitionName) + showPolicyStatement("", pd) + return nil +} + +func (x *PolicyRoutePolicyCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ROUTEPOLICY) + if len(eArgs) == 0 { + if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY, eArgs, nil); err != nil { + return err + } + return nil + } else if len(eArgs) >= 1 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == CMD_ADD || eArgs[0] == CMD_DEL) { + if len(eArgs) != 1 { + return fmt.Errorf("Argument can not be entered: %s", eArgs[1:]) + } + if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY, eArgs, nil); err != nil { + return err + } + return nil + } + parser := flags.NewParser(nil, flags.Default) + parser.Usage = "policy routepolicy [<policy name>],\n gobgp policy routepolicy" + parser.AddCommand(CMD_ADD, "subcommand to add routing policy", "", &PolicyRoutePolicyAddCommand{}) + parser.AddCommand(CMD_DEL, "subcommand to delete routing policy", "", &PolicyRoutePolicyDelCommand{}) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + 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) + } + operator := asPathLen[:idx] + value := asPathLen[idx+1:] + if _, err := strconv.ParseUint(value, 10, 32); err != nil { + return nil, fmt.Errorf("invalid as path length: %s\nPlease enter a numeric", value) + } + conditions.MatchAsPathLength = &api.AsPathLength{ + Value: value, + Operator: operator, + } + } + if conditionOpts.Option != "" { + optionUpper := strings.ToUpper(conditionOpts.Option) + var option string + switch optionUpper { + case policy.OPTIONS_ANY, policy.OPTIONS_ALL, policy.OPTIONS_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.RouteAction != "" { + routeAction, e := parseRouteAction(actionOpts.RouteAction) + if e != nil { + return nil, e + } + actions.RouteAction = routeAction + } + return actions, nil +} + +func modPolicyRoutePolicy(modtype string, stmtType string, eArgs []string, request interface{}) error { + var e error + var operation api.Operation + pd := &api.PolicyDefinition{} + switch modtype { + case CMD_ADD: + stmt := &api.Statement{} + switch stmtType { + case CMD_CONDITIONS: + conditions, err := parseConditions() + if err != nil { + return err + } + stmt.StatementNeme = request.(*PolicyRoutePolicyAddConditionsCommand).statementName + stmt.Conditions = conditions + pd.PolicyDefinitionName = request.(*PolicyRoutePolicyAddConditionsCommand).policyName + case CMD_ACTIONS: + actions, err := parseActions() + if err != nil { + return err + } + stmt.StatementNeme = request.(*PolicyRoutePolicyAddActionsCommand).statementName + stmt.Actions = actions + pd.PolicyDefinitionName = request.(*PolicyRoutePolicyAddActionsCommand).policyName + } + 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) + parser := flags.NewParser(nil, flags.Default) + if len(eArgs) < 2 { + return fmt.Errorf("usage: policy routepolicy add <routing policy name> <statement name>") + } + parser.Usage = "policy routepolicy add <routing policy name> <statement 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])) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + 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]" + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + if len(eArgs) == 0 { + return fmt.Errorf("usage: 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]" + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + if len(eArgs) == 0 { + return fmt.Errorf("usage: 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) > 0 && !(eArgs[0] == "-h" || eArgs[0] == "--help" || eArgs[0] == "all") { + if len(eArgs) > 2 { + return fmt.Errorf("Argument can not be entered: %s", eArgs[2:]) + } + 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>],\n gobgp policy routepolicy del" + parser.AddCommand(CMD_ALL, "subcommand to delete all routing policy", "", &PolicyRoutePolicyDelAllCommand{}) + if _, err := parser.ParseArgs(eArgs); err != nil { + os.Exit(1) + } + return nil +} + +type PolicyRoutePolicyDelAllCommand struct{} + +func (x *PolicyRoutePolicyDelAllCommand) Execute(args []string) error { + eArgs := extractArgs(CMD_ALL) + if len(eArgs) > 0 { + return fmt.Errorf("Argument can not be entered: %s", eArgs) + } + if err := requestGrpc(CMD_POLICY+"_"+CMD_ROUTEPOLICY+"_"+CMD_DEL, eArgs, nil); err != nil { + return err + } + return nil +} |