summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gobgp/cmd/common.go14
-rw-r--r--gobgp/cmd/global.go96
-rw-r--r--gobgp/cmd/global_test.go42
3 files changed, 107 insertions, 45 deletions
diff --git a/gobgp/cmd/common.go b/gobgp/cmd/common.go
index a430cbbb..a10460fd 100644
--- a/gobgp/cmd/common.go
+++ b/gobgp/cmd/common.go
@@ -219,6 +219,20 @@ func ApiStruct2Path(p *gobgpapi.Path) ([]*Path, error) {
return paths, nil
}
+type pathAttrs []bgp.PathAttributeInterface
+
+func (p pathAttrs) Len() int {
+ return len(p)
+}
+
+func (p pathAttrs) Swap(i, j int) {
+ p[i], p[j] = p[j], p[i]
+}
+
+func (p pathAttrs) Less(i, j int) bool {
+ return p[i].GetType() < p[j].GetType()
+}
+
type paths []*Path
func (p paths) Len() int {
diff --git a/gobgp/cmd/global.go b/gobgp/cmd/global.go
index 9820124a..add15339 100644
--- a/gobgp/cmd/global.go
+++ b/gobgp/cmd/global.go
@@ -257,9 +257,11 @@ func ParseExtendedCommunities(input string) ([]bgp.ExtendedCommunityInterface, e
continue
}
if i < len(idxs)-1 {
- a = args[idx.i:idxs[i+1].i]
+ a = args[:idxs[i+1].i-idx.i]
+ args = args[(idxs[i+1].i - idx.i):]
} else {
- a = args[idx.i:]
+ a = args
+ args = nil
}
ext, err := f(a)
if err != nil {
@@ -267,6 +269,9 @@ func ParseExtendedCommunities(input string) ([]bgp.ExtendedCommunityInterface, e
}
exts = append(exts, ext...)
}
+ if len(args) > 0 {
+ return nil, fmt.Errorf("failed to parse %v", args)
+ }
return exts, nil
}
@@ -275,6 +280,7 @@ func ParseFlowSpecArgs(rf bgp.RouteFamily, args []string) (bgp.AddrPrefixInterfa
for idx, v := range args {
if v == "then" {
thenPos = idx
+ break
}
}
if len(args) < 4 || args[0] != "match" || thenPos > len(args)-2 {
@@ -300,7 +306,7 @@ func ParseFlowSpecArgs(rf bgp.RouteFamily, args []string) (bgp.AddrPrefixInterfa
var comms table.FlowSpecComponents
comms = fnlri.Value
sort.Sort(comms)
- return nlri, args[thenPos:], nil
+ return nlri, args[thenPos+1:], nil
}
func ParseEvpnMacAdvArgs(args []string) (bgp.AddrPrefixInterface, []string, error) {
@@ -437,7 +443,7 @@ func extractNexthop(rf bgp.RouteFamily, args []string) ([]string, string, error)
return args, nexthop, nil
}
-func extractLocalPref(args []string) ([]string, []byte, error) {
+func extractLocalPref(args []string) ([]string, bgp.PathAttributeInterface, error) {
for idx, arg := range args {
if arg == "local-pref" && len(args) > (idx+1) {
metric, err := strconv.Atoi(args[idx+1])
@@ -445,14 +451,13 @@ func extractLocalPref(args []string) ([]string, []byte, error) {
return nil, nil, err
}
args = append(args[:idx], args[idx+2:]...)
- localPref, _ := bgp.NewPathAttributeLocalPref(uint32(metric)).Serialize()
- return args, localPref, nil
+ return args, bgp.NewPathAttributeLocalPref(uint32(metric)), nil
}
}
return args, nil, nil
}
-func extractMed(args []string) ([]string, []byte, error) {
+func extractMed(args []string) ([]string, bgp.PathAttributeInterface, error) {
for idx, arg := range args {
if arg == "med" && len(args) > (idx+1) {
metric, err := strconv.Atoi(args[idx+1])
@@ -460,14 +465,13 @@ func extractMed(args []string) ([]string, []byte, error) {
return nil, nil, err
}
args = append(args[:idx], args[idx+2:]...)
- med, _ := bgp.NewPathAttributeMultiExitDisc(uint32(metric)).Serialize()
- return args, med, nil
+ return args, bgp.NewPathAttributeMultiExitDisc(uint32(metric)), nil
}
}
return args, nil, nil
}
-func extractAigp(args []string) ([]string, []byte, error) {
+func extractAigp(args []string) ([]string, bgp.PathAttributeInterface, error) {
for idx, arg := range args {
if arg == "aigp" {
if len(args) < (idx + 3) {
@@ -480,7 +484,7 @@ func extractAigp(args []string) ([]string, []byte, error) {
if err != nil {
return nil, nil, err
}
- aigp, _ := bgp.NewPathAttributeAigp([]bgp.AigpTLV{bgp.NewAigpTLVIgpMetric(uint64(metric))}).Serialize()
+ aigp := bgp.NewPathAttributeAigp([]bgp.AigpTLV{bgp.NewAigpTLVIgpMetric(uint64(metric))})
return append(args[:idx], args[idx+3:]...), aigp, nil
default:
return nil, nil, fmt.Errorf("unknown aigp type: %s", typ)
@@ -494,19 +498,43 @@ func ParsePath(rf bgp.RouteFamily, args []string) (*api.Path, error) {
var nlri bgp.AddrPrefixInterface
var extcomms []string
var err error
+ attrs := pathAttrs(make([]bgp.PathAttributeInterface, 0, 1))
path := &api.Path{
Pattrs: make([][]byte, 0),
}
- origin, _ := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE).Serialize()
- path.Pattrs = append(path.Pattrs, origin)
+ attrs = append(attrs, bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE))
args, nexthop, err := extractNexthop(rf, args)
if err != nil {
return nil, err
}
+ args, med, err := extractMed(args)
+ if err != nil {
+ return nil, err
+ }
+ if med != nil {
+ attrs = append(attrs, med)
+ }
+
+ args, localPref, err := extractLocalPref(args)
+ if err != nil {
+ return nil, err
+ }
+ if localPref != nil {
+ attrs = append(attrs, localPref)
+ }
+
+ args, aigp, err := extractAigp(args)
+ if err != nil {
+ return nil, err
+ }
+ if aigp != nil {
+ attrs = append(attrs, aigp)
+ }
+
switch rf {
case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC:
if len(args) < 1 {
@@ -597,29 +625,10 @@ func ParsePath(rf bgp.RouteFamily, args []string) (*api.Path, error) {
if rf == bgp.RF_IPv4_UC {
path.Nlri, _ = nlri.Serialize()
- n, _ := bgp.NewPathAttributeNextHop(nexthop).Serialize()
- path.Pattrs = append(path.Pattrs, n)
+ attrs = append(attrs, bgp.NewPathAttributeNextHop(nexthop))
} else {
- mpreach, _ := bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}).Serialize()
- path.Pattrs = append(path.Pattrs, mpreach)
- }
-
- var med []byte
- args, med, err = extractMed(args)
- if err != nil {
- return nil, err
- }
- if med != nil {
- path.Pattrs = append(path.Pattrs, med)
- }
-
- var localPref []byte
- args, localPref, err = extractLocalPref(args)
- if err != nil {
- return nil, err
- }
- if localPref != nil {
- path.Pattrs = append(path.Pattrs, localPref)
+ mpreach := bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri})
+ attrs = append(attrs, mpreach)
}
if extcomms != nil && len(extcomms) > 0 {
@@ -628,21 +637,18 @@ func ParsePath(rf bgp.RouteFamily, args []string) (*api.Path, error) {
return nil, err
}
p := bgp.NewPathAttributeExtendedCommunities(extcomms)
- buf, err := p.Serialize()
+ attrs = append(attrs, p)
+ }
+
+ sort.Sort(attrs)
+
+ for _, attr := range attrs {
+ buf, err := attr.Serialize()
if err != nil {
return nil, err
}
path.Pattrs = append(path.Pattrs, buf)
}
- var aigp []byte
- args, aigp, err = extractAigp(args)
- if err != nil {
- return nil, err
- }
- if aigp != nil {
- path.Pattrs = append(path.Pattrs, aigp)
- }
-
return path, nil
}
diff --git a/gobgp/cmd/global_test.go b/gobgp/cmd/global_test.go
new file mode 100644
index 00000000..f567b200
--- /dev/null
+++ b/gobgp/cmd/global_test.go
@@ -0,0 +1,42 @@
+// Copyright (C) 2016 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 (
+ "fmt"
+ "github.com/osrg/gobgp/packet"
+ "github.com/stretchr/testify/assert"
+ "strings"
+ "testing"
+)
+
+func Test_ParsePath(t *testing.T) {
+ assert := assert.New(t)
+ buf := "10.0.0.0/24 rt 100:100 med 10 nexthop 10.0.0.1 aigp metric 10 local-pref 100"
+
+ path, err := ParsePath(bgp.RF_IPv4_UC, strings.Split(buf, " "))
+ assert.Nil(err)
+ fmt.Println(path)
+ path.Family = uint32(bgp.RF_IPv4_UC)
+ paths, err := ApiStruct2Path(path)
+ assert.Nil(err)
+ assert.True(len(paths) == 1)
+ i := 0
+ for _, a := range paths[0].PathAttrs {
+ assert.True(i < int(a.GetType()))
+ i = int(a.GetType())
+ }
+}