diff options
-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.go | 68 | ||||
-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.go | 77 | ||||
-rw-r--r-- | gobgp/lib/path.go | 122 | ||||
-rw-r--r-- | gobgp/main.go | 48 |
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() } |