diff options
-rw-r--r-- | api/grpc_server.go | 2 | ||||
-rw-r--r-- | api/util.go | 123 | ||||
-rw-r--r-- | gobgp/cmd/common.go | 103 | ||||
-rw-r--r-- | gobgp/cmd/global_test.go | 5 | ||||
-rw-r--r-- | gobgp/cmd/monitor.go | 6 | ||||
-rw-r--r-- | gobgp/cmd/neighbor.go | 148 | ||||
-rw-r--r-- | openswitch/openswitch.go | 134 | ||||
-rw-r--r-- | table/destination.go | 9 | ||||
-rw-r--r-- | table/path.go | 25 | ||||
-rw-r--r-- | table/table.go | 14 | ||||
-rw-r--r-- | test/lib/gobgp.py | 20 | ||||
-rw-r--r-- | test/scenario_test/bgp_router_test.py | 8 | ||||
-rw-r--r-- | test/scenario_test/graceful_restart_test.py | 2 | ||||
-rw-r--r-- | test/scenario_test/monitor_test.py | 2 |
14 files changed, 311 insertions, 290 deletions
diff --git a/api/grpc_server.go b/api/grpc_server.go index 225c3971..a850100c 100644 --- a/api/grpc_server.go +++ b/api/grpc_server.go @@ -251,7 +251,7 @@ func (s *Server) GetRib(ctx context.Context, arg *GetRibRequest) (*GetRibRespons } dsts := []*Destination{} - for _, dst := range tbl.GetSortedDestinations() { + for _, dst := range tbl.GetDestinations() { dsts = append(dsts, &Destination{ Prefix: dst.GetNlri().String(), Paths: func(paths []*table.Path) []*Path { diff --git a/api/util.go b/api/util.go new file mode 100644 index 00000000..373bad47 --- /dev/null +++ b/api/util.go @@ -0,0 +1,123 @@ +// 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 gobgpapi + +import ( + "fmt" + "net" + "time" + + "github.com/osrg/gobgp/config" + "github.com/osrg/gobgp/packet/bgp" + "github.com/osrg/gobgp/table" +) + +type ToNativeOption struct { + LocalAS uint32 + LocalID net.IP + RouteReflectorClient bool + RouteReflectorClusterID net.IP + NLRI bgp.AddrPrefixInterface +} + +func (t *Table) ToNativeTable(option ...ToNativeOption) (*table.Table, error) { + dsts := make([]*table.Destination, 0, len(t.Destinations)) + for _, d := range t.Destinations { + dst, err := d.ToNativeDestination(option...) + if err != nil { + return nil, err + } + dsts = append(dsts, dst) + } + return table.NewTable(bgp.RouteFamily(t.Family), dsts...), nil +} + +func getNLRI(family bgp.RouteFamily, buf []byte) (bgp.AddrPrefixInterface, error) { + afi, safi := bgp.RouteFamilyToAfiSafi(bgp.RouteFamily(family)) + nlri, err := bgp.NewPrefixFromRouteFamily(afi, safi) + if err != nil { + return nil, err + } + if err := nlri.DecodeFromBytes(buf); err != nil { + return nil, err + } + return nlri, nil +} + +func (d *Destination) ToNativeDestination(option ...ToNativeOption) (*table.Destination, error) { + if len(d.Paths) == 0 { + return nil, fmt.Errorf("no path in destination") + } + nlri, err := getNLRI(bgp.RouteFamily(d.Paths[0].Family), d.Paths[0].Nlri) + if err != nil { + return nil, err + } + option = append(option, ToNativeOption{ + NLRI: nlri, + }) + paths := make([]*table.Path, 0, len(d.Paths)) + for _, p := range d.Paths { + path, err := p.ToNativePath(option...) + if err != nil { + return nil, err + } + paths = append(paths, path) + } + return table.NewDestination(nlri, paths...), nil +} + +func (p *Path) ToNativePath(option ...ToNativeOption) (*table.Path, error) { + info := &table.PeerInfo{ + AS: p.SourceAsn, + ID: net.ParseIP(p.SourceId), + Address: net.ParseIP(p.NeighborIp), + } + var nlri bgp.AddrPrefixInterface + for _, o := range option { + info.LocalAS = o.LocalAS + info.LocalID = o.LocalID + info.RouteReflectorClient = o.RouteReflectorClient + info.RouteReflectorClusterID = o.RouteReflectorClusterID + nlri = o.NLRI + } + if nlri == nil { + var err error + nlri, err = getNLRI(bgp.RouteFamily(p.Family), p.Nlri) + if err != nil { + return nil, err + } + } + pattr := make([]bgp.PathAttributeInterface, 0, len(p.Pattrs)) + for _, attr := range p.Pattrs { + p, err := bgp.GetPathAttribute(attr) + if err != nil { + return nil, err + } + err = p.DecodeFromBytes(attr) + if err != nil { + return nil, err + } + pattr = append(pattr, p) + } + t := time.Unix(p.Age, 0) + path := table.NewPath(info, nlri, p.IsWithdraw, pattr, t, false) + path.SetValidation(config.IntToRpkiValidationResultTypeMap[int(p.Validation)]) + path.MarkStale(p.Stale) + if p.Filtered { + path.Filter("", table.POLICY_DIRECTION_IN) + } + return path, nil +} diff --git a/gobgp/cmd/common.go b/gobgp/cmd/common.go index e1d58b96..09965803 100644 --- a/gobgp/cmd/common.go +++ b/gobgp/cmd/common.go @@ -138,109 +138,6 @@ func cidr2prefix(cidr string) string { return buffer.String()[:ones] } -type Destination struct { - Prefix string `json:"prefix"` - Paths []*Path `json:"paths"` -} - -func ApiStruct2Destination(dst *gobgpapi.Destination) (*Destination, error) { - paths := make([]*Path, 0, len(dst.Paths)) - for _, p := range dst.Paths { - ps, err := ApiStruct2Path(p) - if err != nil { - return nil, err - } - paths = append(paths, ps...) - } - return &Destination{ - Prefix: dst.Prefix, - Paths: paths, - }, nil - -} - -type Path struct { - Nlri bgp.AddrPrefixInterface `json:"nlri"` - PathAttrs []bgp.PathAttributeInterface `json:"attrs"` - Age int64 `json:"age"` - Best bool `json:"best"` - IsWithdraw bool `json:"isWithdraw"` - Validation int32 `json:"validation"` - Filtered bool `json:"filtered"` - SourceId string `json:"source-id"` - NeighborIp string `json:"neighbor-ip"` - Stale bool `json:"stale"` -} - -func ApiStruct2Path(p *gobgpapi.Path) ([]*Path, error) { - nlris := make([]bgp.AddrPrefixInterface, 0, 1) - if len(p.Nlri) == 0 { - return nil, fmt.Errorf("path doesn't have nlri") - } - afi, safi := bgp.RouteFamilyToAfiSafi(bgp.RouteFamily(p.Family)) - nlri, err := bgp.NewPrefixFromRouteFamily(afi, safi) - if err != nil { - return nil, err - } - - if err := nlri.DecodeFromBytes(p.Nlri); err != nil { - return nil, err - } - nlris = append(nlris, nlri) - - pattr := make([]bgp.PathAttributeInterface, 0, len(p.Pattrs)) - for _, attr := range p.Pattrs { - p, err := bgp.GetPathAttribute(attr) - if err != nil { - return nil, err - } - - err = p.DecodeFromBytes(attr) - if err != nil { - return nil, err - } - pattr = append(pattr, p) - } - - paths := make([]*Path, 0, len(nlris)) - for _, nlri := range nlris { - paths = append(paths, &Path{ - Nlri: nlri, - PathAttrs: pattr, - Age: p.Age, - Best: p.Best, - IsWithdraw: p.IsWithdraw, - Validation: p.Validation, - SourceId: p.SourceId, - NeighborIp: p.NeighborIp, - Filtered: p.Filtered, - Stale: p.Stale, - }) - } - return paths, nil -} - -type paths []*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.String() == p[j].Nlri.String() { - if p[i].Best { - return true - } - } - strings := sort.StringSlice{cidr2prefix(p[i].Nlri.String()), - cidr2prefix(p[j].Nlri.String())} - return strings.Less(0, 1) -} - func extractReserved(args, keys []string) map[string][]string { m := make(map[string][]string, len(keys)) var k string diff --git a/gobgp/cmd/global_test.go b/gobgp/cmd/global_test.go index 8dc8171c..c41f4c56 100644 --- a/gobgp/cmd/global_test.go +++ b/gobgp/cmd/global_test.go @@ -31,11 +31,10 @@ func Test_ParsePath(t *testing.T) { assert.Nil(err) fmt.Println(path) path.Family = uint32(bgp.RF_IPv4_UC) - paths, err := ApiStruct2Path(path) + p, err := path.ToNativePath() assert.Nil(err) - assert.True(len(paths) == 1) i := 0 - for _, a := range paths[0].PathAttrs { + for _, a := range p.GetPathAttrs() { assert.True(i < int(a.GetType())) i = int(a.GetType()) } diff --git a/gobgp/cmd/monitor.go b/gobgp/cmd/monitor.go index 4cb95ece..dd45901e 100644 --- a/gobgp/cmd/monitor.go +++ b/gobgp/cmd/monitor.go @@ -40,16 +40,16 @@ func NewMonitorCmd() *cobra.Command { } else if err != nil { exitWithError(err) } - p, err := ApiStruct2Path(d.Paths[0]) + dst, err := d.ToNativeDestination() if err != nil { exitWithError(err) } if globalOpts.Json { - j, _ := json.Marshal(p) + j, _ := json.Marshal(dst.GetAllKnownPathList()) fmt.Println(string(j)) } else { - ShowRoute(p, false, false, false, true, false) + ShowRoute(dst.GetAllKnownPathList(), false, false, false, true, false) } } } diff --git a/gobgp/cmd/neighbor.go b/gobgp/cmd/neighbor.go index 43c4a8aa..4def24ec 100644 --- a/gobgp/cmd/neighbor.go +++ b/gobgp/cmd/neighbor.go @@ -21,6 +21,7 @@ import ( api "github.com/osrg/gobgp/api" "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet/bgp" + "github.com/osrg/gobgp/table" "github.com/spf13/cobra" "golang.org/x/net/context" "net" @@ -310,7 +311,7 @@ type AsPathFormat struct { separator string } -func ShowRoute(pathList []*Path, showAge, showBest, showLabel, isMonitor, printHeader bool) { +func ShowRoute(pathList []*table.Path, showAge, showBest, showLabel, isMonitor, printHeader bool) { var pathStrs [][]interface{} maxPrefixLen := 20 @@ -319,25 +320,17 @@ func ShowRoute(pathList []*Path, showAge, showBest, showLabel, isMonitor, printH maxLabelLen := 10 now := time.Now() - for _, p := range pathList { - var nexthop string - var aspathstr string + for idx, p := range pathList { + nexthop := "fictitious" + if n := p.GetNexthop(); n != nil { + nexthop = p.GetNexthop().String() + } + aspathstr := p.GetAsString() s := []string{} - for _, a := range p.PathAttrs { + for _, a := range p.GetPathAttrs() { switch a.GetType() { - case bgp.BGP_ATTR_TYPE_NEXT_HOP: - nexthop = a.(*bgp.PathAttributeNextHop).Value.String() - case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: - n := a.(*bgp.PathAttributeMpReachNLRI).Nexthop - if n != nil { - nexthop = n.String() - } else { - nexthop = "fictitious" - } - case bgp.BGP_ATTR_TYPE_AS_PATH: - aspathstr = a.String() - case bgp.BGP_ATTR_TYPE_AS4_PATH: + case bgp.BGP_ATTR_TYPE_NEXT_HOP, bgp.BGP_ATTR_TYPE_MP_REACH_NLRI, bgp.BGP_ATTR_TYPE_AS_PATH, bgp.BGP_ATTR_TYPE_AS4_PATH: continue default: s = append(s, a.String()) @@ -354,27 +347,27 @@ func ShowRoute(pathList []*Path, showAge, showBest, showLabel, isMonitor, printH } best := "" - if p.Stale { + if p.IsStale() { best += "S" } - switch int(p.Validation) { - case config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND.ToInt(): + switch p.Validation() { + case config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND: best += "N" - case config.RPKI_VALIDATION_RESULT_TYPE_VALID.ToInt(): + case config.RPKI_VALIDATION_RESULT_TYPE_VALID: best += "V" - case config.RPKI_VALIDATION_RESULT_TYPE_INVALID.ToInt(): + case config.RPKI_VALIDATION_RESULT_TYPE_INVALID: best += "I" } if showBest { - if p.Best { + if idx == 0 { best += "*>" } else { best += "* " } } - nlri := p.Nlri.String() - if maxPrefixLen < len(nlri) { - maxPrefixLen = len(nlri) + nlri := p.GetNlri() + if maxPrefixLen < len(nlri.String()) { + maxPrefixLen = len(nlri.String()) } if isMonitor { @@ -387,15 +380,15 @@ func ShowRoute(pathList []*Path, showAge, showBest, showLabel, isMonitor, printH args := []interface{}{best, nlri} if showLabel { label := "" - switch p.Nlri.(type) { + switch nlri.(type) { case *bgp.LabeledIPAddrPrefix: - label = p.Nlri.(*bgp.LabeledIPAddrPrefix).Labels.String() + label = nlri.(*bgp.LabeledIPAddrPrefix).Labels.String() case *bgp.LabeledIPv6AddrPrefix: - label = p.Nlri.(*bgp.LabeledIPv6AddrPrefix).Labels.String() + label = nlri.(*bgp.LabeledIPv6AddrPrefix).Labels.String() case *bgp.LabeledVPNIPAddrPrefix: - label = p.Nlri.(*bgp.LabeledVPNIPAddrPrefix).Labels.String() + label = nlri.(*bgp.LabeledVPNIPAddrPrefix).Labels.String() case *bgp.LabeledVPNIPv6AddrPrefix: - label = p.Nlri.(*bgp.LabeledVPNIPv6AddrPrefix).Labels.String() + label = nlri.(*bgp.LabeledVPNIPv6AddrPrefix).Labels.String() } if maxLabelLen < len(label) { maxLabelLen = len(label) @@ -404,7 +397,7 @@ func ShowRoute(pathList []*Path, showAge, showBest, showLabel, isMonitor, printH } args = append(args, []interface{}{nexthop, aspathstr}...) if showAge { - args = append(args, formatTimedelta(int64(now.Sub(time.Unix(int64(p.Age), 0)).Seconds()))) + args = append(args, formatTimedelta(int64(now.Sub(p.GetTimestamp()).Seconds()))) } args = append(args, pattrstr) pathStrs = append(pathStrs, args) @@ -514,10 +507,9 @@ func showNeighborRib(r string, name string, args []string) error { if err != nil { return err } - rib := rsp.Table switch r { case CMD_LOCAL, CMD_ADJ_IN, CMD_ACCEPTED, CMD_REJECTED, CMD_ADJ_OUT: - if len(rib.Destinations) == 0 { + if len(rsp.Table.Destinations) == 0 { peer, err := getNeighbor(name) if err != nil { return err @@ -528,84 +520,48 @@ func showNeighborRib(r string, name string, args []string) error { } } - isResultSorted := func(rf bgp.RouteFamily) bool { - switch rf { - case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC, bgp.RF_FS_IPv4_UC, bgp.RF_FS_IPv6_UC, bgp.RF_FS_IPv4_VPN, bgp.RF_FS_IPv6_VPN, bgp.RF_FS_L2_VPN: - return true - } - return false + rib, err := rsp.Table.ToNativeTable() + if err != nil { + return err + } + + if globalOpts.Json { + j, _ := json.Marshal(rib.GetDestinations()) + fmt.Println(string(j)) + return nil } - dsts := []*Destination{} counter := 0 - for _, d := range rib.Destinations { - dst, err := ApiStruct2Destination(d) - if err != nil { - return err - } - if isResultSorted(rf) && !globalOpts.Json && len(dst.Paths) > 0 { - ps := paths{} - for _, p := range dst.Paths { + for _, d := range rib.GetSortedDestinations() { + var ps []*table.Path + if r == CMD_ACCEPTED || r == CMD_REJECTED { + for _, p := range d.GetAllKnownPathList() { switch r { case CMD_ACCEPTED: - if !p.Filtered { - ps = append(ps, p) + if p.Filtered("") > table.POLICY_DIRECTION_NONE { + continue } case CMD_REJECTED: - if p.Filtered { - ps = append(ps, p) + if p.Filtered("") == table.POLICY_DIRECTION_NONE { + continue } - default: - ps = append(ps, p) } - } - sort.Sort(ps) - if counter == 0 { - ShowRoute(ps, showAge, showBest, showLabel, false, true) - } else { - ShowRoute(ps, showAge, showBest, showLabel, false, false) - } - counter++ - } - dsts = append(dsts, dst) - } - - if globalOpts.Json { - j, _ := json.Marshal(dsts) - fmt.Println(string(j)) - return nil - } - - if isResultSorted(rf) && counter != 0 { - // we already showed - return nil - } - - ps := paths{} - for _, dst := range dsts { - for _, p := range dst.Paths { - switch r { - case CMD_ACCEPTED: - if !p.Filtered { - ps = append(ps, p) - } - case CMD_REJECTED: - if p.Filtered { - ps = append(ps, p) - } - default: ps = append(ps, p) } + } else { + ps = d.GetAllKnownPathList() } + if counter == 0 { + ShowRoute(ps, showAge, showBest, showLabel, false, true) + } else { + ShowRoute(ps, showAge, showBest, showLabel, false, false) + } + counter++ } - if len(ps) == 0 { + if counter == 0 { fmt.Println("Network not in table") - return nil } - - sort.Sort(ps) - ShowRoute(ps, showAge, showBest, showLabel, false, true) return nil } diff --git a/openswitch/openswitch.go b/openswitch/openswitch.go index 4f6d7e0c..7641a9b2 100644 --- a/openswitch/openswitch.go +++ b/openswitch/openswitch.go @@ -24,8 +24,8 @@ import ( log "github.com/Sirupsen/logrus" api "github.com/osrg/gobgp/api" - "github.com/osrg/gobgp/gobgp/cmd" "github.com/osrg/gobgp/packet/bgp" + "github.com/osrg/gobgp/table" "github.com/satori/go.uuid" ovsdb "github.com/socketplane/libovsdb" "golang.org/x/net/context" @@ -403,63 +403,60 @@ func (m *OpsManager) handleRouteUpdate(cli api.GobgpApiClient, update ovsdb.Tabl } } -func parseRouteToOps(pl []*cmd.Path) (map[string]interface{}, bool, error) { +func parseRouteToOps(p *table.Path) (map[string]interface{}, bool, error) { route := map[string]interface{}{"metric": 0, "peer": "Remote announcement"} IsWithdraw := false - for _, p := range pl { - var nexthop string - pathAttr := map[string]string{"BGP_iBGP": "false", - "BGP_flags": "16", - "BGP_internal": "false", - "BGP_loc_pref": "0", - "IsFromGobgp": "true", - } - for _, a := range p.PathAttrs { - switch a.GetType() { - case bgp.BGP_ATTR_TYPE_NEXT_HOP: - nexthop = a.(*bgp.PathAttributeNextHop).Value.String() - case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: - n := a.(*bgp.PathAttributeMpReachNLRI).Nexthop - if n != nil { - nexthop = n.String() - } else { - nexthop = "" - } - case bgp.BGP_ATTR_TYPE_AS_PATH: - pathAttr["BGP_AS_path"] = a.(*bgp.PathAttributeAsPath).String() - case bgp.BGP_ATTR_TYPE_ORIGIN: - origin := "-" - switch a.(*bgp.PathAttributeOrigin).Value[0] { - case bgp.BGP_ORIGIN_ATTR_TYPE_IGP: - origin = "i" - case bgp.BGP_ORIGIN_ATTR_TYPE_EGP: - origin = "e" - case bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE: - origin = "?" - } - pathAttr["BGP_origin"] = origin - case bgp.BGP_ATTR_TYPE_LOCAL_PREF: - pathAttr["BGP_loc_pref"] = fmt.Sprintf("%v", a.(*bgp.PathAttributeLocalPref).Value) - case bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC: - route["metric"] = a.(*bgp.PathAttributeMultiExitDisc).Value - default: - continue + var nexthop string + pathAttr := map[string]string{"BGP_iBGP": "false", + "BGP_flags": "16", + "BGP_internal": "false", + "BGP_loc_pref": "0", + "IsFromGobgp": "true", + } + for _, a := range p.GetPathAttrs() { + switch a.GetType() { + case bgp.BGP_ATTR_TYPE_NEXT_HOP: + nexthop = a.(*bgp.PathAttributeNextHop).Value.String() + case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: + n := a.(*bgp.PathAttributeMpReachNLRI).Nexthop + if n != nil { + nexthop = n.String() + } else { + nexthop = "" } + case bgp.BGP_ATTR_TYPE_AS_PATH: + pathAttr["BGP_AS_path"] = a.(*bgp.PathAttributeAsPath).String() + case bgp.BGP_ATTR_TYPE_ORIGIN: + origin := "-" + switch a.(*bgp.PathAttributeOrigin).Value[0] { + case bgp.BGP_ORIGIN_ATTR_TYPE_IGP: + origin = "i" + case bgp.BGP_ORIGIN_ATTR_TYPE_EGP: + origin = "e" + case bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE: + origin = "?" + } + pathAttr["BGP_origin"] = origin + case bgp.BGP_ATTR_TYPE_LOCAL_PREF: + pathAttr["BGP_loc_pref"] = fmt.Sprintf("%v", a.(*bgp.PathAttributeLocalPref).Value) + case bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC: + route["metric"] = a.(*bgp.PathAttributeMultiExitDisc).Value + default: + continue } - IsWithdraw = p.IsWithdraw - afi := "ipv4" - if p.Nlri.AFI() != bgp.AFI_IP { - afi = "ipv6" - } - safi := "unicast" - - route["prefix"] = p.Nlri.String() - route["address_family"] = afi - route["sub_address_family"] = safi - route["bgp_nexthops"] = nexthop - route["path_attributes"] = pathAttr - break } + IsWithdraw = p.IsWithdraw + afi := "ipv4" + if p.GetNlri().AFI() != bgp.AFI_IP { + afi = "ipv6" + } + safi := "unicast" + + route["prefix"] = p.GetNlri().String() + route["address_family"] = afi + route["sub_address_family"] = safi + route["bgp_nexthops"] = nexthop + route["path_attributes"] = pathAttr return route, IsWithdraw, nil } @@ -512,7 +509,7 @@ func deleteRoute(opsRoute map[string]interface{}) ovsdb.Operation { return deleteOp } -func (m *OpsManager) TransactPreparation(p []*cmd.Path) (*OpsOperation, error) { +func (m *OpsManager) TransactPreparation(p *table.Path) (*OpsOperation, error) { v, err := m.getVrfUUID() if err != nil { return nil, err @@ -571,25 +568,38 @@ func (m *OpsManager) GobgpMonitor(target string) { log.Fatal(err) } cli := api.NewGobgpApiClient(conn) + rsp, err := cli.GetServer(context.Background(), &api.GetServerRequest{}) + if err != nil { + log.Fatal(err) + } + nativeOption := api.ToNativeOption{ + LocalAS: uint32(rsp.Global.As), + LocalID: net.ParseIP(rsp.Global.RouterId), + } stream, err := cli.MonitorRib(context.Background(), &api.Table{ Type: api.Resource_GLOBAL, Family: uint32(bgp.RF_IPv4_UC), }) + if err != nil { + log.Fatal(err) + } for { d, err := stream.Recv() - bPath := d.Paths[0] - if bPath.IsFromExternal && !bPath.IsWithdraw { - continue + if err != nil { + log.Fatal(err) } - p, err := cmd.ApiStruct2Path(bPath) + dst, err := d.ToNativeDestination(nativeOption) if err != nil { log.WithFields(log.Fields{ "Topic": "openswitch", - "Type": "MonitorRequest", - "Error": err, - }).Error("failed parse path of gobgp") + }).Error(err) + continue + } + path := dst.GetAllKnownPathList()[0] + if path.IsLocal() && !path.IsWithdraw { + continue } - o, err := m.TransactPreparation(p) + o, err := m.TransactPreparation(path) if err != nil { log.WithFields(log.Fields{ "Topic": "openswitch", diff --git a/table/destination.go b/table/destination.go index 7e0deb2b..3a1c1c45 100644 --- a/table/destination.go +++ b/table/destination.go @@ -18,6 +18,7 @@ package table import ( "bytes" "encoding/binary" + "encoding/json" "fmt" "net" "sort" @@ -124,11 +125,11 @@ type Destination struct { RadixKey string } -func NewDestination(nlri bgp.AddrPrefixInterface) *Destination { +func NewDestination(nlri bgp.AddrPrefixInterface, known ...*Path) *Destination { d := &Destination{ routeFamily: bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI()), nlri: nlri, - knownPathList: make([]*Path, 0), + knownPathList: known, withdrawList: make([]*Path, 0), newPathList: make([]*Path, 0), } @@ -856,6 +857,10 @@ type DestinationSelectOption struct { adj bool } +func (d *Destination) MarshalJSON() ([]byte, error) { + return json.Marshal(d.GetAllKnownPathList()) +} + func (old *Destination) Select(option ...DestinationSelectOption) *Destination { id := GLOBAL_RIB_NAME var vrf *Vrf diff --git a/table/path.go b/table/path.go index c75ca579..0aab6004 100644 --- a/table/path.go +++ b/table/path.go @@ -17,6 +17,7 @@ package table import ( "bytes" + "encoding/json" "fmt" "math" "net" @@ -845,6 +846,30 @@ func (lhs *Path) Equal(rhs *Path) bool { return bytes.Equal(pattrs(lhs.GetPathAttrs()), pattrs(rhs.GetPathAttrs())) } +func (path *Path) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Nlri bgp.AddrPrefixInterface `json:"nlri"` + PathAttrs []bgp.PathAttributeInterface `json:"attrs"` + Age int64 `json:"age"` + Withdrawal bool `json:"withdrawal,omitempty"` + Validation string `json:"validation,omitempty"` + SourceID net.IP `json:"source-id,omitempty"` + NeighborIP net.IP `json:"neighbor-ip,omitempty"` + Stale bool `json:"stale,omitempty"` + Filtered bool `json:"filtered,omitempty"` + }{ + Nlri: path.GetNlri(), + PathAttrs: path.GetPathAttrs(), + Age: path.GetTimestamp().Unix(), + Withdrawal: path.IsWithdraw, + Validation: string(path.Validation()), + SourceID: path.GetSource().ID, + NeighborIP: path.GetSource().Address, + Stale: path.IsStale(), + Filtered: path.Filtered("") > POLICY_DIRECTION_NONE, + }) +} + func (lhs *Path) Compare(rhs *Path) int { if lhs.IsLocal() && !rhs.IsLocal() { return 1 diff --git a/table/table.go b/table/table.go index bad0e824..f89e8dff 100644 --- a/table/table.go +++ b/table/table.go @@ -50,10 +50,14 @@ type Table struct { destinations map[string]*Destination } -func NewTable(rf bgp.RouteFamily) *Table { +func NewTable(rf bgp.RouteFamily, dsts ...*Destination) *Table { + destinations := make(map[string]*Destination) + for _, dst := range dsts { + destinations[dst.GetNlri().String()] = dst + } return &Table{ routeFamily: rf, - destinations: make(map[string]*Destination), + destinations: destinations, } } @@ -229,15 +233,11 @@ func (t *Table) GetSortedDestinations() []*Destination { results = append(results, v.(*Destination)) return false }) - case bgp.RF_FS_IPv4_UC, bgp.RF_FS_IPv6_UC, bgp.RF_FS_IPv4_VPN, bgp.RF_FS_IPv6_VPN, bgp.RF_FS_L2_VPN: - for _, dst := range t.GetDestinations() { - results = append(results, dst) - } - sort.Sort(destinations(results)) default: for _, dst := range t.GetDestinations() { results = append(results, dst) } + sort.Sort(destinations(results)) } return results } diff --git a/test/lib/gobgp.py b/test/lib/gobgp.py index d16610f0..316e8535 100644 --- a/test/lib/gobgp.py +++ b/test/lib/gobgp.py @@ -121,23 +121,29 @@ class GoBGPContainer(BGPContainer): cmd = 'gobgp -j neighbor {0} local {1} -a {2}'.format(peer_addr, prefix, rf) output = self.local(cmd, capture=True) ret = json.loads(output) - for d in ret: - for p in d["paths"]: + dsts = [] + for k, v in ret.iteritems(): + for p in v: p["nexthop"] = self._get_nexthop(p) p["aspath"] = self._get_as_path(p) p["local-pref"] = self._get_local_pref(p) - return ret + p["prefix"] = k + dsts.append({'paths': v, 'prefix': k}) + return dsts def get_global_rib(self, prefix='', rf='ipv4'): cmd = 'gobgp -j global rib {0} -a {1}'.format(prefix, rf) output = self.local(cmd, capture=True) ret = json.loads(output) - for d in ret: - for p in d["paths"]: + dsts = [] + for k, v in ret.iteritems(): + for p in v: p["nexthop"] = self._get_nexthop(p) p["aspath"] = self._get_as_path(p) p["local-pref"] = self._get_local_pref(p) - return ret + p["prefix"] = k + dsts.append({'paths': v, 'prefix': k}) + return dsts def monitor_global_rib(self, queue, rf='ipv4'): host = self.ip_addrs[0][1].split('/')[0] @@ -168,7 +174,7 @@ class GoBGPContainer(BGPContainer): adj_type, prefix, rf) output = self.local(cmd, capture=True) - ret = [p["paths"][0] for p in json.loads(output)] + ret = [p[0] for p in json.loads(output).itervalues()] for p in ret: p["nexthop"] = self._get_nexthop(p) p["aspath"] = self._get_as_path(p) diff --git a/test/scenario_test/bgp_router_test.py b/test/scenario_test/bgp_router_test.py index f6831f79..3154df21 100644 --- a/test/scenario_test/bgp_router_test.py +++ b/test/scenario_test/bgp_router_test.py @@ -333,10 +333,10 @@ class GoBGPTestBase(unittest.TestCase): paths = g1.get_adj_rib_out(q1, '30.0.0.0/24') self.assertTrue(len(paths) == 1) - self.assertTrue(paths[0]['source-id'] == '<nil>') + self.assertTrue('source-id' not in paths[0]) paths = g1.get_adj_rib_out(q2, '30.0.0.0/24') self.assertTrue(len(paths) == 1) - self.assertTrue(paths[0]['source-id'] == '<nil>') + self.assertTrue('source-id' not in paths[0]) g1.local('gobgp global rib del 30.0.0.0/24') @@ -405,8 +405,8 @@ class GoBGPTestBase(unittest.TestCase): cnt2 = 0 g = next_prefix() n = g.next() - for path in g1.get_global_rib(): - if path['prefix'] == n: + for path in g1.local("gobgp global rib", capture=True).split('\n')[1:]: + if [elem for elem in path.split(' ') if elem != ''][1] == n: try: cnt2 += 1 n = g.next() diff --git a/test/scenario_test/graceful_restart_test.py b/test/scenario_test/graceful_restart_test.py index 9b97b82b..6f0f4211 100644 --- a/test/scenario_test/graceful_restart_test.py +++ b/test/scenario_test/graceful_restart_test.py @@ -82,7 +82,7 @@ class GoBGPTestBase(unittest.TestCase): self.assertTrue(len(g2.get_global_rib('10.10.10.0/24')) == 0) for d in g2.get_global_rib(): for p in d['paths']: - self.assertFalse(p['stale']) + self.assertFalse(p.get('stale', False)) def test_04_add_non_graceful_restart_enabled_peer(self): g1 = self.bgpds['g1'] diff --git a/test/scenario_test/monitor_test.py b/test/scenario_test/monitor_test.py index 147391d1..4c5df7c1 100644 --- a/test/scenario_test/monitor_test.py +++ b/test/scenario_test/monitor_test.py @@ -87,7 +87,7 @@ class GoBGPTestBase(unittest.TestCase): while True: info = qu.get(timeout=120) print 'monitor got {0}'.format(info) - self.assertTrue(info['isWithdraw']) + self.assertTrue(info['withdrawal']) break |