summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gobgp/cmd/common.go (renamed from gobgp/common.go)2
-rw-r--r--gobgp/cmd/global.go (renamed from gobgp/global.go)387
-rw-r--r--gobgp/cmd/monitor.go (renamed from gobgp/monitor.go)2
-rw-r--r--gobgp/cmd/mrt.go (renamed from gobgp/mrt.go)2
-rw-r--r--gobgp/cmd/neighbor.go (renamed from gobgp/neighbor.go)2
-rw-r--r--gobgp/cmd/policy.go (renamed from gobgp/policy.go)2
-rw-r--r--gobgp/cmd/root.go68
-rw-r--r--gobgp/cmd/rpki.go (renamed from gobgp/rpki.go)2
-rw-r--r--gobgp/cmd/vrf.go (renamed from gobgp/vrf.go)2
-rw-r--r--gobgp/lib/lib.go77
-rw-r--r--gobgp/lib/path.go122
-rw-r--r--gobgp/main.go48
12 files changed, 474 insertions, 242 deletions
diff --git a/gobgp/common.go b/gobgp/cmd/common.go
index 04e482a9..3e3f6fca 100644
--- a/gobgp/common.go
+++ b/gobgp/cmd/common.go
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package cmd
import (
"bytes"
diff --git a/gobgp/global.go b/gobgp/cmd/global.go
index 23754e8f..c777bdbc 100644
--- a/gobgp/global.go
+++ b/gobgp/cmd/global.go
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package cmd
import (
"fmt"
@@ -28,10 +28,6 @@ import (
"strings"
)
-func showGlobalRib(args []string) error {
- return showNeighborRib(CMD_GLOBAL, "", args)
-}
-
type ExtCommType int
const (
@@ -203,232 +199,185 @@ func ParseExtendedCommunities(input string) ([]bgp.ExtendedCommunityInterface, e
return exts, nil
}
-func parseFlowSpecArgs(resource api.Resource, name, modtype string, args []string) (bgp.AddrPrefixInterface, string, []string, error) {
+func ParseFlowSpecArgs(args []string) (bgp.AddrPrefixInterface, string, []string, error) {
thenPos := len(args)
for idx, v := range args {
if v == "then" {
thenPos = idx
}
}
- ss := make([]string, 0, len(bgp.ProtocolNameMap))
- for _, v := range bgp.ProtocolNameMap {
- ss = append(ss, v)
- }
- protos := strings.Join(ss, ", ")
- ss = make([]string, 0, len(bgp.TCPFlagNameMap))
- for _, v := range bgp.TCPFlagNameMap {
- ss = append(ss, v)
- }
- flags := strings.Join(ss, ", ")
- helpErr := fmt.Errorf(`usage: global rib %s match <MATCH_EXPR> then <THEN_EXPR> -a ipv4-flowspec
- <MATCH_EXPR> : { %s <PREFIX> | %s <PREFIX> |
- %s <PROTO>... | %s <FRAGMENT_TYPE> | %s <TCPFLAG>... |
- { %s | %s | %s | %s | %s | %s | %s } <ITEM>... }...
- <PROTO> : %s
- <FRAGMENT_TYPE> : not-a-fragment, is-a-fragment, first-fragment, last-fragment
- <TCPFLAG> : %s
- <ITEM> : &?{<|>|=}<value>
- <THEN_EXPR> : { %s | %s | %s <value> | %s <RT> | %s <value> | %s { sample | terminal | sample-terminal } | %s <RT>... }...
- <RT> : xxx:yyy, xx.xx.xx.xx:yyy, xxx.xxx:yyy`, modtype,
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DST_PREFIX],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_SRC_PREFIX],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_IP_PROTO],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_FRAGMENT],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_TCP_FLAG],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_PORT],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DST_PORT],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_SRC_PORT],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_ICMP_TYPE],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_ICMP_CODE],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_PKT_LEN],
- bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DSCP],
- protos, flags,
- ExtCommNameMap[ACCEPT], ExtCommNameMap[DISCARD],
- ExtCommNameMap[RATE], ExtCommNameMap[REDIRECT],
- ExtCommNameMap[MARK], ExtCommNameMap[ACTION], ExtCommNameMap[RT])
-
if len(args) < 4 || args[0] != "match" || thenPos > len(args)-2 {
- return nil, "", nil, helpErr
+ return nil, "", nil, fmt.Errorf("invalid format")
}
matchArgs := args[1:thenPos]
cmp, err := bgp.ParseFlowSpecComponents(strings.Join(matchArgs, " "))
if err != nil {
- return nil, "", nil, fmt.Errorf("%s\n%s", err, helpErr)
+ return nil, "", nil, err
}
nlri := bgp.NewFlowSpecIPv4Unicast(cmp)
return nlri, "0.0.0.0", args[thenPos:], nil
}
-func parseEvpnArgs(resource api.Resource, name, modtype string, args []string) (bgp.AddrPrefixInterface, string, []string, error) {
- cmdstr := "global"
- if resource == api.Resource_VRF {
- cmdstr = fmt.Sprintf("vrf %s", name)
- }
- if len(args) < 1 {
- return nil, "", nil, fmt.Errorf("usage: %s rib %s { macadv | multicast } ... -a evpn", cmdstr, modtype)
+func ParseEvpnMacAdvArgs(args []string) (bgp.AddrPrefixInterface, string, []string, error) {
+ if len(args) < 4 {
+ return nil, "", nil, fmt.Errorf("lack of number of args needs 4 but %d", len(args))
}
- subtype := args[0]
- args = args[1:]
-
var nlri bgp.AddrPrefixInterface
var rts []string
var ip net.IP
iplen := 0
- switch subtype {
- case "macadv":
- switch resource {
- case api.Resource_GLOBAL:
- if len(args) < 6 || args[4] != "rd" || args[6] != "rt" {
- return nil, "", nil, fmt.Errorf("usage: rib %s macadv <mac address> <ip address> <etag> <label> rd <rd> rt <rt>... -a evpn", modtype)
- }
- case api.Resource_VRF:
- if len(args) < 4 {
- return nil, "", nil, fmt.Errorf("usage: vrf %s rib %s macadv <mac address> <ip address> <etag> <label> -a evpn", name, modtype)
- }
- }
- mac, err := net.ParseMAC(args[0])
- if err != nil {
- return nil, "", nil, fmt.Errorf("invalid mac: %s", args[0])
- }
- if args[1] != "0.0.0.0" || args[1] != "::" {
- ip = net.ParseIP(args[1])
- if ip == nil {
- return nil, "", nil, fmt.Errorf("invalid ip prefix: %s", args[1])
- }
- iplen = net.IPv4len * 8
- if ip.To4() == nil {
- iplen = net.IPv6len * 8
- }
+ mac, err := net.ParseMAC(args[0])
+ if err != nil {
+ return nil, "", nil, fmt.Errorf("invalid mac: %s", args[0])
+ }
+ if args[1] != "0.0.0.0" || args[1] != "::" {
+ ip = net.ParseIP(args[1])
+ if ip == nil {
+ return nil, "", nil, fmt.Errorf("invalid ip prefix: %s", args[1])
}
- eTag, err := strconv.Atoi(args[2])
- if err != nil {
- return nil, "", nil, fmt.Errorf("invalid eTag: %s. err: %s", args[2], err)
+ iplen = net.IPv4len * 8
+ if ip.To4() == nil {
+ iplen = net.IPv6len * 8
}
- label, err := strconv.Atoi(args[3])
+ }
+ eTag, err := strconv.Atoi(args[2])
+ if err != nil {
+ return nil, "", nil, fmt.Errorf("invalid eTag: %s. err: %s", args[2], err)
+ }
+ label, err := strconv.Atoi(args[3])
+ if err != nil {
+ return nil, "", nil, fmt.Errorf("invalid label: %s. err: %s", args[3], err)
+ }
+
+ var rd bgp.RouteDistinguisherInterface
+ if args[4] == "rd" && len(args) > 5 {
+ rd, err = bgp.ParseRouteDistinguisher(args[5])
if err != nil {
- return nil, "", nil, fmt.Errorf("invalid label: %s. err: %s", args[3], err)
- }
- var rd bgp.RouteDistinguisherInterface
- if resource == api.Resource_GLOBAL {
- rd, err = bgp.ParseRouteDistinguisher(args[5])
- if err != nil {
- return nil, "", nil, err
- }
- rts = args[6:]
+ return nil, "", nil, err
}
+ }
- macIpAdv := &bgp.EVPNMacIPAdvertisementRoute{
- RD: rd,
- ESI: bgp.EthernetSegmentIdentifier{
- Type: bgp.ESI_ARBITRARY,
- },
- MacAddressLength: 48,
- MacAddress: mac,
- IPAddressLength: uint8(iplen),
- IPAddress: ip,
- Labels: []uint32{uint32(label)},
- ETag: uint32(eTag),
- }
- nlri = bgp.NewEVPNNLRI(bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, 0, macIpAdv)
- case "multicast":
- switch resource {
- case api.Resource_GLOBAL:
- if len(args) < 5 || args[2] != "rd" || args[4] != "rt" {
- return nil, "", nil, fmt.Errorf("usage : global rib %s multicast <ip address> <etag> rd <rd> rt <rt> -a evpn", modtype)
- }
- case api.Resource_VRF:
- if len(args) < 2 {
- return nil, "", nil, fmt.Errorf("usage : vrf %s rib %s multicast <ip address> <etag> -a evpn", name, modtype)
- }
+ if len(args) > 6 {
+ rts = args[6:]
+ }
+
+ macIpAdv := &bgp.EVPNMacIPAdvertisementRoute{
+ RD: rd,
+ ESI: bgp.EthernetSegmentIdentifier{
+ Type: bgp.ESI_ARBITRARY,
+ },
+ MacAddressLength: 48,
+ MacAddress: mac,
+ IPAddressLength: uint8(iplen),
+ IPAddress: ip,
+ Labels: []uint32{uint32(label)},
+ ETag: uint32(eTag),
+ }
+ nlri = bgp.NewEVPNNLRI(bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, 0, macIpAdv)
+ return nlri, "0.0.0.0", rts, nil
+}
+
+func ParseEvpnMulticastArgs(args []string) (bgp.AddrPrefixInterface, string, []string, error) {
+ if len(args) < 2 {
+ return nil, "", nil, fmt.Errorf("lack of number of args needs 2 but %d", len(args))
+ }
+ var nlri bgp.AddrPrefixInterface
+ var rts []string
+ var ip net.IP
+ iplen := 0
+
+ if args[0] != "0.0.0.0" || args[0] != "::" {
+ ip = net.ParseIP(args[0])
+ if ip == nil {
+ return nil, "", nil, fmt.Errorf("invalid ip prefix: %s", args[0])
}
- if args[0] != "0.0.0.0" || args[0] != "::" {
- ip = net.ParseIP(args[0])
- if ip == nil {
- return nil, "", nil, fmt.Errorf("invalid ip prefix: %s", args[0])
- }
- iplen = net.IPv4len * 8
- if ip.To4() == nil {
- iplen = net.IPv6len * 8
- }
+ iplen = net.IPv4len * 8
+ if ip.To4() == nil {
+ iplen = net.IPv6len * 8
}
+ }
- eTag, err := strconv.Atoi(args[1])
- if err != nil {
- return nil, "", nil, fmt.Errorf("invalid eTag: %s. err: %s", args[1], err)
- }
+ eTag, err := strconv.Atoi(args[1])
+ if err != nil {
+ return nil, "", nil, fmt.Errorf("invalid eTag: %s. err: %s", args[1], err)
+ }
- var rd bgp.RouteDistinguisherInterface
- if resource == api.Resource_GLOBAL {
- rd, err = bgp.ParseRouteDistinguisher(args[3])
- if err != nil {
- return nil, "", nil, err
- }
- rts = args[4:]
+ var rd bgp.RouteDistinguisherInterface
+ if args[2] == "rd" && len(args) > 3 {
+ rd, err = bgp.ParseRouteDistinguisher(args[3])
+ if err != nil {
+ return nil, "", nil, err
}
+ }
- multicastEtag := &bgp.EVPNMulticastEthernetTagRoute{
- RD: rd,
- IPAddressLength: uint8(iplen),
- IPAddress: ip,
- ETag: uint32(eTag),
- }
- nlri = bgp.NewEVPNNLRI(bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG, 0, multicastEtag)
- default:
- return nil, "", nil, fmt.Errorf("usage: global rib add { macadv | multicast | ... -a evpn")
+ if len(args) > 4 {
+ rts = args[4:]
+ }
+ multicastEtag := &bgp.EVPNMulticastEthernetTagRoute{
+ RD: rd,
+ IPAddressLength: uint8(iplen),
+ IPAddress: ip,
+ ETag: uint32(eTag),
}
+ nlri = bgp.NewEVPNNLRI(bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG, 0, multicastEtag)
return nlri, "0.0.0.0", rts, nil
+
}
-func modPath(resource api.Resource, name, modtype string, args []string) error {
- rf, err := checkAddressFamily(net.IP{})
- if err != nil {
- return err
+func ParseEvpnArgs(args []string) (bgp.AddrPrefixInterface, string, []string, error) {
+ if len(args) < 1 {
+ return nil, "", nil, fmt.Errorf("lack of args. need 1 but %d", len(args))
+ }
+ subtype := args[0]
+ args = args[1:]
+ switch subtype {
+ case "macadv":
+ return ParseEvpnMacAdvArgs(args)
+ case "multicast":
+ return ParseEvpnMulticastArgs(args)
}
+ return nil, "", nil, fmt.Errorf("invalid subtype. expect [macadv|multicast] but %s", subtype)
+}
+func ParsePath(rf bgp.RouteFamily, args []string) (*api.Path, error) {
var nlri bgp.AddrPrefixInterface
var nexthop string
var extcomms []string
-
- cmdstr := "global"
- if resource == api.Resource_VRF {
- cmdstr = fmt.Sprintf("vrf %s", name)
- }
-
+ var err error
switch rf {
case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC:
if len(args) != 1 {
- return fmt.Errorf("usage: %s rib %s <prefix> -a { ipv4 | ipv6 }", cmdstr, modtype)
+ return nil, fmt.Errorf("invalid format")
}
- ip, net, _ := net.ParseCIDR(args[0])
+ ip, net, err := net.ParseCIDR(args[0])
+ if err != nil {
+ return nil, err
+ }
+ ones, _ := net.Mask.Size()
if rf == bgp.RF_IPv4_UC {
if ip.To4() == nil {
- return fmt.Errorf("invalid ipv4 prefix")
+ return nil, fmt.Errorf("invalid ipv4 prefix")
}
nexthop = "0.0.0.0"
- ones, _ := net.Mask.Size()
nlri = bgp.NewNLRInfo(uint8(ones), ip.String())
} else {
if ip.To16() == nil {
- return fmt.Errorf("invalid ipv6 prefix")
+ return nil, fmt.Errorf("invalid ipv6 prefix")
}
nexthop = "::"
- ones, _ := net.Mask.Size()
nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String())
}
case bgp.RF_IPv4_VPN, bgp.RF_IPv6_VPN:
- if resource != api.Resource_GLOBAL {
- return fmt.Errorf("Unsupported route family: %s", rf)
- }
- if len(args) < 3 || args[1] != "rd" || args[3] != "rt" {
- return fmt.Errorf("usage: %s rib %s <prefix> rd <rd> rt <rt>... -a { vpn-ipv4 | vpn-ipv6 }", cmdstr, modtype)
+ if len(args) < 3 || args[1] != "rd" {
+ return nil, fmt.Errorf("invalid format")
}
ip, net, _ := net.ParseCIDR(args[0])
ones, _ := net.Mask.Size()
rd, err := bgp.ParseRouteDistinguisher(args[2])
if err != nil {
- return err
+ return nil, err
}
extcomms = args[3:]
@@ -437,43 +386,33 @@ func modPath(resource api.Resource, name, modtype string, args []string) error {
if rf == bgp.RF_IPv4_VPN {
if ip.To4() == nil {
- return fmt.Errorf("invalid ipv4 prefix")
+ return nil, fmt.Errorf("invalid ipv4 prefix")
}
nexthop = "0.0.0.0"
nlri = bgp.NewLabeledVPNIPAddrPrefix(uint8(ones), ip.String(), *mpls, rd)
} else {
if ip.To16() == nil {
- return fmt.Errorf("invalid ipv6 prefix")
+ return nil, fmt.Errorf("invalid ipv6 prefix")
}
nexthop = "::"
nlri = bgp.NewLabeledVPNIPv6AddrPrefix(uint8(ones), ip.String(), *mpls, rd)
}
case bgp.RF_EVPN:
- nlri, nexthop, extcomms, err = parseEvpnArgs(resource, name, modtype, args)
- if err != nil {
- return err
- }
+ nlri, nexthop, extcomms, err = ParseEvpnArgs(args)
case bgp.RF_FS_IPv4_UC:
- if resource != api.Resource_GLOBAL {
- return fmt.Errorf("Unsupported route family: %s", rf)
- }
- nlri, nexthop, extcomms, err = parseFlowSpecArgs(resource, name, modtype, args)
- if err != nil {
- return err
- }
+ nlri, nexthop, extcomms, err = ParseFlowSpecArgs(args)
default:
- return fmt.Errorf("Unsupported route family: %s", rf)
+ return nil, fmt.Errorf("Unsupported route family: %s", rf)
+ }
+ if err != nil {
+ return nil, err
}
path := &api.Path{
Pattrs: make([][]byte, 0),
}
- if modtype == CMD_DEL {
- path.IsWithdraw = true
- }
-
if rf == bgp.RF_IPv4_UC {
path.Nlri, _ = nlri.Serialize()
n, _ := bgp.NewPathAttributeNextHop(nexthop).Serialize()
@@ -489,31 +428,101 @@ func modPath(resource api.Resource, name, modtype string, args []string) error {
if extcomms != nil && len(extcomms) > 0 {
extcomms, err := ParseExtendedCommunities(strings.Join(extcomms, " "))
if err != nil {
- return err
+ return nil, err
}
p := bgp.NewPathAttributeExtendedCommunities(extcomms)
buf, err := p.Serialize()
if err != nil {
- return err
+ return nil, err
}
path.Pattrs = append(path.Pattrs, buf)
}
+ return path, nil
+}
- stream, err := client.ModPath(context.Background())
+func showGlobalRib(args []string) error {
+ return showNeighborRib(CMD_GLOBAL, "", args)
+}
+
+func modPath(resource api.Resource, name, modtype string, args []string) error {
+ rf, err := checkAddressFamily(net.IP{})
if err != nil {
return err
}
+
+ path, err := ParsePath(rf, args)
+
+ if err != nil {
+ cmdstr := "global"
+ if resource == api.Resource_VRF {
+ cmdstr = fmt.Sprintf("vrf %s", name)
+ }
+
+ ss := make([]string, 0, len(bgp.ProtocolNameMap))
+ for _, v := range bgp.ProtocolNameMap {
+ ss = append(ss, v)
+ }
+ protos := strings.Join(ss, ", ")
+ ss = make([]string, 0, len(bgp.TCPFlagNameMap))
+ for _, v := range bgp.TCPFlagNameMap {
+ ss = append(ss, v)
+ }
+ flags := strings.Join(ss, ", ")
+ helpErrMap := map[bgp.RouteFamily]error{}
+ helpErrMap[bgp.RF_FS_IPv4_UC] = fmt.Errorf(`usage: %s rib %s match <MATCH_EXPR> then <THEN_EXPR> -a ipv4-flowspec
+ <MATCH_EXPR> : { %s <PREFIX> | %s <PREFIX> |
+ %s <PROTO>... | %s <FRAGMENT_TYPE> | %s <TCPFLAG>... |
+ { %s | %s | %s | %s | %s | %s | %s } <ITEM>... }...
+ <PROTO> : %s
+ <FRAGMENT_TYPE> : not-a-fragment, is-a-fragment, first-fragment, last-fragment
+ <TCPFLAG> : %s
+ <ITEM> : &?{<|>|=}<value>
+ <THEN_EXPR> : { %s | %s | %s <value> | %s <RT> | %s <value> | %s { sample | terminal | sample-terminal } | %s <RT>... }...
+ <RT> : xxx:yyy, xx.xx.xx.xx:yyy, xxx.xxx:yyy`, cmdstr, modtype,
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DST_PREFIX],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_SRC_PREFIX],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_IP_PROTO],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_FRAGMENT],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_TCP_FLAG],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_PORT],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DST_PORT],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_SRC_PORT],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_ICMP_TYPE],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_ICMP_CODE],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_PKT_LEN],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DSCP],
+ protos, flags,
+ ExtCommNameMap[ACCEPT], ExtCommNameMap[DISCARD],
+ ExtCommNameMap[RATE], ExtCommNameMap[REDIRECT],
+ ExtCommNameMap[MARK], ExtCommNameMap[ACTION], ExtCommNameMap[RT])
+ helpErrMap[bgp.RF_EVPN] = fmt.Errorf(`usage: %s rib %s { macadv <MACADV> | multicast <MULTICAST> } -a evpn
+ <MACADV> : <mac address> <ip address> <etag> <label> rd <rd> rt <rt>...
+ <MULTICAST> : <ip address> <etag> rd <rd> rt <rt>...`, cmdstr, modtype)
+ if err, ok := helpErrMap[rf]; ok {
+ return err
+ }
+ return err
+ }
+
+ if modtype == CMD_DEL {
+ path.IsWithdraw = true
+ }
+
arg := &api.ModPathArguments{
Resource: resource,
Name: name,
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.CloseAndRecv()
if e != nil {
return e
diff --git a/gobgp/monitor.go b/gobgp/cmd/monitor.go
index bd96622d..3c91648e 100644
--- a/gobgp/monitor.go
+++ b/gobgp/cmd/monitor.go
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package cmd
import (
"encoding/json"
diff --git a/gobgp/mrt.go b/gobgp/cmd/mrt.go
index c182d23a..fd598aa4 100644
--- a/gobgp/mrt.go
+++ b/gobgp/cmd/mrt.go
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package cmd
import (
"bytes"
diff --git a/gobgp/neighbor.go b/gobgp/cmd/neighbor.go
index 92e82901..d7037145 100644
--- a/gobgp/neighbor.go
+++ b/gobgp/cmd/neighbor.go
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package cmd
import (
"bytes"
diff --git a/gobgp/policy.go b/gobgp/cmd/policy.go
index 7d88d723..cf079bc0 100644
--- a/gobgp/policy.go
+++ b/gobgp/cmd/policy.go
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package cmd
import (
"encoding/json"
diff --git a/gobgp/cmd/root.go b/gobgp/cmd/root.go
new file mode 100644
index 00000000..2ad598fe
--- /dev/null
+++ b/gobgp/cmd/root.go
@@ -0,0 +1,68 @@
+// 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 cmd
+
+import (
+ "github.com/osrg/gobgp/api"
+ "github.com/spf13/cobra"
+)
+
+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"`
+ Debug bool `short:"d" long:"debug" description:"use debug"`
+ Quiet bool `short:"q" long:"quiet" description:"use quiet"`
+ Json bool `short:"j" long:"json" description:"use json format to output format"`
+ GenCmpl bool `short:"c" long:"genbashcmpl" description:"use json format to output format"`
+ BashCmplFile string
+}
+
+var cmds []string
+var client api.GrpcClient
+
+func NewRootCmd() *cobra.Command {
+ cobra.EnablePrefixMatching = true
+ rootCmd := &cobra.Command{
+ Use: "gobgp",
+ PersistentPreRun: func(cmd *cobra.Command, args []string) {
+ if !globalOpts.GenCmpl {
+ conn := connGrpc()
+ client = api.NewGrpcClient(conn)
+ }
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ cmd.GenBashCompletionFile(globalOpts.BashCmplFile)
+ },
+ }
+
+ rootCmd.PersistentFlags().StringVarP(&globalOpts.Host, "host", "u", "127.0.0.1", "host")
+ rootCmd.PersistentFlags().IntVarP(&globalOpts.Port, "port", "p", 8080, "port")
+ rootCmd.PersistentFlags().BoolVarP(&globalOpts.Json, "json", "j", false, "use json format to output format")
+ rootCmd.PersistentFlags().BoolVarP(&globalOpts.Debug, "debug", "d", false, "use debug")
+ rootCmd.PersistentFlags().BoolVarP(&globalOpts.Quiet, "quiet", "q", false, "use quiet")
+ rootCmd.PersistentFlags().BoolVarP(&globalOpts.GenCmpl, "gen-cmpl", "c", false, "generate completion file")
+ rootCmd.PersistentFlags().StringVarP(&globalOpts.BashCmplFile, "bash-cmpl-file", "", "gobgp_completion.bash", "bash cmpl filename")
+
+ globalCmd := NewGlobalCmd()
+ neighborCmd := NewNeighborCmd()
+ vrfCmd := NewVrfCmd()
+ policyCmd := NewPolicyCmd()
+ monitorCmd := NewMonitorCmd()
+ mrtCmd := NewMrtCmd()
+ rpkiCmd := NewRPKICmd()
+ rootCmd.AddCommand(globalCmd, neighborCmd, vrfCmd, policyCmd, monitorCmd, mrtCmd, rpkiCmd)
+ return rootCmd
+}
diff --git a/gobgp/rpki.go b/gobgp/cmd/rpki.go
index 0e299a69..c7a65f47 100644
--- a/gobgp/rpki.go
+++ b/gobgp/cmd/rpki.go
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package cmd
import (
"fmt"
diff --git a/gobgp/vrf.go b/gobgp/cmd/vrf.go
index ef7ba69f..44a145e3 100644
--- a/gobgp/vrf.go
+++ b/gobgp/cmd/vrf.go
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package cmd
import (
"encoding/json"
diff --git a/gobgp/lib/lib.go b/gobgp/lib/lib.go
new file mode 100644
index 00000000..b6103ed3
--- /dev/null
+++ b/gobgp/lib/lib.go
@@ -0,0 +1,77 @@
+// 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
+
+// #include <stdio.h>
+// #include <stdlib.h>
+// #include <string.h>
+// typedef struct {
+// char *value;
+// int len;
+// } buf;
+//
+// typedef struct path_t {
+// buf nlri;
+// buf** path_attributes;
+// int path_attributes_len;
+// int path_attributes_cap;
+// } path;
+//
+// path* new_path() {
+// path* p;
+// int cap = 32;
+// p = (path*)malloc(sizeof(path));
+// memset(p, 0, sizeof(p));
+// p->nlri.len = 0;
+// p->path_attributes_len = 0;
+// p->path_attributes_cap = cap;
+// p->path_attributes = (buf**)malloc(sizeof(buf)*cap);
+// return p;
+// }
+//
+// free_path(path* p) {
+// int i;
+// if (p->nlri.value != NULL) {
+// free(p->nlri.value);
+// }
+// for (i = 0; i < p->path_attributes_len; i++) {
+// buf* b;
+// b = p->path_attributes[i];
+// free(b->value);
+// free(b);
+// }
+// free(p->path_attributes);
+// free(p);
+// }
+//
+// append_path_attribute(path* p, int len, char* value) {
+// buf* b;
+// if (p->path_attributes_len >= p->path_attributes_cap) {
+// return -1;
+// }
+// b = (buf*)malloc(sizeof(buf));
+// b->value = value;
+// b->len = len;
+// p->path_attributes[p->path_attributes_len] = b;
+// p->path_attributes_len++;
+// }
+// buf* get_path_attribute(path* p, int idx) {
+// if (idx < 0 || idx >= p->path_attributes_len) {
+// return NULL;
+// }
+// return p->path_attributes[idx];
+// }
+import "C"
diff --git a/gobgp/lib/path.go b/gobgp/lib/path.go
new file mode 100644
index 00000000..124a994a
--- /dev/null
+++ b/gobgp/lib/path.go
@@ -0,0 +1,122 @@
+// 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
+
+// typedef struct {
+// char *value;
+// int len;
+// } buf;
+//
+// typedef struct path_t {
+// buf nlri;
+// buf** path_attributes;
+// int path_attributes_len;
+// int path_attributes_cap;
+// } path;
+// extern path* new_path();
+// extern free_path(path*);
+// extern append_path_attribute(path*, int, char*);
+// extern buf* get_path_attribute(path*, int);
+import "C"
+
+import (
+ "encoding/json"
+ "fmt"
+ "strings"
+
+ "github.com/osrg/gobgp/gobgp/cmd"
+ "github.com/osrg/gobgp/packet"
+)
+
+//export get_route_family
+func get_route_family(input *C.char) C.int {
+ rf, err := bgp.GetRouteFamily(C.GoString(input))
+ if err != nil {
+ return C.int(-1)
+ }
+ return C.int(rf)
+}
+
+//export serialize_path
+func serialize_path(rf C.int, input *C.char) *C.path {
+ args := strings.Split(C.GoString(input), " ")
+ p, err := cmd.ParsePath(bgp.RouteFamily(rf), args)
+ if err != nil {
+ return nil
+ }
+ path := C.new_path()
+ if len(p.Nlri) > 0 {
+ path.nlri.len = C.int(len(p.Nlri))
+ path.nlri.value = C.CString(string(p.Nlri))
+ }
+ for _, attr := range p.Pattrs {
+ C.append_path_attribute(path, C.int(len(attr)), C.CString(string(attr)))
+ }
+ return path
+}
+
+//export decode_path
+func decode_path(p *C.path) *C.char {
+ var buf []byte
+ var nlri bgp.AddrPrefixInterface
+ if p.nlri.len > 0 {
+ fmt.Println(p.nlri.len)
+ buf = []byte(C.GoStringN(p.nlri.value, p.nlri.len))
+ nlri = &bgp.NLRInfo{}
+ err := nlri.DecodeFromBytes(buf)
+ if err != nil {
+ return nil
+ }
+ }
+ pattrs := make([]bgp.PathAttributeInterface, 0, int(p.path_attributes_len))
+ for i := 0; i < int(p.path_attributes_len); i++ {
+ b := C.get_path_attribute(p, C.int(i))
+ buf = []byte(C.GoStringN(b.value, b.len))
+ pattr, err := bgp.GetPathAttribute(buf)
+ if err != nil {
+ return nil
+ }
+
+ err = pattr.DecodeFromBytes(buf)
+ if err != nil {
+ return nil
+ }
+
+ switch pattr.GetType() {
+ case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI:
+ mpreach := pattr.(*bgp.PathAttributeMpReachNLRI)
+ if len(mpreach.Value) != 1 {
+ return nil
+ }
+ nlri = mpreach.Value[0]
+ }
+
+ pattrs = append(pattrs, pattr)
+ }
+ j, _ := json.Marshal(struct {
+ Nlri bgp.AddrPrefixInterface `json:"nlri"`
+ PathAttrs []bgp.PathAttributeInterface `json:"attrs"`
+ }{
+ Nlri: nlri,
+ PathAttrs: pattrs,
+ })
+ return C.CString(string(j))
+}
+
+func main() {
+ // We need the main function to make possible
+ // CGO compiler to compile the package as C shared library
+}
diff --git a/gobgp/main.go b/gobgp/main.go
index feaf3aba..87ad3b17 100644
--- a/gobgp/main.go
+++ b/gobgp/main.go
@@ -16,53 +16,9 @@
package main
import (
- "github.com/osrg/gobgp/api"
- "github.com/spf13/cobra"
+ "github.com/osrg/gobgp/gobgp/cmd"
)
-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"`
- Debug bool `short:"d" long:"debug" description:"use debug"`
- Quiet bool `short:"q" long:"quiet" description:"use quiet"`
- Json bool `short:"j" long:"json" description:"use json format to output format"`
- GenCmpl bool `short:"c" long:"genbashcmpl" description:"use json format to output format"`
- BashCmplFile string
-}
-
-var cmds []string
-var client api.GrpcClient
-
func main() {
- cobra.EnablePrefixMatching = true
- rootCmd := &cobra.Command{
- Use: "gobgp",
- PersistentPreRun: func(cmd *cobra.Command, args []string) {
- if !globalOpts.GenCmpl {
- conn := connGrpc()
- client = api.NewGrpcClient(conn)
- }
- },
- Run: func(cmd *cobra.Command, args []string) {
- cmd.GenBashCompletionFile(globalOpts.BashCmplFile)
- },
- }
-
- rootCmd.PersistentFlags().StringVarP(&globalOpts.Host, "host", "u", "127.0.0.1", "host")
- rootCmd.PersistentFlags().IntVarP(&globalOpts.Port, "port", "p", 8080, "port")
- rootCmd.PersistentFlags().BoolVarP(&globalOpts.Json, "json", "j", false, "use json format to output format")
- rootCmd.PersistentFlags().BoolVarP(&globalOpts.Debug, "debug", "d", false, "use debug")
- rootCmd.PersistentFlags().BoolVarP(&globalOpts.Quiet, "quiet", "q", false, "use quiet")
- rootCmd.PersistentFlags().BoolVarP(&globalOpts.GenCmpl, "gen-cmpl", "c", false, "generate completion file")
- rootCmd.PersistentFlags().StringVarP(&globalOpts.BashCmplFile, "bash-cmpl-file", "", "gobgp_completion.bash", "bash cmpl filename")
-
- globalCmd := NewGlobalCmd()
- neighborCmd := NewNeighborCmd()
- vrfCmd := NewVrfCmd()
- policyCmd := NewPolicyCmd()
- monitorCmd := NewMonitorCmd()
- mrtCmd := NewMrtCmd()
- rpkiCmd := NewRPKICmd()
- rootCmd.AddCommand(globalCmd, neighborCmd, vrfCmd, policyCmd, monitorCmd, mrtCmd, rpkiCmd)
- rootCmd.Execute()
+ cmd.NewRootCmd().Execute()
}