Skip to content

Commit

Permalink
l3 plugin dumps ipv4 and ipv6 routes
Browse files Browse the repository at this point in the history
Signed-off-by: Vladimir Lavor <[email protected]>
  • Loading branch information
VladoLavor committed Jul 9, 2019
1 parent 6c0c502 commit 1e2154d
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 39 deletions.
2 changes: 1 addition & 1 deletion plugins/vpp/l3plugin/descriptor/vrf_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (d *VrfTableDescriptor) EquivalentVrfTables(key string, oldVrfTable, newVrf
return true
}

// MetadataFactory is a factory for index-map customized for VRFss.
// MetadataFactory is a factory for index-map customized for VRFs.
func (d *VrfTableDescriptor) MetadataFactory() idxmap.NamedMappingRW {
return vrfidx.NewVRFIndex(d.log, "vpp-vrf-index")
}
Expand Down
82 changes: 73 additions & 9 deletions plugins/vpp/l3plugin/vppcalls/vpp1908/route_dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,48 @@ import (
)

// DumpRoutes implements route handler.
func (h *RouteHandler) DumpRoutes() ([]*vppcalls.RouteDetails, error) {
var routes []*vppcalls.RouteDetails
// Dump IPv4 l3 FIB.
reqCtx := h.callsChannel.SendMultiRequest(&l3binapi.IPRouteDump{})
func (h *RouteHandler) DumpRoutes() (routes []*vppcalls.RouteDetails, err error) {
// dump routes for every VRF and for both IP versions
for _, vrfID := range h.vrfIndexes.ListAllVrfIDs() {
// IPv6
ipv6Routes, err := h.dumpRoutesForVrfAndIP(vrfID, true)
if err != nil {
return nil, err
}
routes = append(routes, ipv6Routes...)
// IPv4
ipv4Routes, err := h.dumpRoutesForVrfAndIP(vrfID, false)
if err != nil {
return nil, err
}
routes = append(routes, ipv4Routes...)

}
return routes, nil
}

// dumpRoutesForVrf returns routes for given VRF and IP versiob
func (h *RouteHandler) dumpRoutesForVrfAndIP(vrfID uint32, isIPv6 bool) (routes []*vppcalls.RouteDetails, err error) {
reqCtx := h.callsChannel.SendMultiRequest(&l3binapi.IPRouteDump{
Table: l3binapi.IPTable{
TableID: vrfID,
IsIP6: boolToUint(isIPv6),
},
})
for {
fibDetails := &l3binapi.IPRouteDetails{}
stop, err := reqCtx.ReceiveReply(fibDetails)
if stop {
break
}
if err != nil {
return nil, err
return routes, err
}
ipv4Route, err := h.dumpRouteIPDetails(fibDetails.Route)
ipRoute, err := h.dumpRouteIPDetails(fibDetails.Route)
if err != nil {
return nil, err
return routes, err
}
routes = append(routes, ipv4Route...)
routes = append(routes, ipRoute...)
}

return routes, nil
Expand All @@ -53,10 +77,13 @@ func (h *RouteHandler) dumpRouteIPDetails(ipRoute l3binapi.IPRoute) ([]*vppcalls
// Common fields for every route path (destination IP, VRF)
var dstIP string
netIP := make([]byte, 16)
copy(netIP[:], ipRoute.Prefix.Address.Un.XXX_UnionData[:])
if ipRoute.Prefix.Address.Af == l3binapi.ADDRESS_IP6 {
ip6Addr := ipRoute.Prefix.Address.Un.GetIP6()
copy(netIP[:], ip6Addr[:])
dstIP = fmt.Sprintf("%s/%d", net.IP(netIP).To16().String(), uint32(ipRoute.Prefix.Len))
} else {
ip4Addr := ipRoute.Prefix.Address.Un.GetIP4()
copy(netIP[:], ip4Addr[:])
dstIP = fmt.Sprintf("%s/%d", net.IP(netIP[:4]).To4().String(), uint32(ipRoute.Prefix.Len))
}

Expand Down Expand Up @@ -126,9 +153,19 @@ func (h *RouteHandler) dumpRouteIPDetails(ipRoute l3binapi.IPRoute) ([]*vppcalls
// Route metadata
meta := &vppcalls.RouteMeta{
OutgoingIfIdx: ifIdx,
IsIPv6: path.Proto == l3binapi.FIB_API_PATH_NH_PROTO_IP6,
NextHopID: path.Nh.ObjID,
RpfID: path.RpfID,
LabelStack: labelStack,
}
resolvePathType(meta, path.Type)
resolvePathFlags(meta, path.Flags)
// Note: VPP does not return table name as in older versions, the field
// is filled using index map
vrfName, _, exists := h.vrfIndexes.LookupByVRFIndex(ipRoute.TableID)
if exists {
meta.TableName = vrfName
}

routeDetails = append(routeDetails, &vppcalls.RouteDetails{
Route: route,
Expand All @@ -137,6 +174,7 @@ func (h *RouteHandler) dumpRouteIPDetails(ipRoute l3binapi.IPRoute) ([]*vppcalls
}
} else {
// Return route without path fields, but this is not a valid configuration
h.log.Warnf("Route with destination IP %s (VRF %d) has no path specified", dstIP, ipRoute.TableID)
routeDetails = append(routeDetails, &vppcalls.RouteDetails{
Route: &l3.Route{
Type: l3.Route_INTRA_VRF, // default
Expand All @@ -148,3 +186,29 @@ func (h *RouteHandler) dumpRouteIPDetails(ipRoute l3binapi.IPRoute) ([]*vppcalls

return routeDetails, nil
}

func resolvePathType(meta *vppcalls.RouteMeta, pathType l3binapi.FibPathType) {
switch pathType {
case l3binapi.FIB_API_PATH_TYPE_LOCAL:
meta.IsLocal = true
case l3binapi.FIB_API_PATH_TYPE_UDP_ENCAP:
meta.IsUDPEncap = true
case l3binapi.FIB_API_PATH_TYPE_ICMP_UNREACH:
meta.IsUnreach = true
case l3binapi.FIB_API_PATH_TYPE_ICMP_PROHIBIT:
meta.IsProhibit = true
case l3binapi.FIB_API_PATH_TYPE_DVR:
meta.IsDvr = true
case l3binapi.FIB_API_PATH_TYPE_SOURCE_LOOKUP:
meta.IsSourceLookup = true
}
}

func resolvePathFlags(meta *vppcalls.RouteMeta, pathFlags l3binapi.FibPathFlags) {
switch pathFlags {
case l3binapi.FIB_API_PATH_FLAG_RESOLVE_VIA_HOST:
meta.IsResolveHost = true
case l3binapi.FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED:
meta.IsResolveAttached = true
}
}
35 changes: 20 additions & 15 deletions plugins/vpp/l3plugin/vppcalls/vpp1908/route_dump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package vpp1908
import (
"testing"

"github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vrfidx"

"github.com/ligato/cn-infra/logging/logrus"
"github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1908/ip"
"github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1908/vpe"
Expand All @@ -29,9 +31,11 @@ import (
func TestDumpStaticRoutes(t *testing.T) {
ctx := vppcallmock.SetupTestCtx(t)
defer ctx.TeardownTestCtx()
ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test"), "test")
l3handler := NewRouteVppHandler(ctx.MockChannel, ifIndexes, logrus.DefaultLogger())
ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test-if"), "test-if")
vrfIndexes := vrfidx.NewVRFIndex(logrus.NewLogger("test-vrf"), "test-vrf")
l3handler := NewRouteVppHandler(ctx.MockChannel, ifIndexes, vrfIndexes, logrus.DefaultLogger())

vrfIndexes.Put("vrf1", &vrfidx.VRFMetadata{Index: 0})
ifIndexes.Put("if1", &ifaceidx.IfaceMetadata{SwIfIndex: 1})
ifIndexes.Put("if2", &ifaceidx.IfaceMetadata{SwIfIndex: 2})

Expand All @@ -49,22 +53,23 @@ func TestDumpStaticRoutes(t *testing.T) {
},
},
},
},
&ip.IPRouteDetails{
Route: ip.IPRoute{
Prefix: ip.Prefix{
Address: ip.Address{
Af: ip.ADDRESS_IP6,
Un: ip.AddressUnionIP6([16]uint8{255, 255, 10, 1}),
},
})
ctx.MockVpp.MockReply(&vpe.ControlPingReply{})
ctx.MockVpp.MockReply(&ip.IPRouteDetails{
Route: ip.IPRoute{
Prefix: ip.Prefix{
Address: ip.Address{
Af: ip.ADDRESS_IP6,
Un: ip.AddressUnionIP6([16]uint8{255, 255, 10, 1}),
},
Paths: []ip.FibPath{
{
SwIfIndex: 1,
},
},
Paths: []ip.FibPath{
{
SwIfIndex: 1,
},
},
})
},
})
ctx.MockVpp.MockReply(&vpe.ControlPingReply{})

rtDetails, err := l3handler.DumpRoutes()
Expand Down
7 changes: 5 additions & 2 deletions plugins/vpp/l3plugin/vppcalls/vpp1908/route_vppcalls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package vpp1908_test
import (
"testing"

"github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vrfidx"

"github.com/ligato/cn-infra/logging/logrus"
l3 "github.com/ligato/vpp-agent/api/models/vpp/l3"
"github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1908/ip"
Expand Down Expand Up @@ -85,10 +87,11 @@ func routeTestSetup(t *testing.T) (*vppcallmock.TestCtx, ifvppcalls.InterfaceVpp
ctx := vppcallmock.SetupTestCtx(t)
log := logrus.NewLogger("test-log")
ifHandler := ifvpp1908.NewInterfaceVppHandler(ctx.MockChannel, log)
ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test"), "test")
ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test-if"), "test-if")
vrfIndexes := vrfidx.NewVRFIndex(logrus.NewLogger("test-vrf"), "test-vrf")
ifIndexes.Put("iface1", &ifaceidx.IfaceMetadata{
SwIfIndex: 1,
})
rtHandler := vpp1908.NewRouteVppHandler(ctx.MockChannel, ifIndexes, log)
rtHandler := vpp1908.NewRouteVppHandler(ctx.MockChannel, ifIndexes, vrfIndexes, log)
return ctx, ifHandler, rtHandler
}
39 changes: 27 additions & 12 deletions plugins/vpp/l3plugin/vrfidx/vrfidx.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ type VRFMetadataIndex interface {
// ListAllVRFs returns slice of labels of all VRFs in the mapping.
ListAllVRFs() (names []string)

// ListAllVrfIDs returns a list of VRF indexes read from VRF metadata.
ListAllVrfIDs() (idList []uint32)

// WatchVRFs allows to subscribe to watch for changes in the VRF mapping.
WatchVRFs(subscriber string, channel chan<- VRFMetadataDto)
}
Expand All @@ -54,7 +57,7 @@ type VRFMetadataIndexRW interface {

// VRFMetadata collects metadata for VPP VRF used in secondary lookups.
type VRFMetadata struct {
Index uint32
Index uint32
}

// GetIndex returns VRF index.
Expand Down Expand Up @@ -92,8 +95,8 @@ func NewVRFIndex(logger logging.Logger, title string) VRFMetadataIndexRW {
// identified by <label>. If there is no VRF associated with the given
// name in the mapping, the <exists> is returned as *false* and <metadata>
// as *nil*.
func (vfrm *vrfMetadataIndex) LookupByName(name string) (metadata *VRFMetadata, exists bool) {
meta, found := vfrm.GetValue(name)
func (m *vrfMetadataIndex) LookupByName(name string) (metadata *VRFMetadata, exists bool) {
meta, found := m.GetValue(name)
if found {
if typedMeta, ok := meta.(*VRFMetadata); ok {
return typedMeta, found
Expand All @@ -102,13 +105,13 @@ func (vfrm *vrfMetadataIndex) LookupByName(name string) (metadata *VRFMetadata,
return nil, false
}

// LookupByIndex retrieves a previously stored VRF identified in
// LookupByVRFIndex retrieves a previously stored VRF identified in
// VPP by the given/ <index>.
// If there is no VRF associated with the given index, <exists> is returned
// as *false* with <name> and <metadata> both set to empty values.
func (vrfm *vrfMetadataIndex) LookupByVRFIndex(swIfIndex uint32) (name string, metadata *VRFMetadata, exists bool) {
func (m *vrfMetadataIndex) LookupByVRFIndex(swIfIndex uint32) (name string, metadata *VRFMetadata, exists bool) {
var item idxvpp.WithIndex
name, item, exists = vrfm.nameToIndex.LookupByIndex(swIfIndex)
name, item, exists = m.nameToIndex.LookupByIndex(swIfIndex)
if exists {
var isVrfMeta bool
metadata, isVrfMeta = item.(*VRFMetadata)
Expand All @@ -120,12 +123,24 @@ func (vrfm *vrfMetadataIndex) LookupByVRFIndex(swIfIndex uint32) (name string, m
}

// ListAllVRFs returns slice of labels of all VRFs in the mapping.
func (vrfm *vrfMetadataIndex) ListAllVRFs() (names []string) {
return vrfm.ListAllNames()
func (m *vrfMetadataIndex) ListAllVRFs() (names []string) {
return m.ListAllNames()
}

// ListAllVrfIDs returns a list of VRF indexes read from VRF metadata.
func (m *vrfMetadataIndex) ListAllVrfIDs() (idList []uint32) {
for _, vrf := range m.ListAllNames() {
vrfMeta, ok := m.nameToIndex.LookupByName(vrf)
if vrfMeta == nil || !ok {
continue
}
idList = append(idList, vrfMeta.GetIndex())
}
return
}

// WatchVRFs allows to subscribe to watch for changes in the VRF mapping.
func (vrfm *vrfMetadataIndex) WatchVRFs(subscriber string, channel chan<- VRFMetadataDto) {
func (m *vrfMetadataIndex) WatchVRFs(subscriber string, channel chan<- VRFMetadataDto) {
watcher := func(dto idxmap.NamedMappingGenericEvent) {
typedMeta, ok := dto.Value.(*VRFMetadata)
if !ok {
Expand All @@ -140,11 +155,11 @@ func (vrfm *vrfMetadataIndex) WatchVRFs(subscriber string, channel chan<- VRFMet
case channel <- msg:
// OK
case <-time.After(timeout):
vrfm.log.Warnf("Unable to deliver VRF watch notification after %v, channel is full", timeout)
m.log.Warnf("Unable to deliver VRF watch notification after %v, channel is full", timeout)
}
}
if err := vrfm.Watch(subscriber, watcher); err != nil {
vrfm.log.Error(err)
if err := m.Watch(subscriber, watcher); err != nil {
m.log.Error(err)
}
}

Expand Down
3 changes: 3 additions & 0 deletions plugins/vpp/l3plugin/vrfidx/vrfidx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ func TestRegisterAndUnregisterName(t *testing.T) {
names := index.ListAllVRFs()
Expect(names).To(HaveLen(1))
Expect(names).To(ContainElement(vrfName0))
indexes := index.ListAllVrfIDs()
Expect(indexes).To(HaveLen(1))
Expect(indexes).To(ContainElement(idx0))

// Unregister vrf
index.Delete(vrfName0)
Expand Down

0 comments on commit 1e2154d

Please sign in to comment.