diff options
-rw-r--r-- | gobgp/cmd/common.go | 14 | ||||
-rw-r--r-- | gobgp/cmd/global.go | 96 | ||||
-rw-r--r-- | gobgp/cmd/global_test.go | 42 |
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()) + } +} |