From 3bb93dff32eb3edd1f2ff3d8f5919536523cc8f0 Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Thu, 11 Jul 2019 15:47:18 +0200 Subject: [PATCH 01/15] vpp: bump govpp library for UNIX socket support --- go.mod | 2 +- go.sum | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2c71d8fc3e..9c99b4b7c9 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/skydive-project/skydive require ( - git.fd.io/govpp.git v0.0.0-20190321220742-345201eedce4 + git.fd.io/govpp.git v0.1.0 github.com/GehirnInc/crypt v0.0.0-20170404120257-5a3fafaa7c86 github.com/IBM/ibm-cos-sdk-go v0.0.0-20190328184230-08c1143e8d36 github.com/Knetic/govaluate v0.0.0-20171022003610-9aa49832a739 // indirect diff --git a/go.sum b/go.sum index 866fdf229d..4505048ea3 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,9 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -git.fd.io/govpp.git v0.0.0-20190321220742-345201eedce4 h1:RgD/hziNkW6p1RJSU1wH9vtj27KBlPDYlApd/SWwyM0= -git.fd.io/govpp.git v0.0.0-20190321220742-345201eedce4/go.mod h1:+vyimAjILe5SYKjw4/WJ/8qPl9U5Qd9IT2v6b9VB83o= +git.fd.io/govpp.git v0.1.0 h1:fV5H9ghURFfmNAjk7Scb/aG3OGwevLayHfSdS8GsYjE= +git.fd.io/govpp.git v0.1.0/go.mod h1:+vyimAjILe5SYKjw4/WJ/8qPl9U5Qd9IT2v6b9VB83o= +github.com/Azure/go-autorest v11.1.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -394,9 +395,12 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= +github.com/lebauce/go-libvirt v0.0.0-20190717144624-7799d804f7e4 h1:x5KFqNwY2VCNzeb/e3uDMXFGTsJIkshXR196AICUFlA= github.com/lebauce/go-libvirt v0.0.0-20190717144624-7799d804f7e4/go.mod h1:0vvEvX3eAM/+BVh8JR6ujCJR5kiHdNz6EmbN+UXekPY= github.com/lebauce/gobpf v0.0.0-20190909090614-f9e9df81702a/go.mod h1:JhYasZSlL+g2F1yLuDe6xblKOyBqS74nxpnrmkjvyIE= +github.com/lebauce/netlink v0.0.0-20190122103356-fa328be7c8d2 h1:BJ76NzXWxDpXfIllk9aqIUAkfE9ii5vckEVzbnu8Xuo= github.com/lebauce/netlink v0.0.0-20190122103356-fa328be7c8d2/go.mod h1:BM4By6mUPPgCziwQuGvUvszl5C2leD3bQWoot0sEgxA= +github.com/lebauce/viper v0.0.0-20190903114911-3b7a98e30843 h1:ECfqMmqlbfCw03LG3vqLw59qHkftBcmhWpupIgc20r0= github.com/lebauce/viper v0.0.0-20190903114911-3b7a98e30843/go.mod h1:jUyf+v/KTOnRyUy2/AsjF537WfJWVv3AnlcKSNd+AIg= github.com/libvirt/libvirt-go v0.0.0-20181005092746-9c5bdce3c18f h1:MR3DdYRibNNyUFwDOmuMynXQMTrlktmPK20JlTyW8qo= github.com/libvirt/libvirt-go v0.0.0-20181005092746-9c5bdce3c18f/go.mod h1:34zsnB4iGeOv7Byj6qotuW8Ya4v4Tr43ttjz/F0wjLE= From d361b777d080827083174193df9408a2924d18b5 Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Thu, 11 Jul 2019 15:51:18 +0200 Subject: [PATCH 02/15] common: support all namespace types --- common/namespace.go | 178 ++++++++++++++++++++++++ common/netns.go | 81 ----------- common/{no_netns.go => no_namespace.go} | 18 +-- flow/probes/gopacket/gopacket.go | 2 +- topology/probes/netlink/netlink.go | 4 +- topology/probes/netns/netns.go | 44 ++---- topology/topology.go | 2 +- 7 files changed, 203 insertions(+), 126 deletions(-) create mode 100644 common/namespace.go delete mode 100644 common/netns.go rename common/{no_netns.go => no_namespace.go} (63%) diff --git a/common/namespace.go b/common/namespace.go new file mode 100644 index 0000000000..0cc992e00c --- /dev/null +++ b/common/namespace.go @@ -0,0 +1,178 @@ +// +build linux + +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * 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 ofthe 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 specificlanguage governing permissions and + * limitations under the License. + * + */ + +package common + +import ( + "fmt" + "os" + "runtime" + "syscall" + + "github.com/skydive-project/skydive/logging" + "github.com/vishvananda/netns" +) + +// Namespace types +const ( + IPCNamespace = "ipc" + MountNamespace = "mnt" + NetworkNamespace = "net" + PIDNamespace = "pid" + UserNamespace = "user" + TimeNamespace = "uts" +) + +// Namespace describes a network namespace path associated with a device / inode +type Namespace struct { + netns.NsHandle + path string + dev uint64 + ino uint64 +} + +func (ns *Namespace) String() string { + return fmt.Sprintf("%d,%d", ns.dev, ns.ino) +} + +// Path returns the namespace path +func (ns *Namespace) Path() string { + return ns.path +} + +// Ino returns the namespace inode number +func (ns *Namespace) Ino() uint64 { + return ns.ino +} + +// Dev returns the namespace device number +func (ns *Namespace) Dev() uint64 { + return ns.dev +} + +// Equal compares two Namespace objects +func (ns *Namespace) Equal(o *Namespace) bool { + return (ns.dev == o.dev && ns.ino == o.ino) +} + +// GetNamespaceFromPath open a namespace fd from a path +func GetNamespaceFromPath(kind, path string) (*Namespace, error) { + ns, err := netns.GetFromPath(path) + if err != nil { + return nil, fmt.Errorf("Failed to get %s root namespace %s", kind, path) + } + + var stats syscall.Stat_t + if err = syscall.Fstat(int(ns), &stats); err != nil { + return nil, fmt.Errorf("Failed to stat %s root namespace %s", kind, path) + } + + return &Namespace{NsHandle: ns, path: path, dev: stats.Dev, ino: stats.Ino}, nil +} + +// GetCurrentNamespace returns the current namespace of the specified kind +func GetCurrentNamespace(kind string) (*Namespace, error) { + return GetNamespaceFromPath(kind, fmt.Sprintf("/proc/%d/task/%d/ns/%s", os.Getpid(), syscall.Gettid(), kind)) +} + +// NamespaceContext describes a NameSpace Context switch API +type NamespaceContext struct { + nsType int + origNs netns.NsHandle + newNs netns.NsHandle +} + +// Quit the NameSpace and go back to the original one +func (n *NamespaceContext) Quit() error { + if n != nil { + if err := netns.Setns(n.origNs, n.nsType); err != nil { + return err + } + n.newNs.Close() + n.origNs.Close() + } + return nil +} + +// Close the NameSpace +func (n *NamespaceContext) Close() { + if n != nil && n.origNs.IsOpen() { + n.Quit() + } + + runtime.UnlockOSThread() +} + +func getNsType(kind string) int { + switch kind { + case NetworkNamespace: + return syscall.CLONE_NEWNET + case IPCNamespace: + return syscall.CLONE_NEWIPC + case MountNamespace: + return syscall.CLONE_NEWNS + case PIDNamespace: + return syscall.CLONE_NEWPID + case UserNamespace: + return syscall.CLONE_NEWUSER + case TimeNamespace: + return syscall.CLONE_NEWUTS + default: + return 0 + } +} + +// NewNamespaceContext creates a new namespace context from a path +func NewNamespaceContext(kind string, path string) (*NamespaceContext, error) { + nsType := getNsType(kind) + if nsType == 0 { + return nil, fmt.Errorf("Unsupported namespace type: %s", kind) + } + + runtime.LockOSThread() + + origns, err := GetCurrentNamespace(kind) + if err != nil { + return nil, fmt.Errorf("Error while getting current %s ns: %s", kind, err.Error()) + } + + newns, err := GetNamespaceFromPath(kind, path) + if err != nil { + origns.Close() + return nil, fmt.Errorf("Error while opening %s: %s", path, err.Error()) + } + + if err = netns.Setns(newns.NsHandle, nsType); err != nil { + logging.GetLogger().Errorf("Failed to set namespace %d with type %d", newns.NsHandle, nsType) + newns.Close() + origns.Close() + return nil, fmt.Errorf("Error while switching from root %s ns to %s: %s", kind, path, err.Error()) + } + + return &NamespaceContext{ + nsType: nsType, + origNs: origns.NsHandle, + newNs: newns.NsHandle, + }, nil +} + +// NewNetNsContext creates a new network namespace context from a path +func NewNetNsContext(path string) (*NamespaceContext, error) { + return NewNamespaceContext(NetworkNamespace, path) +} diff --git a/common/netns.go b/common/netns.go deleted file mode 100644 index 20522ab29f..0000000000 --- a/common/netns.go +++ /dev/null @@ -1,81 +0,0 @@ -// +build linux - -/* - * Copyright (C) 2016 Red Hat, Inc. - * - * 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 ofthe 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 specificlanguage governing permissions and - * limitations under the License. - * - */ - -package common - -import ( - "fmt" - "runtime" - - "github.com/vishvananda/netns" -) - -// NetNSContext describes a NameSpace Context switch API -type NetNSContext struct { - origns netns.NsHandle - newns netns.NsHandle -} - -// Quit the NameSpace and go back to the original one -func (n *NetNSContext) Quit() error { - if n != nil { - if err := netns.Set(n.origns); err != nil { - return err - } - n.newns.Close() - n.origns.Close() - } - return nil -} - -// Close the NameSpace -func (n *NetNSContext) Close() { - if n != nil && n.origns.IsOpen() { - n.Quit() - } - - runtime.UnlockOSThread() -} - -// NewNetNsContext creates a new NameSpace context base on path -func NewNetNsContext(path string) (*NetNSContext, error) { - runtime.LockOSThread() - - origns, err := netns.Get() - if err != nil { - return nil, fmt.Errorf("Error while getting current ns: %s", err.Error()) - } - - newns, err := netns.GetFromPath(path) - if err != nil { - origns.Close() - return nil, fmt.Errorf("Error while opening %s: %s", path, err.Error()) - } - - if err = netns.Set(newns); err != nil { - newns.Close() - origns.Close() - return nil, fmt.Errorf("Error while switching from root ns to %s: %s", path, err.Error()) - } - - return &NetNSContext{ - origns: origns, - newns: newns, - }, nil -} diff --git a/common/no_netns.go b/common/no_namespace.go similarity index 63% rename from common/no_netns.go rename to common/no_namespace.go index 9761d67e16..2e4bdcec60 100644 --- a/common/no_netns.go +++ b/common/no_namespace.go @@ -19,24 +19,24 @@ package common -// NetNSContext describes a NameSpace Context switch API -type NetNSContext struct { +// NamespaceContext describes a namespace context switch API +type NamespaceContext struct { } -// Quit the NameSpace and go back to the original one -func (n *NetNSContext) Quit() error { +// Quit the namespace and go back to the original one +func (n *NamespaceContext) Quit() error { return nil } -// Close the NameSpace -func (n *NetNSContext) Close() { +// Close the namespace +func (n *NamespaceContext) Close() { } -// NewNetNsContext creates a new NameSpace context base on path -func NewNetNsContext(path string) (*NetNSContext, error) { +// NewNetNsContext creates a new namespace context base on path +func NewNetNsContext(path string) (*NamespaceContext, error) { if path != "" { return nil, ErrNotImplemented } - return &NetNSContext{}, nil + return &NamespaceContext{}, nil } diff --git a/flow/probes/gopacket/gopacket.go b/flow/probes/gopacket/gopacket.go index d4b5f4818b..7227e39829 100644 --- a/flow/probes/gopacket/gopacket.go +++ b/flow/probes/gopacket/gopacket.go @@ -141,7 +141,7 @@ func (p *Probe) listen(packetCallback func(gopacket.Packet)) error { func (p *Probe) Run(packetCallback func(gopacket.Packet), e probes.ProbeEventHandler) error { p.state.Store(common.RunningState) - var nsContext *common.NetNSContext + var nsContext *common.NamespaceContext var err error if p.nsPath != "" { p.Ctx.Logger.Debugf("Switching to namespace (path: %s)", p.nsPath) diff --git a/topology/probes/netlink/netlink.go b/topology/probes/netlink/netlink.go index 1c1faebc56..424adce81b 100644 --- a/topology/probes/netlink/netlink.go +++ b/topology/probes/netlink/netlink.go @@ -363,7 +363,7 @@ func newInterfaceMetricsFromNetlink(link netlink.Link) *topology.InterfaceMetric } func (u *Probe) updateLinkNetNsName(intf *graph.Node, link netlink.Link, metadata graph.Metadata) bool { - var context *common.NetNSContext + var context *common.NamespaceContext lnsid := link.Attrs().NetNsID @@ -1205,7 +1205,7 @@ func newProbe(ctx tp.Context, nsPath string, sriovProcessor *graph.Processor) (* netNsNameTry: make(map[graph.Identifier]int), sriovProcessor: sriovProcessor, } - var context *common.NetNSContext + var context *common.NamespaceContext var err error errFnc := func(err error) (*Probe, error) { diff --git a/topology/probes/netns/netns.go b/topology/probes/netns/netns.go index f42cf565fc..9c61444db1 100644 --- a/topology/probes/netns/netns.go +++ b/topology/probes/netns/netns.go @@ -39,7 +39,6 @@ import ( "github.com/skydive-project/skydive/topology" tp "github.com/skydive-project/skydive/topology/probes" "github.com/skydive-project/skydive/topology/probes/netlink" - "github.com/vishvananda/netns" ) // ProbeHandler describes a netlink probe in a network namespace @@ -47,9 +46,9 @@ type ProbeHandler struct { common.RWMutex Ctx tp.Context nlHandler *netlink.ProbeHandler - pathToNetNS map[string]*NetNs + pathToNetNS map[string]*common.Namespace nsNetLinkProbes map[string]*nsNetLinkProbe - rootNs *NetNs + rootNs *common.Namespace watcher *fsnotify.Watcher pending chan string exclude []string @@ -57,13 +56,6 @@ type ProbeHandler struct { wg sync.WaitGroup } -// NetNs describes a network namespace path associated with a device / inode -type NetNs struct { - path string - dev uint64 - ino uint64 -} - // extends the original struct to add use count number type nsNetLinkProbe struct { *netlink.Probe @@ -75,15 +67,6 @@ func getNetNSName(path string) string { return s[len(s)-1] } -func (ns *NetNs) String() string { - return fmt.Sprintf("%d,%d", ns.dev, ns.ino) -} - -// Equal compares two NetNs objects -func (ns *NetNs) Equal(o *NetNs) bool { - return (ns.dev == o.dev && ns.ino == o.ino) -} - func (u *ProbeHandler) checkNamespace(path string) error { // When a new network namespace has been seen by inotify, the path to // the namespace may still be a regular file, not a bind mount to the @@ -140,7 +123,10 @@ func (u *ProbeHandler) Register(path string, name string) (*graph.Node, error) { return nil, fmt.Errorf("Failed to stat namespace %s: %s", path, err) } - newns := &NetNs{path: path, dev: stats.Dev, ino: stats.Ino} + newns, err := common.GetNamespaceFromPath(common.NetworkNamespace, path) + if err != nil { + return nil, err + } // avoid hard link to root ns if u.rootNs.Equal(newns) { @@ -169,8 +155,8 @@ func (u *ProbeHandler) Register(path string, name string) (*graph.Node, error) { "Name": name, "Type": "netns", "Path": path, - "Inode": int64(newns.ino), - "Device": int64(newns.dev), + "Inode": int64(newns.Ino()), + "Device": int64(newns.Dev()), } u.Ctx.Graph.Lock() @@ -381,17 +367,11 @@ func NewProbe(ctx tp.Context, bundle *probe.Bundle) (probe.Handler, error) { return nil, errors.New("unable to find the netlink handler") } - ns, err := netns.Get() + rootNs, err := common.GetCurrentNamespace(common.NetworkNamespace) if err != nil { - return nil, errors.New("Failed to get root namespace") - } - defer ns.Close() - - var stats syscall.Stat_t - if err = syscall.Fstat(int(ns), &stats); err != nil { - return nil, errors.New("Failed to stat root namespace") + return nil, err } - rootNs := &NetNs{dev: stats.Dev, ino: stats.Ino} + defer rootNs.Close() watcher, err := fsnotify.NewWatcher() if err != nil { @@ -401,7 +381,7 @@ func NewProbe(ctx tp.Context, bundle *probe.Bundle) (probe.Handler, error) { u := &ProbeHandler{ Ctx: ctx, nlHandler: nlHandler.(*netlink.ProbeHandler), - pathToNetNS: make(map[string]*NetNs), + pathToNetNS: make(map[string]*common.Namespace), nsNetLinkProbes: make(map[string]*nsNetLinkProbe), rootNs: rootNs, watcher: watcher, diff --git a/topology/topology.go b/topology/topology.go index f2568e1c0c..f5e56a0311 100644 --- a/topology/topology.go +++ b/topology/topology.go @@ -85,7 +85,7 @@ func NamespaceFromNode(g *graph.Graph, n *graph.Node) (string, string, error) { } // NewNetNSContextByNode creates a new network namespace context based on the node -func NewNetNSContextByNode(g *graph.Graph, n *graph.Node) (*common.NetNSContext, error) { +func NewNetNSContextByNode(g *graph.Graph, n *graph.Node) (*common.NamespaceContext, error) { name, path, err := NamespaceFromNode(g, n) if err != nil || name == "" || path == "" { return nil, err From 250ded0cec8a74f304e7a602e3630ce01fce8dbb Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Mon, 15 Jul 2019 13:48:31 +0200 Subject: [PATCH 03/15] vpp: properly disconnect from VPP --- topology/probes/vpp/vpp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topology/probes/vpp/vpp.go b/topology/probes/vpp/vpp.go index ad93343b36..a6271c61ea 100644 --- a/topology/probes/vpp/vpp.go +++ b/topology/probes/vpp/vpp.go @@ -342,8 +342,8 @@ func (p *Probe) Start() error { func (p *Probe) Stop() { p.state.Store(common.StoppingState) close(p.notifChan) - p.conn.Disconnect() p.wg.Wait() + p.conn.Disconnect() } // NewProbe returns a new VPP probe From 846fed7f5cd33e9ac74587827cd75429f51549fe Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Mon, 15 Jul 2019 14:22:15 +0200 Subject: [PATCH 04/15] vpp: use an indexer to keep track of created interfaces --- topology/probes/vpp/vpp.go | 107 +++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/topology/probes/vpp/vpp.go b/topology/probes/vpp/vpp.go index a6271c61ea..68b21a3aed 100644 --- a/topology/probes/vpp/vpp.go +++ b/topology/probes/vpp/vpp.go @@ -23,8 +23,8 @@ package vpp import ( - "fmt" "io/ioutil" + "net" "os" "strings" "sync" @@ -38,6 +38,7 @@ import ( "github.com/skydive-project/skydive/common" "github.com/skydive-project/skydive/graffiti/graph" + "github.com/skydive-project/skydive/logging" "github.com/skydive-project/skydive/probe" "github.com/skydive-project/skydive/topology" tp "github.com/skydive-project/skydive/topology/probes" @@ -50,28 +51,27 @@ const ( VPPPollingTime = 200 ) -// Probe is VPP probe +// Probe is an instance of a VPP probe in a namespace type Probe struct { sync.Mutex + *graph.EventHandler Ctx tp.Context shm string // connect SHM path conn *core.Connection // VPP connection interfaceMap map[uint32]*interfaces.SwInterfaceDetails // MAP of VPP interfaces + intfIndexer *graph.MetadataIndexer // index of created nodes by the probe vppRootNode *graph.Node // root node for ownership notifChan chan api.Message // notification channel on interfaces events state common.ServiceState // state of the probe (running or stopped) wg sync.WaitGroup // goroutines wait group } +func interfaceName(name []byte) string { + return strings.Trim(string(name), "\000") +} + func interfaceMAC(mac []byte) string { - s := "" - for i, m := range mac { - if i != 0 { - s += ":" - } - s += fmt.Sprintf("%02x", m) - } - return s + return net.HardwareAddr(mac).String() } func interfaceDuplex(duplex uint8) string { @@ -103,25 +103,26 @@ func (p *Probe) getInterfaceVrfID(ch api.Channel, index uint32) int64 { } func (p *Probe) getInterface(index uint32) *graph.Node { - p.Ctx.Graph.RLock() - defer p.Ctx.Graph.RUnlock() - return p.Ctx.Graph.LookupFirstNode(graph.Metadata{"IfIndex": int64(index), "Type": "vpp"}) + node, _ := p.intfIndexer.GetNode(int64(index)) + return node } func (p *Probe) createOrUpdateInterface(ch api.Channel, intf *interfaces.SwInterfaceDetails) *graph.Node { - metadata := graph.Metadata{"IfIndex": int64(intf.SwIfIndex), "Type": "vpp"} + vrfID := p.getInterfaceVrfID(ch, intf.SwIfIndex) p.Ctx.Graph.Lock() defer p.Ctx.Graph.Unlock() var err error - node := p.Ctx.Graph.LookupFirstNode(metadata) + node := p.getInterface(intf.SwIfIndex) if node == nil { - node, err = p.Ctx.Graph.NewNode(graph.GenID(), metadata) + node, err = p.Ctx.Graph.NewNode(graph.GenID(), graph.Metadata{"IfIndex": int64(intf.SwIfIndex), "Type": "vpp"}) if err != nil { p.Ctx.Logger.Error(err) return nil } + p.NotifyEvent(graph.NodeAdded, node) + if _, err = p.Ctx.Graph.Link(p.vppRootNode, node, topology.OwnershipMetadata()); err != nil { p.Ctx.Logger.Error(err) return nil @@ -129,9 +130,8 @@ func (p *Probe) createOrUpdateInterface(ch api.Channel, intf *interfaces.SwInter } tr := p.Ctx.Graph.StartMetadataTransaction(node) - defer tr.Commit() tr.AddMetadata("Driver", "vpp") - tr.AddMetadata("Name", strings.Trim(string(intf.InterfaceName), "\000")) + tr.AddMetadata("Name", interfaceName(intf.InterfaceName)) tr.AddMetadata("IfIndex", int64(intf.SwIfIndex)) tr.AddMetadata("MAC", interfaceMAC(intf.L2Address[:intf.L2AddressLength])) tr.AddMetadata("MTU", int64(intf.LinkMtu)) @@ -141,18 +141,17 @@ func (p *Probe) createOrUpdateInterface(ch api.Channel, intf *interfaces.SwInter if state != "DOWN" { tr.AddMetadata("Duplex", interfaceDuplex(intf.LinkDuplex)) } - tr.AddMetadata("VrfID", p.getInterfaceVrfID(ch, intf.SwIfIndex)) + tr.AddMetadata("VrfID", vrfID) + tr.Commit() + p.NotifyEvent(graph.NodeUpdated, node) return node } func interfaceNeedUpdate(i1, i2 *interfaces.SwInterfaceDetails) bool { - if (i1.LinkMtu != i2.LinkMtu) || - (i1.LinkSpeed != i2.LinkSpeed) || - (i1.LinkDuplex != i2.LinkDuplex) { - return true - } - return false + return i1.LinkMtu != i2.LinkMtu || + i1.LinkSpeed != i2.LinkSpeed || + i1.LinkDuplex != i2.LinkDuplex } func (p *Probe) eventAddInterface(ch api.Channel, intf *interfaces.SwInterfaceDetails) { @@ -160,25 +159,18 @@ func (p *Probe) eventAddInterface(ch api.Channel, intf *interfaces.SwInterfaceDe } func (p *Probe) eventDelInterface(node *graph.Node) { - p.Ctx.Graph.Lock() - defer p.Ctx.Graph.Unlock() if err := p.Ctx.Graph.DelNode(node); err != nil { p.Ctx.Logger.Error(err) } } func (p *Probe) interfaceEventsEnableDisable(ch api.Channel, enable bool) { - ed := uint32(0) + req := &interfaces.WantInterfaceEvents{PID: uint32(os.Getpid())} if enable { - ed = uint32(1) - } - req := &interfaces.WantInterfaceEvents{ - EnableDisable: ed, - PID: uint32(os.Getpid()), + req.EnableDisable = 1 } msg := &interfaces.WantInterfaceEventsReply{} - err := ch.SendRequest(req).ReceiveReply(msg) - if err != nil { + if err := ch.SendRequest(req).ReceiveReply(msg); err != nil { p.Ctx.Logger.Error(err) } } @@ -198,6 +190,7 @@ func (p *Probe) interfacesEvents() { return } + logging.GetLogger().Debugf("Registering for VPP events") p.interfaceEventsEnableDisable(ch, true) for p.state.Load() == common.RunningState { @@ -206,22 +199,24 @@ func (p *Probe) interfacesEvents() { break } msg := notif.(*interfaces.SwInterfaceEvent) + logging.GetLogger().Debugf("Received sw interface event %+v", msg) - node := p.getInterface(msg.SwIfIndex) - p.Ctx.Graph.RLock() - name, _ := node.GetFieldString("Name") - p.Ctx.Graph.RUnlock() - if msg.Deleted > 0 { - p.Ctx.Logger.Debugf("Delete interface %v idx %d", name, msg.SwIfIndex) - p.eventDelInterface(node) - continue - } - p.Ctx.Logger.Debugf("ChangeState interface %v idx %d updown %d", name, msg.SwIfIndex, msg.AdminUpDown) p.Ctx.Graph.Lock() - node.Metadata.SetField("State", interfaceUpDown(msg.AdminUpDown)) + if node := p.getInterface(msg.SwIfIndex); node != nil { + name, _ := node.GetFieldString("Name") + if msg.Deleted > 0 { + logging.GetLogger().Debugf("Delete interface %v idx %d", name, msg.SwIfIndex) + p.eventDelInterface(node) + } else { + state := interfaceUpDown(msg.AdminUpDown) + logging.GetLogger().Debugf("ChangeState interface %s idx %d updown %d", name, msg.SwIfIndex, state) + p.Ctx.Graph.AddMetadata(node, "State", state) + } + } p.Ctx.Graph.Unlock() } + logging.GetLogger().Debugf("Unregistering for VPP events") p.interfaceEventsEnableDisable(ch, false) sub.Unsubscribe() @@ -267,7 +262,7 @@ func (p *Probe) interfacesPolling() { /* Update interface metadata */ for index := range needUpdate { msg := p.interfaceMap[index] - p.Ctx.Logger.Debugf("Add/Update interface %v idx %d up/down %d", strings.Trim(string(msg.InterfaceName), "\000"), int64(msg.SwIfIndex), int64(msg.AdminUpDown)) + logging.GetLogger().Debugf("Add/Update interface %s idx %d up/down %d", interfaceName(msg.InterfaceName), int64(msg.SwIfIndex), interfaceUpDown(msg.AdminUpDown)) p.eventAddInterface(ch, msg) } /* Remove interface that didn't exist anymore */ @@ -275,12 +270,13 @@ func (p *Probe) interfacesPolling() { _, found := foundInterfaces[index] _, firsttime := needUpdate[index] if !found && !firsttime { - node := p.getInterface(index) - p.Ctx.Graph.RLock() - name, _ := node.GetFieldString("Name") - p.Ctx.Graph.RUnlock() - p.Ctx.Logger.Debugf("Delete interface %v idx %d", name, index) - p.eventDelInterface(node) + p.Ctx.Graph.Lock() + if node := p.getInterface(index); node != nil { + name, _ := node.GetFieldString("Name") + logging.GetLogger().Debugf("Delete interface %v idx %d", name, index) + p.eventDelInterface(node) + } + p.Ctx.Graph.Unlock() delete(p.interfaceMap, index) } } @@ -313,6 +309,8 @@ func (p *Probe) Start() error { } ch.Close() + p.intfIndexer.Start() + metadata := graph.Metadata{ "Name": "vpp", "Type": "vpp", @@ -340,6 +338,7 @@ func (p *Probe) Start() error { // Stop the probe func (p *Probe) Stop() { + p.intfIndexer.Stop() p.state.Store(common.StoppingState) close(p.notifChan) p.wg.Wait() @@ -351,10 +350,12 @@ func NewProbe(ctx tp.Context, bundle *probe.Bundle) (probe.Handler, error) { shm := ctx.Config.GetString("agent.topology.vpp.connect") p := &Probe{ + EventHandler: graph.NewEventHandler(100), Ctx: ctx, shm: shm, interfaceMap: make(map[uint32]*interfaces.SwInterfaceDetails), notifChan: make(chan api.Message, 100), + intfIndexer: graph.NewMetadataIndexer(p.Ctx.Graph, p, nil, "IfIndex"), } p.state.Store(common.StoppedState) From de5ca88e2edc288e0da8fb9259d927acafa929a9 Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Tue, 16 Jul 2019 13:45:31 +0200 Subject: [PATCH 05/15] docker: report containers bind mounts --- topology/probes/docker/docker.go | 15 +++++++++++++++ topology/probes/docker/metadata.go | 9 +++++++++ 2 files changed, 24 insertions(+) diff --git a/topology/probes/docker/docker.go b/topology/probes/docker/docker.go index ee90c593dd..18e4ae514c 100644 --- a/topology/probes/docker/docker.go +++ b/topology/probes/docker/docker.go @@ -23,6 +23,7 @@ import ( "context" "errors" "fmt" + "strings" "sync" "github.com/docker/docker/api/types" @@ -114,6 +115,20 @@ func (p *ProbeHandler) registerContainer(id string) { dockerMetadata.Labels = graph.Metadata(common.NormalizeValue(info.Config.Labels).(map[string]interface{})) } + if len(info.HostConfig.Binds) > 0 { + dockerMetadata.Mounts = make([]*Mount, len(info.HostConfig.Binds)) + for i, bind := range info.HostConfig.Binds { + split := strings.Split(bind, ":") + if len(split) >= 2 { + mount := &Mount{ + Source: split[0], + Destination: split[1], + } + dockerMetadata.Mounts[i] = mount + } + } + } + p.Ctx.Graph.Lock() defer p.Ctx.Graph.Unlock() diff --git a/topology/probes/docker/metadata.go b/topology/probes/docker/metadata.go index c6a417a4ba..a27d5c8422 100644 --- a/topology/probes/docker/metadata.go +++ b/topology/probes/docker/metadata.go @@ -28,6 +28,14 @@ import ( "github.com/skydive-project/skydive/graffiti/graph" ) +// Mount describes the metadata of a docker bind mount +// easyjson:json +// gendecoder +type Mount struct { + Source string + Destination string +} + // Metadata describe the metadata of a docker container // easyjson:json // gendecoder @@ -35,6 +43,7 @@ type Metadata struct { ContainerID string ContainerName string Labels graph.Metadata `field:"Metadata"` + Mounts []*Mount } // MetadataDecoder implements a json message raw decoder From e040e3b21667e29734571122caaa9801a6dc86ee Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Fri, 19 Jul 2019 15:53:52 +0200 Subject: [PATCH 06/15] vpp: make use of retry probe wrapper --- topology/probes/vpp/vpp.go | 294 ++++++++++++++++++++----------------- 1 file changed, 157 insertions(+), 137 deletions(-) diff --git a/topology/probes/vpp/vpp.go b/topology/probes/vpp/vpp.go index 68b21a3aed..edefb32395 100644 --- a/topology/probes/vpp/vpp.go +++ b/topology/probes/vpp/vpp.go @@ -23,6 +23,8 @@ package vpp import ( + "context" + "fmt" "io/ioutil" "net" "os" @@ -36,11 +38,10 @@ import ( "github.com/sirupsen/logrus" - "github.com/skydive-project/skydive/common" "github.com/skydive-project/skydive/graffiti/graph" - "github.com/skydive-project/skydive/logging" "github.com/skydive-project/skydive/probe" "github.com/skydive-project/skydive/topology" + "github.com/skydive-project/skydive/topology/probes" tp "github.com/skydive-project/skydive/topology/probes" "github.com/skydive-project/skydive/topology/probes/vpp/bin_api/interfaces" "github.com/skydive-project/skydive/topology/probes/vpp/bin_api/vpe" @@ -48,7 +49,9 @@ import ( const ( // VPPPollingTime in milliseconds - VPPPollingTime = 200 + VPPPollingTime = 10 * time.Second + HealthCheckReplyTimeout = 3 * time.Second + HealthCheckInterval = 3 * time.Second ) // Probe is an instance of a VPP probe in a namespace @@ -56,14 +59,11 @@ type Probe struct { sync.Mutex *graph.EventHandler Ctx tp.Context - shm string // connect SHM path + addr string // VPP address (unix or SHM) conn *core.Connection // VPP connection - interfaceMap map[uint32]*interfaces.SwInterfaceDetails // MAP of VPP interfaces + interfaceMap map[uint32]*interfaces.SwInterfaceDetails // map of VPP interfaces intfIndexer *graph.MetadataIndexer // index of created nodes by the probe vppRootNode *graph.Node // root node for ownership - notifChan chan api.Message // notification channel on interfaces events - state common.ServiceState // state of the probe (running or stopped) - wg sync.WaitGroup // goroutines wait group } func interfaceName(name []byte) string { @@ -160,6 +160,7 @@ func (p *Probe) eventAddInterface(ch api.Channel, intf *interfaces.SwInterfaceDe func (p *Probe) eventDelInterface(node *graph.Node) { if err := p.Ctx.Graph.DelNode(node); err != nil { + p.NotifyEvent(graph.NodeDeleted, node) p.Ctx.Logger.Error(err) } } @@ -175,189 +176,208 @@ func (p *Probe) interfaceEventsEnableDisable(ch api.Channel, enable bool) { } } -func (p *Probe) interfacesEvents() { - defer p.wg.Done() +func (p *Probe) synchronize(ch api.Channel) error { + foundInterfaces := make(map[uint32]struct{}) + needUpdate := make(map[uint32]struct{}) - ch, err := p.conn.NewAPIChannel() - if err != nil { - p.Ctx.Logger.Error("API channel error: ", err) - return - } + req := &interfaces.SwInterfaceDump{} + reqCtx := ch.SendMultiRequest(req) + for { + msg := &interfaces.SwInterfaceDetails{} + stop, err := reqCtx.ReceiveReply(msg) + if stop { + break + } + if err != nil { + return err + } - sub, err := ch.SubscribeNotification(p.notifChan, &interfaces.SwInterfaceEvent{}) - if err != nil { - p.Ctx.Logger.Error(err) - return + intf, found := p.interfaceMap[msg.SwIfIndex] + if !found || interfaceNeedUpdate(msg, intf) { + needUpdate[msg.SwIfIndex] = struct{}{} + } + if found { + foundInterfaces[msg.SwIfIndex] = struct{}{} + } + p.interfaceMap[msg.SwIfIndex] = msg } - logging.GetLogger().Debugf("Registering for VPP events") - p.interfaceEventsEnableDisable(ch, true) - - for p.state.Load() == common.RunningState { - notif := <-p.notifChan - if notif == nil { - break - } - msg := notif.(*interfaces.SwInterfaceEvent) - logging.GetLogger().Debugf("Received sw interface event %+v", msg) + /* Update interface metadata */ + for index := range needUpdate { + msg := p.interfaceMap[index] + p.Ctx.Logger.Debugf("Add/Update interface %s idx %d up/down %s", interfaceName(msg.InterfaceName), int64(msg.SwIfIndex), interfaceUpDown(msg.AdminUpDown)) + p.eventAddInterface(ch, msg) + } - p.Ctx.Graph.Lock() - if node := p.getInterface(msg.SwIfIndex); node != nil { - name, _ := node.GetFieldString("Name") - if msg.Deleted > 0 { - logging.GetLogger().Debugf("Delete interface %v idx %d", name, msg.SwIfIndex) + /* Remove interface that didn't exist anymore */ + for index := range p.interfaceMap { + _, found := foundInterfaces[index] + _, firsttime := needUpdate[index] + if !found && !firsttime { + p.Ctx.Graph.Lock() + if node := p.getInterface(index); node != nil { + name, _ := node.GetFieldString("Name") + p.Ctx.Logger.Debugf("Delete interface %v idx %d", name, index) p.eventDelInterface(node) - } else { - state := interfaceUpDown(msg.AdminUpDown) - logging.GetLogger().Debugf("ChangeState interface %s idx %d updown %d", name, msg.SwIfIndex, state) - p.Ctx.Graph.AddMetadata(node, "State", state) } + p.Ctx.Graph.Unlock() + delete(p.interfaceMap, index) } - p.Ctx.Graph.Unlock() } - logging.GetLogger().Debugf("Unregistering for VPP events") - p.interfaceEventsEnableDisable(ch, false) - - sub.Unsubscribe() - ch.Close() + return nil } -func (p *Probe) interfacesPolling() { - defer p.wg.Done() +func (p *Probe) handleInterfaceEvent(msg *interfaces.SwInterfaceEvent) { + p.Ctx.Graph.Lock() + if node := p.getInterface(msg.SwIfIndex); node != nil { + name, _ := node.GetFieldString("Name") + if msg.Deleted > 0 { + p.Ctx.Logger.Debugf("Delete interface %v idx %d", name, msg.SwIfIndex) + p.eventDelInterface(node) + } else { + state := interfaceUpDown(msg.AdminUpDown) + p.Ctx.Logger.Debugf("ChangeState interface %s idx %d updown %d", name, msg.SwIfIndex, state) + p.Ctx.Graph.AddMetadata(node, "State", state) + } + } + p.Ctx.Graph.Unlock() +} +func (p *Probe) run(ctx context.Context) { ch, err := p.conn.NewAPIChannel() if err != nil { p.Ctx.Logger.Error("API channel error: ", err) return } + ch.SetReplyTimeout(HealthCheckReplyTimeout) - for p.state.Load() == common.RunningState { - foundInterfaces := make(map[uint32]struct{}) - needUpdate := make(map[uint32]struct{}) - - req := &interfaces.SwInterfaceDump{} - reqCtx := ch.SendMultiRequest(req) - for { - msg := &interfaces.SwInterfaceDetails{} - stop, err := reqCtx.ReceiveReply(msg) - if stop { - break - } - if err != nil { - p.Ctx.Logger.Error(err) - goto nextEvents - } + notifChan := make(chan api.Message, 100) + sub, err := ch.SubscribeNotification(notifChan, &interfaces.SwInterfaceEvent{}) + if err != nil { + p.Ctx.Logger.Error(err) + return + } - intf, found := p.interfaceMap[msg.SwIfIndex] - if !found || interfaceNeedUpdate(msg, intf) { - needUpdate[msg.SwIfIndex] = struct{}{} - } - if found { - foundInterfaces[msg.SwIfIndex] = struct{}{} + p.Ctx.Logger.Debugf("Registering for VPP events") + p.interfaceEventsEnableDisable(ch, true) + + pollingTicker := time.NewTicker(VPPPollingTime) + defer pollingTicker.Stop() + + if err := p.synchronize(ch); err != nil { + p.Ctx.Logger.Error(err) + return + } + + pingTimer := time.NewTimer(HealthCheckInterval) + defer pingTimer.Stop() + +LOOP: + for { + select { + case notif := <-notifChan: + msg := notif.(*interfaces.SwInterfaceEvent) + p.Ctx.Logger.Debugf("Received sw interface event %+v", msg) + p.handleInterfaceEvent(msg) + case <-pollingTicker.C: + err = p.synchronize(ch) + case <-pingTimer.C: + req := &vpe.ControlPing{} + msg := &vpe.ControlPingReply{} + if err = ch.SendRequest(req).ReceiveReply(msg); err != nil { + err = fmt.Errorf("Health check failed: %s", err) } - p.interfaceMap[msg.SwIfIndex] = msg + case <-ctx.Done(): + defer p.conn.Disconnect() + break LOOP } - /* Update interface metadata */ - for index := range needUpdate { - msg := p.interfaceMap[index] - logging.GetLogger().Debugf("Add/Update interface %s idx %d up/down %d", interfaceName(msg.InterfaceName), int64(msg.SwIfIndex), interfaceUpDown(msg.AdminUpDown)) - p.eventAddInterface(ch, msg) - } - /* Remove interface that didn't exist anymore */ - for index := range p.interfaceMap { - _, found := foundInterfaces[index] - _, firsttime := needUpdate[index] - if !found && !firsttime { - p.Ctx.Graph.Lock() - if node := p.getInterface(index); node != nil { - name, _ := node.GetFieldString("Name") - logging.GetLogger().Debugf("Delete interface %v idx %d", name, index) - p.eventDelInterface(node) - } - p.Ctx.Graph.Unlock() - delete(p.interfaceMap, index) - } + if err != nil { + break } - nextEvents: - time.Sleep(VPPPollingTime * time.Millisecond) + pingTimer.Reset(HealthCheckInterval) } + p.Ctx.Logger.Debugf("Unregistering for VPP events") + p.interfaceEventsEnableDisable(ch, false) + + sub.Unsubscribe() ch.Close() } -// Start VPP probe and get all interfaces -func (p *Probe) Start() error { - conn, err := govpp.Connect(p.shm) +// Do starts the VPP probe and get all interfaces +func (p *Probe) Do(ctx context.Context, wg *sync.WaitGroup) error { + conn, err := govpp.Connect(p.addr) if err != nil { return fmt.Errorf("VPP connection error: %s", err) } p.conn = conn - ch, err := conn.NewAPIChannel() - if err != nil { - return fmt.Errorf("API channel error: %s", err) - } + if p.vppRootNode == nil { + ch, err := conn.NewAPIChannel() + if err != nil { + return fmt.Errorf("API channel error: %s", err) + } - req := &vpe.ShowVersion{} - msg := &vpe.ShowVersionReply{} - err = ch.SendRequest(req).ReceiveReply(msg) - if err != nil { - return err - } - ch.Close() + req := &vpe.ShowVersion{} + msg := &vpe.ShowVersionReply{} + err = ch.SendRequest(req).ReceiveReply(msg) + if err != nil { + return err + } + ch.Close() + + metadata := graph.Metadata{ + "Name": "vpp", + "Type": "vpp", + "Program": string(msg.Program), + "Version": string(msg.Version), + "BuildDate": string(msg.BuildDate), + } - p.intfIndexer.Start() + p.Ctx.Graph.Lock() + defer p.Ctx.Graph.Unlock() - metadata := graph.Metadata{ - "Name": "vpp", - "Type": "vpp", - "Program": string(msg.Program), - "Version": string(msg.Version), - "BuildDate": string(msg.BuildDate), + if p.vppRootNode, err = p.Ctx.Graph.NewNode(graph.GenID(), metadata); err != nil { + return err + } + + if _, err := topology.AddOwnershipLink(p.Ctx.Graph, p.Ctx.RootNode, p.vppRootNode, nil); err != nil { + return err + } } - p.Ctx.Graph.Lock() - defer p.Ctx.Graph.Unlock() + wg.Add(1) + go func() { + defer wg.Done() - if p.vppRootNode, err = p.Ctx.Graph.NewNode(graph.GenID(), metadata); err != nil { - return err - } - topology.AddOwnershipLink(p.Ctx.Graph, p.Ctx.RootNode, p.vppRootNode, nil) + p.intfIndexer.Start() + defer p.intfIndexer.Stop() - p.state.Store(common.RunningState) + p.Ctx.Graph.RLock() + p.intfIndexer.Sync() + p.Ctx.Graph.RUnlock() - p.wg.Add(2) - go p.interfacesPolling() - go p.interfacesEvents() + p.run(ctx) + }() return nil } -// Stop the probe -func (p *Probe) Stop() { - p.intfIndexer.Stop() - p.state.Store(common.StoppingState) - close(p.notifChan) - p.wg.Wait() - p.conn.Disconnect() -} - // NewProbe returns a new VPP probe func NewProbe(ctx tp.Context, bundle *probe.Bundle) (probe.Handler, error) { - shm := ctx.Config.GetString("agent.topology.vpp.connect") + addr := ctx.Config.GetString("agent.topology.vpp.connect") p := &Probe{ EventHandler: graph.NewEventHandler(100), Ctx: ctx, - shm: shm, + addr: addr, interfaceMap: make(map[uint32]*interfaces.SwInterfaceDetails), - notifChan: make(chan api.Message, 100), - intfIndexer: graph.NewMetadataIndexer(p.Ctx.Graph, p, nil, "IfIndex"), } - p.state.Store(common.StoppedState) + + p.intfIndexer = graph.NewMetadataIndexer(p.Ctx.Graph, p, nil, "IfIndex") /* Forward all govpp logging to Skydive logging */ l := logrus.New() @@ -365,7 +385,7 @@ func NewProbe(ctx tp.Context, bundle *probe.Bundle) (probe.Handler, error) { l.Hooks.Add(p) core.SetLogger(l) - return p, nil + return probes.NewProbeWrapper(p), nil } // Levels Logrus to Skydive logger helper From 0acc97a88c8fc68de2de1d6209761b01d788765c Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Tue, 23 Jul 2019 13:18:50 +0200 Subject: [PATCH 07/15] nsm: generate easyjson for metadata --- topology/probes/nsm/metadata_easyjson.go | 839 +++++++++++++++++++++++ 1 file changed, 839 insertions(+) create mode 100644 topology/probes/nsm/metadata_easyjson.go diff --git a/topology/probes/nsm/metadata_easyjson.go b/topology/probes/nsm/metadata_easyjson.go new file mode 100644 index 0000000000..d528ad286f --- /dev/null +++ b/topology/probes/nsm/metadata_easyjson.go @@ -0,0 +1,839 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package nsm + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm(in *jlexer.Lexer, out *RemoteNSMMetadata) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "SourceCrossConnectID": + out.SourceCrossConnectID = string(in.String()) + case "DestinationCrossConnectID": + out.DestinationCrossConnectID = string(in.String()) + case "Via": + (out.Via).UnmarshalEasyJSON(in) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm(out *jwriter.Writer, in RemoteNSMMetadata) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"SourceCrossConnectID\":" + out.RawString(prefix[1:]) + out.String(string(in.SourceCrossConnectID)) + } + { + const prefix string = ",\"DestinationCrossConnectID\":" + out.RawString(prefix) + out.String(string(in.DestinationCrossConnectID)) + } + { + const prefix string = ",\"Via\":" + out.RawString(prefix) + (in.Via).MarshalEasyJSON(out) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v RemoteNSMMetadata) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v RemoteNSMMetadata) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *RemoteNSMMetadata) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *RemoteNSMMetadata) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm(l, v) +} +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm1(in *jlexer.Lexer, out *RemoteConnectionMetadata) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "SourceNSM": + out.SourceNSM = string(in.String()) + case "DestinationNSM": + out.DestinationNSM = string(in.String()) + case "NetworkServiceEndpoint": + out.NetworkServiceEndpoint = string(in.String()) + case "MechanismType": + out.MechanismType = string(in.String()) + case "MechanismParameters": + if in.IsNull() { + in.Skip() + } else { + in.Delim('{') + if !in.IsDelim('}') { + out.MechanismParameters = make(map[string]string) + } else { + out.MechanismParameters = nil + } + for !in.IsDelim('}') { + key := string(in.String()) + in.WantColon() + var v1 string + v1 = string(in.String()) + (out.MechanismParameters)[key] = v1 + in.WantComma() + } + in.Delim('}') + } + case "Labels": + if in.IsNull() { + in.Skip() + } else { + in.Delim('{') + if !in.IsDelim('}') { + out.Labels = make(map[string]string) + } else { + out.Labels = nil + } + for !in.IsDelim('}') { + key := string(in.String()) + in.WantColon() + var v2 string + v2 = string(in.String()) + (out.Labels)[key] = v2 + in.WantComma() + } + in.Delim('}') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm1(out *jwriter.Writer, in RemoteConnectionMetadata) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"SourceNSM\":" + out.RawString(prefix[1:]) + out.String(string(in.SourceNSM)) + } + { + const prefix string = ",\"DestinationNSM\":" + out.RawString(prefix) + out.String(string(in.DestinationNSM)) + } + { + const prefix string = ",\"NetworkServiceEndpoint\":" + out.RawString(prefix) + out.String(string(in.NetworkServiceEndpoint)) + } + { + const prefix string = ",\"MechanismType\":" + out.RawString(prefix) + out.String(string(in.MechanismType)) + } + { + const prefix string = ",\"MechanismParameters\":" + out.RawString(prefix) + if in.MechanismParameters == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 { + out.RawString(`null`) + } else { + out.RawByte('{') + v3First := true + for v3Name, v3Value := range in.MechanismParameters { + if v3First { + v3First = false + } else { + out.RawByte(',') + } + out.String(string(v3Name)) + out.RawByte(':') + out.String(string(v3Value)) + } + out.RawByte('}') + } + } + { + const prefix string = ",\"Labels\":" + out.RawString(prefix) + if in.Labels == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 { + out.RawString(`null`) + } else { + out.RawByte('{') + v4First := true + for v4Name, v4Value := range in.Labels { + if v4First { + v4First = false + } else { + out.RawByte(',') + } + out.String(string(v4Name)) + out.RawByte(':') + out.String(string(v4Value)) + } + out.RawByte('}') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v RemoteConnectionMetadata) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm1(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v RemoteConnectionMetadata) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm1(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *RemoteConnectionMetadata) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm1(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *RemoteConnectionMetadata) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm1(l, v) +} +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm2(in *jlexer.Lexer, out *LocalNSMMetadata) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "CrossConnectID": + out.CrossConnectID = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm2(out *jwriter.Writer, in LocalNSMMetadata) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"CrossConnectID\":" + out.RawString(prefix[1:]) + out.String(string(in.CrossConnectID)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v LocalNSMMetadata) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm2(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v LocalNSMMetadata) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm2(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *LocalNSMMetadata) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm2(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *LocalNSMMetadata) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm2(l, v) +} +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm3(in *jlexer.Lexer, out *LocalConnectionMetadata) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "IP": + out.IP = string(in.String()) + case "MechanismType": + out.MechanismType = string(in.String()) + case "MechanismParameters": + if in.IsNull() { + in.Skip() + } else { + in.Delim('{') + if !in.IsDelim('}') { + out.MechanismParameters = make(map[string]string) + } else { + out.MechanismParameters = nil + } + for !in.IsDelim('}') { + key := string(in.String()) + in.WantColon() + var v5 string + v5 = string(in.String()) + (out.MechanismParameters)[key] = v5 + in.WantComma() + } + in.Delim('}') + } + case "Labels": + if in.IsNull() { + in.Skip() + } else { + in.Delim('{') + if !in.IsDelim('}') { + out.Labels = make(map[string]string) + } else { + out.Labels = nil + } + for !in.IsDelim('}') { + key := string(in.String()) + in.WantColon() + var v6 string + v6 = string(in.String()) + (out.Labels)[key] = v6 + in.WantComma() + } + in.Delim('}') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm3(out *jwriter.Writer, in LocalConnectionMetadata) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"IP\":" + out.RawString(prefix[1:]) + out.String(string(in.IP)) + } + { + const prefix string = ",\"MechanismType\":" + out.RawString(prefix) + out.String(string(in.MechanismType)) + } + { + const prefix string = ",\"MechanismParameters\":" + out.RawString(prefix) + if in.MechanismParameters == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 { + out.RawString(`null`) + } else { + out.RawByte('{') + v7First := true + for v7Name, v7Value := range in.MechanismParameters { + if v7First { + v7First = false + } else { + out.RawByte(',') + } + out.String(string(v7Name)) + out.RawByte(':') + out.String(string(v7Value)) + } + out.RawByte('}') + } + } + { + const prefix string = ",\"Labels\":" + out.RawString(prefix) + if in.Labels == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 { + out.RawString(`null`) + } else { + out.RawByte('{') + v8First := true + for v8Name, v8Value := range in.Labels { + if v8First { + v8First = false + } else { + out.RawByte(',') + } + out.String(string(v8Name)) + out.RawByte(':') + out.String(string(v8Value)) + } + out.RawByte('}') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v LocalConnectionMetadata) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm3(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v LocalConnectionMetadata) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm3(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *LocalConnectionMetadata) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm3(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *LocalConnectionMetadata) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm3(l, v) +} +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm4(in *jlexer.Lexer, out *EdgeMetadata) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "SourceCrossConnectID": + out.SourceCrossConnectID = string(in.String()) + case "DestinationCrossConnectID": + out.DestinationCrossConnectID = string(in.String()) + case "Via": + (out.Via).UnmarshalEasyJSON(in) + case "CrossConnectID": + out.CrossConnectID = string(in.String()) + case "NetworkService": + out.NetworkService = string(in.String()) + case "Payload": + out.Payload = string(in.String()) + case "Source": + (out.Source).UnmarshalEasyJSON(in) + case "Destination": + (out.Destination).UnmarshalEasyJSON(in) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm4(out *jwriter.Writer, in EdgeMetadata) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"SourceCrossConnectID\":" + out.RawString(prefix[1:]) + out.String(string(in.SourceCrossConnectID)) + } + { + const prefix string = ",\"DestinationCrossConnectID\":" + out.RawString(prefix) + out.String(string(in.DestinationCrossConnectID)) + } + { + const prefix string = ",\"Via\":" + out.RawString(prefix) + (in.Via).MarshalEasyJSON(out) + } + { + const prefix string = ",\"CrossConnectID\":" + out.RawString(prefix) + out.String(string(in.CrossConnectID)) + } + { + const prefix string = ",\"NetworkService\":" + out.RawString(prefix) + out.String(string(in.NetworkService)) + } + { + const prefix string = ",\"Payload\":" + out.RawString(prefix) + out.String(string(in.Payload)) + } + { + const prefix string = ",\"Source\":" + out.RawString(prefix) + (in.Source).MarshalEasyJSON(out) + } + { + const prefix string = ",\"Destination\":" + out.RawString(prefix) + (in.Destination).MarshalEasyJSON(out) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v EdgeMetadata) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm4(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v EdgeMetadata) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm4(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *EdgeMetadata) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm4(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *EdgeMetadata) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm4(l, v) +} +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm5(in *jlexer.Lexer, out *BaseNSMMetadata) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "NetworkService": + out.NetworkService = string(in.String()) + case "Payload": + out.Payload = string(in.String()) + case "Source": + (out.Source).UnmarshalEasyJSON(in) + case "Destination": + (out.Destination).UnmarshalEasyJSON(in) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm5(out *jwriter.Writer, in BaseNSMMetadata) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"NetworkService\":" + out.RawString(prefix[1:]) + out.String(string(in.NetworkService)) + } + { + const prefix string = ",\"Payload\":" + out.RawString(prefix) + out.String(string(in.Payload)) + } + { + const prefix string = ",\"Source\":" + out.RawString(prefix) + (in.Source).MarshalEasyJSON(out) + } + { + const prefix string = ",\"Destination\":" + out.RawString(prefix) + (in.Destination).MarshalEasyJSON(out) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v BaseNSMMetadata) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm5(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v BaseNSMMetadata) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm5(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *BaseNSMMetadata) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm5(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *BaseNSMMetadata) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm5(l, v) +} +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm6(in *jlexer.Lexer, out *BaseConnectionMetadata) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "MechanismType": + out.MechanismType = string(in.String()) + case "MechanismParameters": + if in.IsNull() { + in.Skip() + } else { + in.Delim('{') + if !in.IsDelim('}') { + out.MechanismParameters = make(map[string]string) + } else { + out.MechanismParameters = nil + } + for !in.IsDelim('}') { + key := string(in.String()) + in.WantColon() + var v9 string + v9 = string(in.String()) + (out.MechanismParameters)[key] = v9 + in.WantComma() + } + in.Delim('}') + } + case "Labels": + if in.IsNull() { + in.Skip() + } else { + in.Delim('{') + if !in.IsDelim('}') { + out.Labels = make(map[string]string) + } else { + out.Labels = nil + } + for !in.IsDelim('}') { + key := string(in.String()) + in.WantColon() + var v10 string + v10 = string(in.String()) + (out.Labels)[key] = v10 + in.WantComma() + } + in.Delim('}') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm6(out *jwriter.Writer, in BaseConnectionMetadata) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"MechanismType\":" + out.RawString(prefix[1:]) + out.String(string(in.MechanismType)) + } + { + const prefix string = ",\"MechanismParameters\":" + out.RawString(prefix) + if in.MechanismParameters == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 { + out.RawString(`null`) + } else { + out.RawByte('{') + v11First := true + for v11Name, v11Value := range in.MechanismParameters { + if v11First { + v11First = false + } else { + out.RawByte(',') + } + out.String(string(v11Name)) + out.RawByte(':') + out.String(string(v11Value)) + } + out.RawByte('}') + } + } + { + const prefix string = ",\"Labels\":" + out.RawString(prefix) + if in.Labels == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 { + out.RawString(`null`) + } else { + out.RawByte('{') + v12First := true + for v12Name, v12Value := range in.Labels { + if v12First { + v12First = false + } else { + out.RawByte(',') + } + out.String(string(v12Name)) + out.RawByte(':') + out.String(string(v12Value)) + } + out.RawByte('}') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v BaseConnectionMetadata) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm6(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v BaseConnectionMetadata) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesNsm6(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *BaseConnectionMetadata) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm6(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *BaseConnectionMetadata) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesNsm6(l, v) +} From 5fddaef1b66bf60e42381efbba10c3d40207ecd3 Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Tue, 23 Jul 2019 13:24:44 +0200 Subject: [PATCH 08/15] graffiti: separate index management from graph events handling --- graffiti/graph/indexer.go | 94 +++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/graffiti/graph/indexer.go b/graffiti/graph/indexer.go index 25cb0d37b0..9ff8dbd70b 100644 --- a/graffiti/graph/indexer.go +++ b/graffiti/graph/indexer.go @@ -38,29 +38,46 @@ func Hash(values ...interface{}) string { return h } -// Indexer provides a way to index graph nodes. A node can be mapped to +// NodeIndex provides a way to index graph nodes. A node can be mapped to // multiple hash,value pairs. A hash can also be mapped to multiple nodes. -type Indexer struct { +type NodeIndex struct { common.RWMutex + graph *Graph + eventHandler *EventHandler + hashNode NodeHasher + appendOnly bool + hashToValues map[string]map[Identifier]interface{} + nodeToHashes map[Identifier]map[string]bool +} + +// Indexer listens and indexes nodes using an Index +type Indexer struct { + *NodeIndex DefaultGraphListener - graph *Graph - eventHandler *EventHandler listenerHandler ListenerHandler hashNode NodeHasher - appendOnly bool - hashToValues map[string]map[Identifier]interface{} - nodeToHashes map[Identifier]map[string]bool +} + +// FromHash returns the nodes mapped by a hash along with their associated values +func (i *NodeIndex) FromHash(hash string) (nodes []*Node, values []interface{}) { + if ids, found := i.hashToValues[hash]; found { + for id, obj := range ids { + nodes = append(nodes, i.graph.GetNode(id)) + values = append(values, obj) + } + } + return } // Get computes the hash of the passed parameters and returns the matching // nodes with their respective value -func (i *Indexer) Get(values ...interface{}) ([]*Node, []interface{}) { +func (i *NodeIndex) Get(values ...interface{}) ([]*Node, []interface{}) { return i.FromHash(Hash(values...)) } // GetNode computes the hash of the passed parameters and returns the first // matching node with its respective value -func (i *Indexer) GetNode(values ...interface{}) (*Node, interface{}) { +func (i *NodeIndex) GetNode(values ...interface{}) (*Node, interface{}) { nodes, values := i.Get(values...) if len(nodes) > 0 && len(values) > 0 { return nodes[0], values[0] @@ -68,7 +85,7 @@ func (i *Indexer) GetNode(values ...interface{}) (*Node, interface{}) { return nil, nil } -func (i *Indexer) index(id Identifier, h string, value interface{}) { +func (i *NodeIndex) index(id Identifier, h string, value interface{}) { if _, found := i.hashToValues[h]; !found { i.hashToValues[h] = make(map[Identifier]interface{}) } @@ -76,7 +93,7 @@ func (i *Indexer) index(id Identifier, h string, value interface{}) { i.nodeToHashes[id][h] = true } -func (i *Indexer) unindex(id Identifier, h string) { +func (i *NodeIndex) unindex(id Identifier, h string) { delete(i.hashToValues[h], id) if len(i.hashToValues[h]) == 0 { delete(i.hashToValues, h) @@ -84,7 +101,7 @@ func (i *Indexer) unindex(id Identifier, h string) { } // Index indexes a node with a set of hash -> value map -func (i *Indexer) Index(id Identifier, n *Node, kv map[string]interface{}) { +func (i *NodeIndex) Index(id Identifier, n *Node, kv map[string]interface{}) { i.Lock() defer i.Unlock() @@ -115,7 +132,7 @@ func (i *Indexer) Index(id Identifier, n *Node, kv map[string]interface{}) { } // Unindex removes the node and its associated hashes from the index -func (i *Indexer) Unindex(id Identifier, n *Node) { +func (i *NodeIndex) Unindex(id Identifier, n *Node) { i.Lock() defer i.Unlock() @@ -129,6 +146,27 @@ func (i *Indexer) Unindex(id Identifier, n *Node) { } } +// AddEventListener subscribes a new graph listener +func (i *NodeIndex) AddEventListener(l EventListener) { + i.eventHandler.AddEventListener(l) +} + +// RemoveEventListener unsubscribe a graph listener +func (i *NodeIndex) RemoveEventListener(l EventListener) { + i.eventHandler.RemoveEventListener(l) +} + +// NewNodeIndex returns a new node index +func NewNodeIndex(g *Graph, appendOnly bool) *NodeIndex { + return &NodeIndex{ + graph: g, + eventHandler: NewEventHandler(maxEvents), + hashToValues: make(map[string]map[Identifier]interface{}), + nodeToHashes: make(map[Identifier]map[string]bool), + appendOnly: appendOnly, + } +} + // OnNodeAdded event func (i *Indexer) OnNodeAdded(n *Node) { if kv := i.hashNode(n); len(kv) != 0 { @@ -150,17 +188,6 @@ func (i *Indexer) OnNodeDeleted(n *Node) { i.Unindex(n.ID, n) } -// FromHash returns the nodes mapped by a hash along with their associated values -func (i *Indexer) FromHash(hash string) (nodes []*Node, values []interface{}) { - if ids, found := i.hashToValues[hash]; found { - for id, obj := range ids { - nodes = append(nodes, i.graph.GetNode(id)) - values = append(values, obj) - } - } - return -} - // Start registers the graph indexer as a graph listener func (i *Indexer) Start() error { if i.listenerHandler != nil { @@ -176,26 +203,15 @@ func (i *Indexer) Stop() { } } -// AddEventListener subscribes a new graph listener -func (i *Indexer) AddEventListener(l EventListener) { - i.eventHandler.AddEventListener(l) -} - -// RemoveEventListener unsubscribe a graph listener -func (i *Indexer) RemoveEventListener(l EventListener) { - i.eventHandler.RemoveEventListener(l) -} - // NewIndexer returns a new graph indexer with the associated hashing callback func NewIndexer(g *Graph, listenerHandler ListenerHandler, hashNode NodeHasher, appendOnly bool) *Indexer { + if hashNode == nil { + hashNode = func(n *Node) map[string]interface{} { return nil } + } indexer := &Indexer{ - graph: g, - eventHandler: NewEventHandler(maxEvents), + NodeIndex: NewNodeIndex(g, appendOnly), listenerHandler: listenerHandler, hashNode: hashNode, - hashToValues: make(map[string]map[Identifier]interface{}), - nodeToHashes: make(map[Identifier]map[string]bool), - appendOnly: appendOnly, } return indexer } From c196327a0b3442a33dda5952ec2136c48e6c4ad7 Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Tue, 23 Jul 2019 13:26:34 +0200 Subject: [PATCH 09/15] topology: add GetOwner method --- topology/probes/ovn/ovn.go | 35 +++++++---------------------------- topology/topology.go | 22 +++++++++------------- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/topology/probes/ovn/ovn.go b/topology/probes/ovn/ovn.go index c3d8df0035..d655393b7c 100644 --- a/topology/probes/ovn/ovn.go +++ b/topology/probes/ovn/ovn.go @@ -132,11 +132,7 @@ func (l *switchPortLinker) GetABLinks(lsNode *graph.Node) (edges []*graph.Edge) ports, _ := l.probe.ovndbapi.LSPList(name) for _, lp := range ports { if lpNode, _ := probe.lspIndexer.GetNode(lp.UUID); lpNode != nil { - link, err := topology.NewLink(probe.graph, lsNode, lpNode, topology.OwnershipLink, nil) - if err != nil { - logging.GetLogger().Error(err) - continue - } + link := topology.NewLink(probe.graph, lsNode, lpNode, topology.OwnershipLink, nil) edges = append(edges, link) } } @@ -153,11 +149,7 @@ func (l *switchPortLinker) GetBALinks(lpNode *graph.Node) (edges []*graph.Edge) for _, lp := range ports { if lp.UUID == uuid { if lsNode, _ := probe.lsIndexer.GetNode(ls.UUID); lsNode != nil { - link, err := topology.NewLink(probe.graph, lsNode, lpNode, topology.OwnershipLink, nil) - if err != nil { - logging.GetLogger().Error(link) - continue - } + link := topology.NewLink(probe.graph, lsNode, lpNode, topology.OwnershipLink, nil) edges = append(edges, link) } } @@ -177,11 +169,7 @@ func (l *routerPortLinker) GetABLinks(lrNode *graph.Node) (edges []*graph.Edge) ports, _ := l.probe.ovndbapi.LRPList(name) for _, lp := range ports { if lrpNode, _ := probe.lrpIndexer.GetNode(lp.UUID); lrpNode != nil { - link, err := topology.NewLink(probe.graph, lrNode, lrpNode, topology.OwnershipLink, nil) - if err != nil { - logging.GetLogger().Error(err) - continue - } + link := topology.NewLink(probe.graph, lrNode, lrpNode, topology.OwnershipLink, nil) edges = append(edges, link) } } @@ -198,11 +186,7 @@ func (l *routerPortLinker) GetBALinks(lrpNode *graph.Node) (edges []*graph.Edge) for _, lp := range ports { if lp.UUID == uuid { if lrNode, _ := probe.lrIndexer.GetNode(lr.UUID); lrNode != nil { - link, err := topology.NewLink(probe.graph, lrNode, lrpNode, topology.OwnershipLink, nil) - if err != nil { - logging.GetLogger().Error(link) - continue - } + link := topology.NewLink(probe.graph, lrNode, lrpNode, topology.OwnershipLink, nil) edges = append(edges, link) } } @@ -221,9 +205,8 @@ func (l *aclLinker) GetABLinks(lsNode *graph.Node) (edges []*graph.Edge) { acls, _ := l.probe.ovndbapi.ACLList(name) for _, acl := range acls { if aclNode, _ := l.probe.aclIndexer.GetNode(acl.UUID); aclNode != nil { - if link, _ := topology.NewLink(l.probe.graph, lsNode, aclNode, topology.OwnershipLink, nil); link != nil { - edges = append(edges, link) - } + link := topology.NewLink(l.probe.graph, lsNode, aclNode, topology.OwnershipLink, nil) + edges = append(edges, link) } } return edges @@ -238,11 +221,7 @@ func (l *aclLinker) GetBALinks(aclNode *graph.Node) (edges []*graph.Edge) { for _, acl := range acls { if acl.UUID == uuid { if lsNode, _ := l.probe.lsIndexer.GetNode(ls.UUID); lsNode != nil { - link, err := topology.NewLink(l.probe.graph, lsNode, aclNode, topology.OwnershipLink, nil) - if err != nil { - logging.GetLogger().Error(link) - continue - } + link := topology.NewLink(l.probe.graph, lsNode, aclNode, topology.OwnershipLink, nil) edges = append(edges, link) } } diff --git a/topology/topology.go b/topology/topology.go index f5e56a0311..df83c0cf24 100644 --- a/topology/topology.go +++ b/topology/topology.go @@ -120,9 +120,12 @@ func IsOwnershipLinked(g *graph.Graph, node *graph.Node) bool { return len(edges) != 0 } -// GetOwnershipLink get ownership Link between the parent and the child node or nil -func GetOwnershipLink(g *graph.Graph, parent *graph.Node, child *graph.Node) *graph.Edge { - return g.GetFirstLink(parent, child, OwnershipMetadata()) +// GetOwner returns the parent linked with an ownership link +func GetOwner(g *graph.Graph, child *graph.Node) *graph.Node { + if parents := g.LookupParents(child, nil, OwnershipMetadata()); len(parents) > 0 { + return parents[0] + } + return nil } // AddOwnershipLink Link between the parent and the child node, the child can have only one parent, previous will be overwritten @@ -146,26 +149,19 @@ func HaveLink(g *graph.Graph, node1 *graph.Node, node2 *graph.Node, relationType } // NewLink creates a link between a parent and a child node with the specified relation type and metadata -func NewLink(g *graph.Graph, node1 *graph.Node, node2 *graph.Node, relationType string, metadata graph.Metadata) (*graph.Edge, error) { +func NewLink(g *graph.Graph, node1 *graph.Node, node2 *graph.Node, relationType string, metadata graph.Metadata) *graph.Edge { m := graph.Metadata{"RelationType": relationType} for k, v := range metadata { m[k] = v } id, _ := uuid.NewV5(uuid.NamespaceOID, []byte(node1.ID+node2.ID+graph.Identifier(relationType))) - edge := g.CreateEdge(graph.Identifier(id.String()), node1, node2, m, graph.Time(time.Now())) - if edge == nil { - return nil, fmt.Errorf("Failed to create edge with id %s", id.String()) - } - return edge, nil + return g.CreateEdge(graph.Identifier(id.String()), node1, node2, m, graph.Time(time.Now())) } // AddLink links the parent and the child node with the specified relation type and metadata func AddLink(g *graph.Graph, node1 *graph.Node, node2 *graph.Node, relationType string, metadata graph.Metadata) (*graph.Edge, error) { - edge, err := NewLink(g, node1, node2, relationType, metadata) - if err != nil { - return nil, err - } + edge := NewLink(g, node1, node2, relationType, metadata) return edge, g.AddEdge(edge) } From 95adbec83b544ef69f13a1528ecbff32b2be9574 Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Tue, 23 Jul 2019 13:28:19 +0200 Subject: [PATCH 10/15] vpp: run seeds in containers and handle memifs --- analyzer/server.go | 2 + statics/css/skydive.css | 2 +- tests/vpp_test.go | 4 +- topology/probes/docker/metadata_easyjson.go | 136 +++- topology/probes/docker/metadata_gendecoder.go | 90 +++ .../vpp/bin_api/interfaces/interfaces.ba.go | 591 +++++++++++++----- topology/probes/vpp/bin_api/memif/memif.ba.go | 337 ++++++++++ topology/probes/vpp/bin_api/vpe/vpe.ba.go | 251 +++++--- topology/probes/vpp/metadata.go | 52 ++ topology/probes/vpp/metadata_easyjson.go | 134 ++++ topology/probes/vpp/metadata_gendecoder.go | 96 +++ topology/probes/vpp/vpp.go | 303 ++++++++- 12 files changed, 1738 insertions(+), 260 deletions(-) create mode 100644 topology/probes/vpp/bin_api/memif/memif.ba.go create mode 100644 topology/probes/vpp/metadata.go create mode 100644 topology/probes/vpp/metadata_easyjson.go create mode 100644 topology/probes/vpp/metadata_gendecoder.go diff --git a/analyzer/server.go b/analyzer/server.go index c086f7bc7f..dc598a99e1 100644 --- a/analyzer/server.go +++ b/analyzer/server.go @@ -58,6 +58,7 @@ import ( "github.com/skydive-project/skydive/topology/probes/ovn" "github.com/skydive-project/skydive/topology/probes/ovsdb" "github.com/skydive-project/skydive/topology/probes/runc" + "github.com/skydive-project/skydive/topology/probes/vpp" "github.com/skydive-project/skydive/ui" "github.com/skydive-project/skydive/websocket" ws "github.com/skydive-project/skydive/websocket" @@ -431,6 +432,7 @@ func init() { graph.NodeMetadataDecoders["OVN"] = ovn.MetadataDecoder graph.NodeMetadataDecoders["Neutron"] = neutron.MetadataDecoder graph.NodeMetadataDecoders["Contrail"] = opencontrail.MetadataDecoder + graph.NodeMetadataDecoders["VPP"] = vpp.MetadataDecoder graph.EdgeMetadataDecoders["NSM"] = nsm.MetadataDecoder } diff --git a/statics/css/skydive.css b/statics/css/skydive.css index 39685628aa..8e30d76e1c 100644 --- a/statics/css/skydive.css +++ b/statics/css/skydive.css @@ -138,7 +138,7 @@ label { color: #ffffff; } -.mode { +.navbar-brand .mode { color: white; font-size: 0.8em; padding-left: 26px; diff --git a/tests/vpp_test.go b/tests/vpp_test.go index 56f7f9253d..22762a73a6 100644 --- a/tests/vpp_test.go +++ b/tests/vpp_test.go @@ -36,7 +36,7 @@ func createLoopback(t *testing.T) string { if err != nil { t.Error("Can't create vpp loopback interface ", err) } - time.Sleep(2 * vpp.VPPPollingTime * time.Millisecond) + time.Sleep(vpp.VPPPollingTime) return strings.Trim(string(out), "\r\n") } @@ -46,7 +46,7 @@ func deleteLoopback(t *testing.T, intf string) string { if err != nil { t.Error("Can't delete vpp loopback interface ", intf, " : ", err) } - time.Sleep(2 * vpp.VPPPollingTime * time.Millisecond) + time.Sleep(vpp.VPPPollingTime) return strings.Trim(string(out), "\r\n") } diff --git a/topology/probes/docker/metadata_easyjson.go b/topology/probes/docker/metadata_easyjson.go index a02855db76..bd73894515 100644 --- a/topology/probes/docker/metadata_easyjson.go +++ b/topology/probes/docker/metadata_easyjson.go @@ -17,7 +17,80 @@ var ( _ easyjson.Marshaler ) -func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(in *jlexer.Lexer, out *Metadata) { +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(in *jlexer.Lexer, out *Mount) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "Source": + out.Source = string(in.String()) + case "Destination": + out.Destination = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(out *jwriter.Writer, in Mount) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"Source\":" + out.RawString(prefix[1:]) + out.String(string(in.Source)) + } + { + const prefix string = ",\"Destination\":" + out.RawString(prefix) + out.String(string(in.Destination)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v Mount) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v Mount) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *Mount) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *Mount) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(l, v) +} +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker1(in *jlexer.Lexer, out *Metadata) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -42,6 +115,37 @@ func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(in out.ContainerName = string(in.String()) case "Labels": (out.Labels).UnmarshalEasyJSON(in) + case "Mounts": + if in.IsNull() { + in.Skip() + out.Mounts = nil + } else { + in.Delim('[') + if out.Mounts == nil { + if !in.IsDelim(']') { + out.Mounts = make([]*Mount, 0, 8) + } else { + out.Mounts = []*Mount{} + } + } else { + out.Mounts = (out.Mounts)[:0] + } + for !in.IsDelim(']') { + var v1 *Mount + if in.IsNull() { + in.Skip() + v1 = nil + } else { + if v1 == nil { + v1 = new(Mount) + } + (*v1).UnmarshalEasyJSON(in) + } + out.Mounts = append(out.Mounts, v1) + in.WantComma() + } + in.Delim(']') + } default: in.SkipRecursive() } @@ -52,7 +156,7 @@ func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(in in.Consumed() } } -func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(out *jwriter.Writer, in Metadata) { +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker1(out *jwriter.Writer, in Metadata) { out.RawByte('{') first := true _ = first @@ -71,29 +175,49 @@ func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(ou out.RawString(prefix) (in.Labels).MarshalEasyJSON(out) } + { + const prefix string = ",\"Mounts\":" + out.RawString(prefix) + if in.Mounts == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v2, v3 := range in.Mounts { + if v2 > 0 { + out.RawByte(',') + } + if v3 == nil { + out.RawString("null") + } else { + (*v3).MarshalEasyJSON(out) + } + } + out.RawByte(']') + } + } out.RawByte('}') } // MarshalJSON supports json.Marshaler interface func (v Metadata) MarshalJSON() ([]byte, error) { w := jwriter.Writer{} - easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(&w, v) + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker1(&w, v) return w.Buffer.BuildBytes(), w.Error } // MarshalEasyJSON supports easyjson.Marshaler interface func (v Metadata) MarshalEasyJSON(w *jwriter.Writer) { - easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(w, v) + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesDocker1(w, v) } // UnmarshalJSON supports json.Unmarshaler interface func (v *Metadata) UnmarshalJSON(data []byte) error { r := jlexer.Lexer{Data: data} - easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(&r, v) + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker1(&r, v) return r.Error() } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *Metadata) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker(l, v) + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesDocker1(l, v) } diff --git a/topology/probes/docker/metadata_gendecoder.go b/topology/probes/docker/metadata_gendecoder.go index 0f42410798..7fff3a707f 100644 --- a/topology/probes/docker/metadata_gendecoder.go +++ b/topology/probes/docker/metadata_gendecoder.go @@ -30,6 +30,7 @@ func (obj *Metadata) GetFieldKeys() []string { "ContainerID", "ContainerName", "Labels", + "Mounts", } } @@ -45,6 +46,14 @@ func (obj *Metadata) MatchBool(key string, predicate common.BoolPredicate) bool if index != -1 && obj.Labels != nil { return obj.Labels.MatchBool(key[index+1:], predicate) } + case "Mounts": + if index != -1 { + for _, obj := range obj.Mounts { + if obj.MatchBool(key[index+1:], predicate) { + return true + } + } + } } return false } @@ -62,6 +71,14 @@ func (obj *Metadata) MatchInt64(key string, predicate common.Int64Predicate) boo if index != -1 && obj.Labels != nil { return obj.Labels.MatchInt64(key[index+1:], predicate) } + case "Mounts": + if index != -1 { + for _, obj := range obj.Mounts { + if obj.MatchInt64(key[index+1:], predicate) { + return true + } + } + } } return false } @@ -83,6 +100,14 @@ func (obj *Metadata) MatchString(key string, predicate common.StringPredicate) b if index != -1 && obj.Labels != nil { return obj.Labels.MatchString(key[index+1:], predicate) } + case "Mounts": + if index != -1 { + for _, obj := range obj.Mounts { + if obj.MatchString(key[index+1:], predicate) { + return true + } + } + } } return false } @@ -107,7 +132,72 @@ func (obj *Metadata) GetField(key string) (interface{}, error) { return obj.Labels, nil } } + case "Mounts": + if obj.Mounts != nil { + if index != -1 { + var results []interface{} + for _, obj := range obj.Mounts { + if field, err := obj.GetField(key[index+1:]); err == nil { + results = append(results, field) + } + } + return results, nil + } else { + var results []interface{} + for _, obj := range obj.Mounts { + results = append(results, obj) + } + return results, nil + } + } + + } + return nil, common.ErrFieldNotFound +} + +func (obj *Mount) GetFieldBool(key string) (bool, error) { + return false, common.ErrFieldNotFound +} +func (obj *Mount) GetFieldInt64(key string) (int64, error) { + return 0, common.ErrFieldNotFound +} + +func (obj *Mount) GetFieldString(key string) (string, error) { + switch key { + case "Source": + return string(obj.Source), nil + case "Destination": + return string(obj.Destination), nil + } + return "", common.ErrFieldNotFound +} + +func (obj *Mount) GetFieldKeys() []string { + return []string{ + "Source", + "Destination", + } +} + +func (obj *Mount) MatchBool(key string, predicate common.BoolPredicate) bool { + return false +} + +func (obj *Mount) MatchInt64(key string, predicate common.Int64Predicate) bool { + return false +} + +func (obj *Mount) MatchString(key string, predicate common.StringPredicate) bool { + if b, err := obj.GetFieldString(key); err == nil { + return predicate(b) + } + return false +} + +func (obj *Mount) GetField(key string) (interface{}, error) { + if s, err := obj.GetFieldString(key); err == nil { + return s, nil } return nil, common.ErrFieldNotFound } diff --git a/topology/probes/vpp/bin_api/interfaces/interfaces.ba.go b/topology/probes/vpp/bin_api/interfaces/interfaces.ba.go index 9d44ad249a..13f8ae4464 100644 --- a/topology/probes/vpp/bin_api/interfaces/interfaces.ba.go +++ b/topology/probes/vpp/bin_api/interfaces/interfaces.ba.go @@ -1,62 +1,38 @@ -// Code generated by GoVPP binapi-generator. DO NOT EDIT. -// source: /usr/share/vpp/api/interface.api.json +// Code generated by GoVPP's binapi-generator. DO NOT EDIT. +// source: /usr/share/vpp/api/interface.api.json /* - Package interfaces is a generated from VPP binary API module 'interface'. +Package interfaces is a generated VPP binary API for 'interface' module. - It contains following objects: - 25 services +It consists of: 1 alias 51 messages + 25 services */ package interfaces -import api "git.fd.io/govpp.git/api" -import struc "github.com/lunixbochs/struc" -import bytes "bytes" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = api.RegisterMessage -var _ = struc.Pack -var _ = bytes.NewBuffer - -// Services represents VPP binary API services: -type Services interface { - DumpSwInterface(*SwInterfaceDump) ([]*SwInterfaceDetails, error) - DumpSwInterfaceRxPlacement(*SwInterfaceRxPlacementDump) ([]*SwInterfaceRxPlacementDetails, error) - CollectDetailedInterfaceStats(*CollectDetailedInterfaceStats) (*CollectDetailedInterfaceStatsReply, error) - CreateLoopback(*CreateLoopback) (*CreateLoopbackReply, error) - CreateLoopbackInstance(*CreateLoopbackInstance) (*CreateLoopbackInstanceReply, error) - CreateSubif(*CreateSubif) (*CreateSubifReply, error) - CreateVlanSubif(*CreateVlanSubif) (*CreateVlanSubifReply, error) - DeleteLoopback(*DeleteLoopback) (*DeleteLoopbackReply, error) - DeleteSubif(*DeleteSubif) (*DeleteSubifReply, error) - HwInterfaceSetMtu(*HwInterfaceSetMtu) (*HwInterfaceSetMtuReply, error) - InterfaceNameRenumber(*InterfaceNameRenumber) (*InterfaceNameRenumberReply, error) - SwInterfaceAddDelAddress(*SwInterfaceAddDelAddress) (*SwInterfaceAddDelAddressReply, error) - SwInterfaceClearStats(*SwInterfaceClearStats) (*SwInterfaceClearStatsReply, error) - SwInterfaceGetMacAddress(*SwInterfaceGetMacAddress) (*SwInterfaceGetMacAddressReply, error) - SwInterfaceGetTable(*SwInterfaceGetTable) (*SwInterfaceGetTableReply, error) - SwInterfaceSetFlags(*SwInterfaceSetFlags) (*SwInterfaceSetFlagsReply, error) - SwInterfaceSetIPDirectedBroadcast(*SwInterfaceSetIPDirectedBroadcast) (*SwInterfaceSetIPDirectedBroadcastReply, error) - SwInterfaceSetMacAddress(*SwInterfaceSetMacAddress) (*SwInterfaceSetMacAddressReply, error) - SwInterfaceSetMtu(*SwInterfaceSetMtu) (*SwInterfaceSetMtuReply, error) - SwInterfaceSetRxMode(*SwInterfaceSetRxMode) (*SwInterfaceSetRxModeReply, error) - SwInterfaceSetRxPlacement(*SwInterfaceSetRxPlacement) (*SwInterfaceSetRxPlacementReply, error) - SwInterfaceSetTable(*SwInterfaceSetTable) (*SwInterfaceSetTableReply, error) - SwInterfaceSetUnnumbered(*SwInterfaceSetUnnumbered) (*SwInterfaceSetUnnumberedReply, error) - SwInterfaceTagAddDel(*SwInterfaceTagAddDel) (*SwInterfaceTagAddDelReply, error) - WantInterfaceEvents(*WantInterfaceEvents) (*WantInterfaceEventsReply, error) -} - -/* Aliases */ - -// InterfaceIndex represents VPP binary API alias 'interface_index': +import ( + bytes "bytes" + context "context" + api "git.fd.io/govpp.git/api" + struc "github.com/lunixbochs/struc" + io "io" + strconv "strconv" +) + +const ( + // ModuleName is the name of this module. + ModuleName = "interface" + // APIVersion is the API version of this module. + APIVersion = "2.2.0" + // VersionCrc is the CRC of this module. + VersionCrc = 0x672de521 +) + +// InterfaceIndex represents VPP binary API alias 'interface_index'. type InterfaceIndex uint32 -/* Messages */ - -// CollectDetailedInterfaceStats represents VPP binary API message 'collect_detailed_interface_stats': +// CollectDetailedInterfaceStats represents VPP binary API message 'collect_detailed_interface_stats'. type CollectDetailedInterfaceStats struct { SwIfIndex uint32 EnableDisable uint8 @@ -72,7 +48,7 @@ func (*CollectDetailedInterfaceStats) GetMessageType() api.MessageType { return api.RequestMessage } -// CollectDetailedInterfaceStatsReply represents VPP binary API message 'collect_detailed_interface_stats_reply': +// CollectDetailedInterfaceStatsReply represents VPP binary API message 'collect_detailed_interface_stats_reply'. type CollectDetailedInterfaceStatsReply struct { Retval int32 } @@ -87,7 +63,7 @@ func (*CollectDetailedInterfaceStatsReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// CreateLoopback represents VPP binary API message 'create_loopback': +// CreateLoopback represents VPP binary API message 'create_loopback'. type CreateLoopback struct { MacAddress []byte `struc:"[6]byte"` } @@ -102,7 +78,7 @@ func (*CreateLoopback) GetMessageType() api.MessageType { return api.RequestMessage } -// CreateLoopbackInstance represents VPP binary API message 'create_loopback_instance': +// CreateLoopbackInstance represents VPP binary API message 'create_loopback_instance'. type CreateLoopbackInstance struct { MacAddress []byte `struc:"[6]byte"` IsSpecified uint8 @@ -119,7 +95,7 @@ func (*CreateLoopbackInstance) GetMessageType() api.MessageType { return api.RequestMessage } -// CreateLoopbackInstanceReply represents VPP binary API message 'create_loopback_instance_reply': +// CreateLoopbackInstanceReply represents VPP binary API message 'create_loopback_instance_reply'. type CreateLoopbackInstanceReply struct { Retval int32 SwIfIndex uint32 @@ -135,7 +111,7 @@ func (*CreateLoopbackInstanceReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// CreateLoopbackReply represents VPP binary API message 'create_loopback_reply': +// CreateLoopbackReply represents VPP binary API message 'create_loopback_reply'. type CreateLoopbackReply struct { Retval int32 SwIfIndex uint32 @@ -151,7 +127,7 @@ func (*CreateLoopbackReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// CreateSubif represents VPP binary API message 'create_subif': +// CreateSubif represents VPP binary API message 'create_subif'. type CreateSubif struct { SwIfIndex uint32 SubID uint32 @@ -177,7 +153,7 @@ func (*CreateSubif) GetMessageType() api.MessageType { return api.RequestMessage } -// CreateSubifReply represents VPP binary API message 'create_subif_reply': +// CreateSubifReply represents VPP binary API message 'create_subif_reply'. type CreateSubifReply struct { Retval int32 SwIfIndex uint32 @@ -193,7 +169,7 @@ func (*CreateSubifReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// CreateVlanSubif represents VPP binary API message 'create_vlan_subif': +// CreateVlanSubif represents VPP binary API message 'create_vlan_subif'. type CreateVlanSubif struct { SwIfIndex uint32 VlanID uint32 @@ -209,7 +185,7 @@ func (*CreateVlanSubif) GetMessageType() api.MessageType { return api.RequestMessage } -// CreateVlanSubifReply represents VPP binary API message 'create_vlan_subif_reply': +// CreateVlanSubifReply represents VPP binary API message 'create_vlan_subif_reply'. type CreateVlanSubifReply struct { Retval int32 SwIfIndex uint32 @@ -225,7 +201,7 @@ func (*CreateVlanSubifReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// DeleteLoopback represents VPP binary API message 'delete_loopback': +// DeleteLoopback represents VPP binary API message 'delete_loopback'. type DeleteLoopback struct { SwIfIndex uint32 } @@ -240,7 +216,7 @@ func (*DeleteLoopback) GetMessageType() api.MessageType { return api.RequestMessage } -// DeleteLoopbackReply represents VPP binary API message 'delete_loopback_reply': +// DeleteLoopbackReply represents VPP binary API message 'delete_loopback_reply'. type DeleteLoopbackReply struct { Retval int32 } @@ -255,7 +231,7 @@ func (*DeleteLoopbackReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// DeleteSubif represents VPP binary API message 'delete_subif': +// DeleteSubif represents VPP binary API message 'delete_subif'. type DeleteSubif struct { SwIfIndex uint32 } @@ -270,7 +246,7 @@ func (*DeleteSubif) GetMessageType() api.MessageType { return api.RequestMessage } -// DeleteSubifReply represents VPP binary API message 'delete_subif_reply': +// DeleteSubifReply represents VPP binary API message 'delete_subif_reply'. type DeleteSubifReply struct { Retval int32 } @@ -285,7 +261,7 @@ func (*DeleteSubifReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// HwInterfaceSetMtu represents VPP binary API message 'hw_interface_set_mtu': +// HwInterfaceSetMtu represents VPP binary API message 'hw_interface_set_mtu'. type HwInterfaceSetMtu struct { SwIfIndex uint32 Mtu uint16 @@ -301,7 +277,7 @@ func (*HwInterfaceSetMtu) GetMessageType() api.MessageType { return api.RequestMessage } -// HwInterfaceSetMtuReply represents VPP binary API message 'hw_interface_set_mtu_reply': +// HwInterfaceSetMtuReply represents VPP binary API message 'hw_interface_set_mtu_reply'. type HwInterfaceSetMtuReply struct { Retval int32 } @@ -316,7 +292,7 @@ func (*HwInterfaceSetMtuReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// InterfaceNameRenumber represents VPP binary API message 'interface_name_renumber': +// InterfaceNameRenumber represents VPP binary API message 'interface_name_renumber'. type InterfaceNameRenumber struct { SwIfIndex uint32 NewShowDevInstance uint32 @@ -332,7 +308,7 @@ func (*InterfaceNameRenumber) GetMessageType() api.MessageType { return api.RequestMessage } -// InterfaceNameRenumberReply represents VPP binary API message 'interface_name_renumber_reply': +// InterfaceNameRenumberReply represents VPP binary API message 'interface_name_renumber_reply'. type InterfaceNameRenumberReply struct { Retval int32 } @@ -347,7 +323,7 @@ func (*InterfaceNameRenumberReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceAddDelAddress represents VPP binary API message 'sw_interface_add_del_address': +// SwInterfaceAddDelAddress represents VPP binary API message 'sw_interface_add_del_address'. type SwInterfaceAddDelAddress struct { SwIfIndex uint32 IsAdd uint8 @@ -367,7 +343,7 @@ func (*SwInterfaceAddDelAddress) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceAddDelAddressReply represents VPP binary API message 'sw_interface_add_del_address_reply': +// SwInterfaceAddDelAddressReply represents VPP binary API message 'sw_interface_add_del_address_reply'. type SwInterfaceAddDelAddressReply struct { Retval int32 } @@ -382,7 +358,7 @@ func (*SwInterfaceAddDelAddressReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceClearStats represents VPP binary API message 'sw_interface_clear_stats': +// SwInterfaceClearStats represents VPP binary API message 'sw_interface_clear_stats'. type SwInterfaceClearStats struct { SwIfIndex uint32 } @@ -397,7 +373,7 @@ func (*SwInterfaceClearStats) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceClearStatsReply represents VPP binary API message 'sw_interface_clear_stats_reply': +// SwInterfaceClearStatsReply represents VPP binary API message 'sw_interface_clear_stats_reply'. type SwInterfaceClearStatsReply struct { Retval int32 } @@ -412,7 +388,7 @@ func (*SwInterfaceClearStatsReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceDetails represents VPP binary API message 'sw_interface_details': +// SwInterfaceDetails represents VPP binary API message 'sw_interface_details'. type SwInterfaceDetails struct { SwIfIndex uint32 SupSwIfIndex uint32 @@ -457,7 +433,7 @@ func (*SwInterfaceDetails) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceDump represents VPP binary API message 'sw_interface_dump': +// SwInterfaceDump represents VPP binary API message 'sw_interface_dump'. type SwInterfaceDump struct { NameFilterValid uint8 NameFilter []byte `struc:"[49]byte"` @@ -473,7 +449,7 @@ func (*SwInterfaceDump) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceEvent represents VPP binary API message 'sw_interface_event': +// SwInterfaceEvent represents VPP binary API message 'sw_interface_event'. type SwInterfaceEvent struct { PID uint32 SwIfIndex uint32 @@ -492,7 +468,7 @@ func (*SwInterfaceEvent) GetMessageType() api.MessageType { return api.EventMessage } -// SwInterfaceGetMacAddress represents VPP binary API message 'sw_interface_get_mac_address': +// SwInterfaceGetMacAddress represents VPP binary API message 'sw_interface_get_mac_address'. type SwInterfaceGetMacAddress struct { SwIfIndex uint32 } @@ -507,7 +483,7 @@ func (*SwInterfaceGetMacAddress) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceGetMacAddressReply represents VPP binary API message 'sw_interface_get_mac_address_reply': +// SwInterfaceGetMacAddressReply represents VPP binary API message 'sw_interface_get_mac_address_reply'. type SwInterfaceGetMacAddressReply struct { Retval int32 MacAddress []byte `struc:"[6]byte"` @@ -523,7 +499,7 @@ func (*SwInterfaceGetMacAddressReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceGetTable represents VPP binary API message 'sw_interface_get_table': +// SwInterfaceGetTable represents VPP binary API message 'sw_interface_get_table'. type SwInterfaceGetTable struct { SwIfIndex uint32 IsIPv6 uint8 @@ -539,7 +515,7 @@ func (*SwInterfaceGetTable) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceGetTableReply represents VPP binary API message 'sw_interface_get_table_reply': +// SwInterfaceGetTableReply represents VPP binary API message 'sw_interface_get_table_reply'. type SwInterfaceGetTableReply struct { Retval int32 VrfID uint32 @@ -555,7 +531,7 @@ func (*SwInterfaceGetTableReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceRxPlacementDetails represents VPP binary API message 'sw_interface_rx_placement_details': +// SwInterfaceRxPlacementDetails represents VPP binary API message 'sw_interface_rx_placement_details'. type SwInterfaceRxPlacementDetails struct { SwIfIndex uint32 QueueID uint32 @@ -573,7 +549,7 @@ func (*SwInterfaceRxPlacementDetails) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceRxPlacementDump represents VPP binary API message 'sw_interface_rx_placement_dump': +// SwInterfaceRxPlacementDump represents VPP binary API message 'sw_interface_rx_placement_dump'. type SwInterfaceRxPlacementDump struct { SwIfIndex uint32 } @@ -588,7 +564,7 @@ func (*SwInterfaceRxPlacementDump) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceSetFlags represents VPP binary API message 'sw_interface_set_flags': +// SwInterfaceSetFlags represents VPP binary API message 'sw_interface_set_flags'. type SwInterfaceSetFlags struct { SwIfIndex uint32 AdminUpDown uint8 @@ -604,7 +580,7 @@ func (*SwInterfaceSetFlags) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceSetFlagsReply represents VPP binary API message 'sw_interface_set_flags_reply': +// SwInterfaceSetFlagsReply represents VPP binary API message 'sw_interface_set_flags_reply'. type SwInterfaceSetFlagsReply struct { Retval int32 } @@ -619,7 +595,7 @@ func (*SwInterfaceSetFlagsReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceSetIPDirectedBroadcast represents VPP binary API message 'sw_interface_set_ip_directed_broadcast': +// SwInterfaceSetIPDirectedBroadcast represents VPP binary API message 'sw_interface_set_ip_directed_broadcast'. type SwInterfaceSetIPDirectedBroadcast struct { SwIfIndex uint32 Enable uint8 @@ -635,7 +611,7 @@ func (*SwInterfaceSetIPDirectedBroadcast) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceSetIPDirectedBroadcastReply represents VPP binary API message 'sw_interface_set_ip_directed_broadcast_reply': +// SwInterfaceSetIPDirectedBroadcastReply represents VPP binary API message 'sw_interface_set_ip_directed_broadcast_reply'. type SwInterfaceSetIPDirectedBroadcastReply struct { Retval int32 } @@ -650,7 +626,7 @@ func (*SwInterfaceSetIPDirectedBroadcastReply) GetMessageType() api.MessageType return api.ReplyMessage } -// SwInterfaceSetMacAddress represents VPP binary API message 'sw_interface_set_mac_address': +// SwInterfaceSetMacAddress represents VPP binary API message 'sw_interface_set_mac_address'. type SwInterfaceSetMacAddress struct { SwIfIndex uint32 MacAddress []byte `struc:"[6]byte"` @@ -666,7 +642,7 @@ func (*SwInterfaceSetMacAddress) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceSetMacAddressReply represents VPP binary API message 'sw_interface_set_mac_address_reply': +// SwInterfaceSetMacAddressReply represents VPP binary API message 'sw_interface_set_mac_address_reply'. type SwInterfaceSetMacAddressReply struct { Retval int32 } @@ -681,7 +657,7 @@ func (*SwInterfaceSetMacAddressReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceSetMtu represents VPP binary API message 'sw_interface_set_mtu': +// SwInterfaceSetMtu represents VPP binary API message 'sw_interface_set_mtu'. type SwInterfaceSetMtu struct { SwIfIndex uint32 Mtu []uint32 `struc:"[4]uint32"` @@ -697,7 +673,7 @@ func (*SwInterfaceSetMtu) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceSetMtuReply represents VPP binary API message 'sw_interface_set_mtu_reply': +// SwInterfaceSetMtuReply represents VPP binary API message 'sw_interface_set_mtu_reply'. type SwInterfaceSetMtuReply struct { Retval int32 } @@ -712,7 +688,7 @@ func (*SwInterfaceSetMtuReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceSetRxMode represents VPP binary API message 'sw_interface_set_rx_mode': +// SwInterfaceSetRxMode represents VPP binary API message 'sw_interface_set_rx_mode'. type SwInterfaceSetRxMode struct { SwIfIndex uint32 QueueIDValid uint8 @@ -730,7 +706,7 @@ func (*SwInterfaceSetRxMode) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceSetRxModeReply represents VPP binary API message 'sw_interface_set_rx_mode_reply': +// SwInterfaceSetRxModeReply represents VPP binary API message 'sw_interface_set_rx_mode_reply'. type SwInterfaceSetRxModeReply struct { Retval int32 } @@ -745,7 +721,7 @@ func (*SwInterfaceSetRxModeReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceSetRxPlacement represents VPP binary API message 'sw_interface_set_rx_placement': +// SwInterfaceSetRxPlacement represents VPP binary API message 'sw_interface_set_rx_placement'. type SwInterfaceSetRxPlacement struct { SwIfIndex uint32 QueueID uint32 @@ -763,7 +739,7 @@ func (*SwInterfaceSetRxPlacement) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceSetRxPlacementReply represents VPP binary API message 'sw_interface_set_rx_placement_reply': +// SwInterfaceSetRxPlacementReply represents VPP binary API message 'sw_interface_set_rx_placement_reply'. type SwInterfaceSetRxPlacementReply struct { Retval int32 } @@ -778,7 +754,7 @@ func (*SwInterfaceSetRxPlacementReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceSetTable represents VPP binary API message 'sw_interface_set_table': +// SwInterfaceSetTable represents VPP binary API message 'sw_interface_set_table'. type SwInterfaceSetTable struct { SwIfIndex uint32 IsIPv6 uint8 @@ -795,7 +771,7 @@ func (*SwInterfaceSetTable) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceSetTableReply represents VPP binary API message 'sw_interface_set_table_reply': +// SwInterfaceSetTableReply represents VPP binary API message 'sw_interface_set_table_reply'. type SwInterfaceSetTableReply struct { Retval int32 } @@ -810,7 +786,7 @@ func (*SwInterfaceSetTableReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceSetUnnumbered represents VPP binary API message 'sw_interface_set_unnumbered': +// SwInterfaceSetUnnumbered represents VPP binary API message 'sw_interface_set_unnumbered'. type SwInterfaceSetUnnumbered struct { SwIfIndex uint32 UnnumberedSwIfIndex uint32 @@ -827,7 +803,7 @@ func (*SwInterfaceSetUnnumbered) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceSetUnnumberedReply represents VPP binary API message 'sw_interface_set_unnumbered_reply': +// SwInterfaceSetUnnumberedReply represents VPP binary API message 'sw_interface_set_unnumbered_reply'. type SwInterfaceSetUnnumberedReply struct { Retval int32 } @@ -842,7 +818,7 @@ func (*SwInterfaceSetUnnumberedReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// SwInterfaceTagAddDel represents VPP binary API message 'sw_interface_tag_add_del': +// SwInterfaceTagAddDel represents VPP binary API message 'sw_interface_tag_add_del'. type SwInterfaceTagAddDel struct { IsAdd uint8 SwIfIndex uint32 @@ -859,7 +835,7 @@ func (*SwInterfaceTagAddDel) GetMessageType() api.MessageType { return api.RequestMessage } -// SwInterfaceTagAddDelReply represents VPP binary API message 'sw_interface_tag_add_del_reply': +// SwInterfaceTagAddDelReply represents VPP binary API message 'sw_interface_tag_add_del_reply'. type SwInterfaceTagAddDelReply struct { Retval int32 } @@ -874,7 +850,7 @@ func (*SwInterfaceTagAddDelReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// WantInterfaceEvents represents VPP binary API message 'want_interface_events': +// WantInterfaceEvents represents VPP binary API message 'want_interface_events'. type WantInterfaceEvents struct { EnableDisable uint32 PID uint32 @@ -890,7 +866,7 @@ func (*WantInterfaceEvents) GetMessageType() api.MessageType { return api.RequestMessage } -// WantInterfaceEventsReply represents VPP binary API message 'want_interface_events_reply': +// WantInterfaceEventsReply represents VPP binary API message 'want_interface_events_reply'. type WantInterfaceEventsReply struct { Retval int32 } @@ -959,56 +935,369 @@ func init() { api.RegisterMessage((*WantInterfaceEventsReply)(nil), "interface.WantInterfaceEventsReply") } -var Messages = []api.Message{ - (*CollectDetailedInterfaceStats)(nil), - (*CollectDetailedInterfaceStatsReply)(nil), - (*CreateLoopback)(nil), - (*CreateLoopbackInstance)(nil), - (*CreateLoopbackInstanceReply)(nil), - (*CreateLoopbackReply)(nil), - (*CreateSubif)(nil), - (*CreateSubifReply)(nil), - (*CreateVlanSubif)(nil), - (*CreateVlanSubifReply)(nil), - (*DeleteLoopback)(nil), - (*DeleteLoopbackReply)(nil), - (*DeleteSubif)(nil), - (*DeleteSubifReply)(nil), - (*HwInterfaceSetMtu)(nil), - (*HwInterfaceSetMtuReply)(nil), - (*InterfaceNameRenumber)(nil), - (*InterfaceNameRenumberReply)(nil), - (*SwInterfaceAddDelAddress)(nil), - (*SwInterfaceAddDelAddressReply)(nil), - (*SwInterfaceClearStats)(nil), - (*SwInterfaceClearStatsReply)(nil), - (*SwInterfaceDetails)(nil), - (*SwInterfaceDump)(nil), - (*SwInterfaceEvent)(nil), - (*SwInterfaceGetMacAddress)(nil), - (*SwInterfaceGetMacAddressReply)(nil), - (*SwInterfaceGetTable)(nil), - (*SwInterfaceGetTableReply)(nil), - (*SwInterfaceRxPlacementDetails)(nil), - (*SwInterfaceRxPlacementDump)(nil), - (*SwInterfaceSetFlags)(nil), - (*SwInterfaceSetFlagsReply)(nil), - (*SwInterfaceSetIPDirectedBroadcast)(nil), - (*SwInterfaceSetIPDirectedBroadcastReply)(nil), - (*SwInterfaceSetMacAddress)(nil), - (*SwInterfaceSetMacAddressReply)(nil), - (*SwInterfaceSetMtu)(nil), - (*SwInterfaceSetMtuReply)(nil), - (*SwInterfaceSetRxMode)(nil), - (*SwInterfaceSetRxModeReply)(nil), - (*SwInterfaceSetRxPlacement)(nil), - (*SwInterfaceSetRxPlacementReply)(nil), - (*SwInterfaceSetTable)(nil), - (*SwInterfaceSetTableReply)(nil), - (*SwInterfaceSetUnnumbered)(nil), - (*SwInterfaceSetUnnumberedReply)(nil), - (*SwInterfaceTagAddDel)(nil), - (*SwInterfaceTagAddDelReply)(nil), - (*WantInterfaceEvents)(nil), - (*WantInterfaceEventsReply)(nil), +// Messages returns list of all messages in this module. +func AllMessages() []api.Message { + return []api.Message{ + (*CollectDetailedInterfaceStats)(nil), + (*CollectDetailedInterfaceStatsReply)(nil), + (*CreateLoopback)(nil), + (*CreateLoopbackInstance)(nil), + (*CreateLoopbackInstanceReply)(nil), + (*CreateLoopbackReply)(nil), + (*CreateSubif)(nil), + (*CreateSubifReply)(nil), + (*CreateVlanSubif)(nil), + (*CreateVlanSubifReply)(nil), + (*DeleteLoopback)(nil), + (*DeleteLoopbackReply)(nil), + (*DeleteSubif)(nil), + (*DeleteSubifReply)(nil), + (*HwInterfaceSetMtu)(nil), + (*HwInterfaceSetMtuReply)(nil), + (*InterfaceNameRenumber)(nil), + (*InterfaceNameRenumberReply)(nil), + (*SwInterfaceAddDelAddress)(nil), + (*SwInterfaceAddDelAddressReply)(nil), + (*SwInterfaceClearStats)(nil), + (*SwInterfaceClearStatsReply)(nil), + (*SwInterfaceDetails)(nil), + (*SwInterfaceDump)(nil), + (*SwInterfaceEvent)(nil), + (*SwInterfaceGetMacAddress)(nil), + (*SwInterfaceGetMacAddressReply)(nil), + (*SwInterfaceGetTable)(nil), + (*SwInterfaceGetTableReply)(nil), + (*SwInterfaceRxPlacementDetails)(nil), + (*SwInterfaceRxPlacementDump)(nil), + (*SwInterfaceSetFlags)(nil), + (*SwInterfaceSetFlagsReply)(nil), + (*SwInterfaceSetIPDirectedBroadcast)(nil), + (*SwInterfaceSetIPDirectedBroadcastReply)(nil), + (*SwInterfaceSetMacAddress)(nil), + (*SwInterfaceSetMacAddressReply)(nil), + (*SwInterfaceSetMtu)(nil), + (*SwInterfaceSetMtuReply)(nil), + (*SwInterfaceSetRxMode)(nil), + (*SwInterfaceSetRxModeReply)(nil), + (*SwInterfaceSetRxPlacement)(nil), + (*SwInterfaceSetRxPlacementReply)(nil), + (*SwInterfaceSetTable)(nil), + (*SwInterfaceSetTableReply)(nil), + (*SwInterfaceSetUnnumbered)(nil), + (*SwInterfaceSetUnnumberedReply)(nil), + (*SwInterfaceTagAddDel)(nil), + (*SwInterfaceTagAddDelReply)(nil), + (*WantInterfaceEvents)(nil), + (*WantInterfaceEventsReply)(nil), + } +} + +// RPCService represents RPC service API for interface module. +type RPCService interface { + DumpSwInterface(ctx context.Context, in *SwInterfaceDump) (RPCService_DumpSwInterfaceClient, error) + DumpSwInterfaceRxPlacement(ctx context.Context, in *SwInterfaceRxPlacementDump) (RPCService_DumpSwInterfaceRxPlacementClient, error) + CollectDetailedInterfaceStats(ctx context.Context, in *CollectDetailedInterfaceStats) (*CollectDetailedInterfaceStatsReply, error) + CreateLoopback(ctx context.Context, in *CreateLoopback) (*CreateLoopbackReply, error) + CreateLoopbackInstance(ctx context.Context, in *CreateLoopbackInstance) (*CreateLoopbackInstanceReply, error) + CreateSubif(ctx context.Context, in *CreateSubif) (*CreateSubifReply, error) + CreateVlanSubif(ctx context.Context, in *CreateVlanSubif) (*CreateVlanSubifReply, error) + DeleteLoopback(ctx context.Context, in *DeleteLoopback) (*DeleteLoopbackReply, error) + DeleteSubif(ctx context.Context, in *DeleteSubif) (*DeleteSubifReply, error) + HwInterfaceSetMtu(ctx context.Context, in *HwInterfaceSetMtu) (*HwInterfaceSetMtuReply, error) + InterfaceNameRenumber(ctx context.Context, in *InterfaceNameRenumber) (*InterfaceNameRenumberReply, error) + SwInterfaceAddDelAddress(ctx context.Context, in *SwInterfaceAddDelAddress) (*SwInterfaceAddDelAddressReply, error) + SwInterfaceClearStats(ctx context.Context, in *SwInterfaceClearStats) (*SwInterfaceClearStatsReply, error) + SwInterfaceGetMacAddress(ctx context.Context, in *SwInterfaceGetMacAddress) (*SwInterfaceGetMacAddressReply, error) + SwInterfaceGetTable(ctx context.Context, in *SwInterfaceGetTable) (*SwInterfaceGetTableReply, error) + SwInterfaceSetFlags(ctx context.Context, in *SwInterfaceSetFlags) (*SwInterfaceSetFlagsReply, error) + SwInterfaceSetIPDirectedBroadcast(ctx context.Context, in *SwInterfaceSetIPDirectedBroadcast) (*SwInterfaceSetIPDirectedBroadcastReply, error) + SwInterfaceSetMacAddress(ctx context.Context, in *SwInterfaceSetMacAddress) (*SwInterfaceSetMacAddressReply, error) + SwInterfaceSetMtu(ctx context.Context, in *SwInterfaceSetMtu) (*SwInterfaceSetMtuReply, error) + SwInterfaceSetRxMode(ctx context.Context, in *SwInterfaceSetRxMode) (*SwInterfaceSetRxModeReply, error) + SwInterfaceSetRxPlacement(ctx context.Context, in *SwInterfaceSetRxPlacement) (*SwInterfaceSetRxPlacementReply, error) + SwInterfaceSetTable(ctx context.Context, in *SwInterfaceSetTable) (*SwInterfaceSetTableReply, error) + SwInterfaceSetUnnumbered(ctx context.Context, in *SwInterfaceSetUnnumbered) (*SwInterfaceSetUnnumberedReply, error) + SwInterfaceTagAddDel(ctx context.Context, in *SwInterfaceTagAddDel) (*SwInterfaceTagAddDelReply, error) + WantInterfaceEvents(ctx context.Context, in *WantInterfaceEvents) (*WantInterfaceEventsReply, error) +} + +type serviceClient struct { + ch api.Channel +} + +func NewServiceClient(ch api.Channel) RPCService { + return &serviceClient{ch} +} + +func (c *serviceClient) DumpSwInterface(ctx context.Context, in *SwInterfaceDump) (RPCService_DumpSwInterfaceClient, error) { + stream := c.ch.SendMultiRequest(in) + x := &serviceClient_DumpSwInterfaceClient{stream} + return x, nil +} + +type RPCService_DumpSwInterfaceClient interface { + Recv() (*SwInterfaceDetails, error) +} + +type serviceClient_DumpSwInterfaceClient struct { + api.MultiRequestCtx +} + +func (c *serviceClient_DumpSwInterfaceClient) Recv() (*SwInterfaceDetails, error) { + m := new(SwInterfaceDetails) + stop, err := c.MultiRequestCtx.ReceiveReply(m) + if err != nil { + return nil, err + } + if stop { + return nil, io.EOF + } + return m, nil +} + +func (c *serviceClient) DumpSwInterfaceRxPlacement(ctx context.Context, in *SwInterfaceRxPlacementDump) (RPCService_DumpSwInterfaceRxPlacementClient, error) { + stream := c.ch.SendMultiRequest(in) + x := &serviceClient_DumpSwInterfaceRxPlacementClient{stream} + return x, nil +} + +type RPCService_DumpSwInterfaceRxPlacementClient interface { + Recv() (*SwInterfaceRxPlacementDetails, error) +} + +type serviceClient_DumpSwInterfaceRxPlacementClient struct { + api.MultiRequestCtx +} + +func (c *serviceClient_DumpSwInterfaceRxPlacementClient) Recv() (*SwInterfaceRxPlacementDetails, error) { + m := new(SwInterfaceRxPlacementDetails) + stop, err := c.MultiRequestCtx.ReceiveReply(m) + if err != nil { + return nil, err + } + if stop { + return nil, io.EOF + } + return m, nil +} + +func (c *serviceClient) CollectDetailedInterfaceStats(ctx context.Context, in *CollectDetailedInterfaceStats) (*CollectDetailedInterfaceStatsReply, error) { + out := new(CollectDetailedInterfaceStatsReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) CreateLoopback(ctx context.Context, in *CreateLoopback) (*CreateLoopbackReply, error) { + out := new(CreateLoopbackReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) CreateLoopbackInstance(ctx context.Context, in *CreateLoopbackInstance) (*CreateLoopbackInstanceReply, error) { + out := new(CreateLoopbackInstanceReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) CreateSubif(ctx context.Context, in *CreateSubif) (*CreateSubifReply, error) { + out := new(CreateSubifReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) CreateVlanSubif(ctx context.Context, in *CreateVlanSubif) (*CreateVlanSubifReply, error) { + out := new(CreateVlanSubifReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) DeleteLoopback(ctx context.Context, in *DeleteLoopback) (*DeleteLoopbackReply, error) { + out := new(DeleteLoopbackReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil } + +func (c *serviceClient) DeleteSubif(ctx context.Context, in *DeleteSubif) (*DeleteSubifReply, error) { + out := new(DeleteSubifReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) HwInterfaceSetMtu(ctx context.Context, in *HwInterfaceSetMtu) (*HwInterfaceSetMtuReply, error) { + out := new(HwInterfaceSetMtuReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) InterfaceNameRenumber(ctx context.Context, in *InterfaceNameRenumber) (*InterfaceNameRenumberReply, error) { + out := new(InterfaceNameRenumberReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceAddDelAddress(ctx context.Context, in *SwInterfaceAddDelAddress) (*SwInterfaceAddDelAddressReply, error) { + out := new(SwInterfaceAddDelAddressReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceClearStats(ctx context.Context, in *SwInterfaceClearStats) (*SwInterfaceClearStatsReply, error) { + out := new(SwInterfaceClearStatsReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceGetMacAddress(ctx context.Context, in *SwInterfaceGetMacAddress) (*SwInterfaceGetMacAddressReply, error) { + out := new(SwInterfaceGetMacAddressReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceGetTable(ctx context.Context, in *SwInterfaceGetTable) (*SwInterfaceGetTableReply, error) { + out := new(SwInterfaceGetTableReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceSetFlags(ctx context.Context, in *SwInterfaceSetFlags) (*SwInterfaceSetFlagsReply, error) { + out := new(SwInterfaceSetFlagsReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceSetIPDirectedBroadcast(ctx context.Context, in *SwInterfaceSetIPDirectedBroadcast) (*SwInterfaceSetIPDirectedBroadcastReply, error) { + out := new(SwInterfaceSetIPDirectedBroadcastReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceSetMacAddress(ctx context.Context, in *SwInterfaceSetMacAddress) (*SwInterfaceSetMacAddressReply, error) { + out := new(SwInterfaceSetMacAddressReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceSetMtu(ctx context.Context, in *SwInterfaceSetMtu) (*SwInterfaceSetMtuReply, error) { + out := new(SwInterfaceSetMtuReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceSetRxMode(ctx context.Context, in *SwInterfaceSetRxMode) (*SwInterfaceSetRxModeReply, error) { + out := new(SwInterfaceSetRxModeReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceSetRxPlacement(ctx context.Context, in *SwInterfaceSetRxPlacement) (*SwInterfaceSetRxPlacementReply, error) { + out := new(SwInterfaceSetRxPlacementReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceSetTable(ctx context.Context, in *SwInterfaceSetTable) (*SwInterfaceSetTableReply, error) { + out := new(SwInterfaceSetTableReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceSetUnnumbered(ctx context.Context, in *SwInterfaceSetUnnumbered) (*SwInterfaceSetUnnumberedReply, error) { + out := new(SwInterfaceSetUnnumberedReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) SwInterfaceTagAddDel(ctx context.Context, in *SwInterfaceTagAddDel) (*SwInterfaceTagAddDelReply, error) { + out := new(SwInterfaceTagAddDelReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) WantInterfaceEvents(ctx context.Context, in *WantInterfaceEvents) (*WantInterfaceEventsReply, error) { + out := new(WantInterfaceEventsReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the GoVPP api package it is being compiled against. +// A compilation error at this line likely means your copy of the +// GoVPP api package needs to be updated. +const _ = api.GoVppAPIPackageIsVersion1 // please upgrade the GoVPP api package + +// Reference imports to suppress errors if they are not otherwise used. +var _ = api.RegisterMessage +var _ = bytes.NewBuffer +var _ = context.Background +var _ = io.Copy +var _ = strconv.Itoa +var _ = struc.Pack diff --git a/topology/probes/vpp/bin_api/memif/memif.ba.go b/topology/probes/vpp/bin_api/memif/memif.ba.go new file mode 100644 index 0000000000..14eb1e5e48 --- /dev/null +++ b/topology/probes/vpp/bin_api/memif/memif.ba.go @@ -0,0 +1,337 @@ +// Code generated by GoVPP's binapi-generator. DO NOT EDIT. +// source: /usr/share/vpp/api/memif.api.json + +/* +Package memif is a generated VPP binary API for 'memif' module. + +It consists of: + 10 messages + 5 services +*/ +package memif + +import ( + bytes "bytes" + context "context" + api "git.fd.io/govpp.git/api" + struc "github.com/lunixbochs/struc" + io "io" + strconv "strconv" +) + +const ( + // ModuleName is the name of this module. + ModuleName = "memif" + // APIVersion is the API version of this module. + APIVersion = "2.0.0" + // VersionCrc is the CRC of this module. + VersionCrc = 0x31b42e17 +) + +// MemifCreate represents VPP binary API message 'memif_create'. +type MemifCreate struct { + Role uint8 + Mode uint8 + RxQueues uint8 + TxQueues uint8 + ID uint32 + SocketID uint32 + Secret []byte `struc:"[24]byte"` + RingSize uint32 + BufferSize uint16 + HwAddr []byte `struc:"[6]byte"` +} + +func (*MemifCreate) GetMessageName() string { + return "memif_create" +} +func (*MemifCreate) GetCrcString() string { + return "6597cdb2" +} +func (*MemifCreate) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// MemifCreateReply represents VPP binary API message 'memif_create_reply'. +type MemifCreateReply struct { + Retval int32 + SwIfIndex uint32 +} + +func (*MemifCreateReply) GetMessageName() string { + return "memif_create_reply" +} +func (*MemifCreateReply) GetCrcString() string { + return "fda5941f" +} +func (*MemifCreateReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// MemifDelete represents VPP binary API message 'memif_delete'. +type MemifDelete struct { + SwIfIndex uint32 +} + +func (*MemifDelete) GetMessageName() string { + return "memif_delete" +} +func (*MemifDelete) GetCrcString() string { + return "529cb13f" +} +func (*MemifDelete) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// MemifDeleteReply represents VPP binary API message 'memif_delete_reply'. +type MemifDeleteReply struct { + Retval int32 +} + +func (*MemifDeleteReply) GetMessageName() string { + return "memif_delete_reply" +} +func (*MemifDeleteReply) GetCrcString() string { + return "e8d4e804" +} +func (*MemifDeleteReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// MemifDetails represents VPP binary API message 'memif_details'. +type MemifDetails struct { + SwIfIndex uint32 + IfName []byte `struc:"[64]byte"` + HwAddr []byte `struc:"[6]byte"` + ID uint32 + Role uint8 + Mode uint8 + SocketID uint32 + RingSize uint32 + BufferSize uint16 + AdminUpDown uint8 + LinkUpDown uint8 +} + +func (*MemifDetails) GetMessageName() string { + return "memif_details" +} +func (*MemifDetails) GetCrcString() string { + return "4f5a3397" +} +func (*MemifDetails) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// MemifDump represents VPP binary API message 'memif_dump'. +type MemifDump struct{} + +func (*MemifDump) GetMessageName() string { + return "memif_dump" +} +func (*MemifDump) GetCrcString() string { + return "51077d14" +} +func (*MemifDump) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// MemifSocketFilenameAddDel represents VPP binary API message 'memif_socket_filename_add_del'. +type MemifSocketFilenameAddDel struct { + IsAdd uint8 + SocketID uint32 + SocketFilename []byte `struc:"[128]byte"` +} + +func (*MemifSocketFilenameAddDel) GetMessageName() string { + return "memif_socket_filename_add_del" +} +func (*MemifSocketFilenameAddDel) GetCrcString() string { + return "30e3929d" +} +func (*MemifSocketFilenameAddDel) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// MemifSocketFilenameAddDelReply represents VPP binary API message 'memif_socket_filename_add_del_reply'. +type MemifSocketFilenameAddDelReply struct { + Retval int32 +} + +func (*MemifSocketFilenameAddDelReply) GetMessageName() string { + return "memif_socket_filename_add_del_reply" +} +func (*MemifSocketFilenameAddDelReply) GetCrcString() string { + return "e8d4e804" +} +func (*MemifSocketFilenameAddDelReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// MemifSocketFilenameDetails represents VPP binary API message 'memif_socket_filename_details'. +type MemifSocketFilenameDetails struct { + SocketID uint32 + SocketFilename []byte `struc:"[128]byte"` +} + +func (*MemifSocketFilenameDetails) GetMessageName() string { + return "memif_socket_filename_details" +} +func (*MemifSocketFilenameDetails) GetCrcString() string { + return "e347e32f" +} +func (*MemifSocketFilenameDetails) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// MemifSocketFilenameDump represents VPP binary API message 'memif_socket_filename_dump'. +type MemifSocketFilenameDump struct{} + +func (*MemifSocketFilenameDump) GetMessageName() string { + return "memif_socket_filename_dump" +} +func (*MemifSocketFilenameDump) GetCrcString() string { + return "51077d14" +} +func (*MemifSocketFilenameDump) GetMessageType() api.MessageType { + return api.RequestMessage +} + +func init() { + api.RegisterMessage((*MemifCreate)(nil), "memif.MemifCreate") + api.RegisterMessage((*MemifCreateReply)(nil), "memif.MemifCreateReply") + api.RegisterMessage((*MemifDelete)(nil), "memif.MemifDelete") + api.RegisterMessage((*MemifDeleteReply)(nil), "memif.MemifDeleteReply") + api.RegisterMessage((*MemifDetails)(nil), "memif.MemifDetails") + api.RegisterMessage((*MemifDump)(nil), "memif.MemifDump") + api.RegisterMessage((*MemifSocketFilenameAddDel)(nil), "memif.MemifSocketFilenameAddDel") + api.RegisterMessage((*MemifSocketFilenameAddDelReply)(nil), "memif.MemifSocketFilenameAddDelReply") + api.RegisterMessage((*MemifSocketFilenameDetails)(nil), "memif.MemifSocketFilenameDetails") + api.RegisterMessage((*MemifSocketFilenameDump)(nil), "memif.MemifSocketFilenameDump") +} + +// Messages returns list of all messages in this module. +func AllMessages() []api.Message { + return []api.Message{ + (*MemifCreate)(nil), + (*MemifCreateReply)(nil), + (*MemifDelete)(nil), + (*MemifDeleteReply)(nil), + (*MemifDetails)(nil), + (*MemifDump)(nil), + (*MemifSocketFilenameAddDel)(nil), + (*MemifSocketFilenameAddDelReply)(nil), + (*MemifSocketFilenameDetails)(nil), + (*MemifSocketFilenameDump)(nil), + } +} + +// RPCService represents RPC service API for memif module. +type RPCService interface { + DumpMemif(ctx context.Context, in *MemifDump) (RPCService_DumpMemifClient, error) + DumpMemifSocketFilename(ctx context.Context, in *MemifSocketFilenameDump) (RPCService_DumpMemifSocketFilenameClient, error) + MemifCreate(ctx context.Context, in *MemifCreate) (*MemifCreateReply, error) + MemifDelete(ctx context.Context, in *MemifDelete) (*MemifDeleteReply, error) + MemifSocketFilenameAddDel(ctx context.Context, in *MemifSocketFilenameAddDel) (*MemifSocketFilenameAddDelReply, error) +} + +type serviceClient struct { + ch api.Channel +} + +func NewServiceClient(ch api.Channel) RPCService { + return &serviceClient{ch} +} + +func (c *serviceClient) DumpMemif(ctx context.Context, in *MemifDump) (RPCService_DumpMemifClient, error) { + stream := c.ch.SendMultiRequest(in) + x := &serviceClient_DumpMemifClient{stream} + return x, nil +} + +type RPCService_DumpMemifClient interface { + Recv() (*MemifDetails, error) +} + +type serviceClient_DumpMemifClient struct { + api.MultiRequestCtx +} + +func (c *serviceClient_DumpMemifClient) Recv() (*MemifDetails, error) { + m := new(MemifDetails) + stop, err := c.MultiRequestCtx.ReceiveReply(m) + if err != nil { + return nil, err + } + if stop { + return nil, io.EOF + } + return m, nil +} + +func (c *serviceClient) DumpMemifSocketFilename(ctx context.Context, in *MemifSocketFilenameDump) (RPCService_DumpMemifSocketFilenameClient, error) { + stream := c.ch.SendMultiRequest(in) + x := &serviceClient_DumpMemifSocketFilenameClient{stream} + return x, nil +} + +type RPCService_DumpMemifSocketFilenameClient interface { + Recv() (*MemifSocketFilenameDetails, error) +} + +type serviceClient_DumpMemifSocketFilenameClient struct { + api.MultiRequestCtx +} + +func (c *serviceClient_DumpMemifSocketFilenameClient) Recv() (*MemifSocketFilenameDetails, error) { + m := new(MemifSocketFilenameDetails) + stop, err := c.MultiRequestCtx.ReceiveReply(m) + if err != nil { + return nil, err + } + if stop { + return nil, io.EOF + } + return m, nil +} + +func (c *serviceClient) MemifCreate(ctx context.Context, in *MemifCreate) (*MemifCreateReply, error) { + out := new(MemifCreateReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) MemifDelete(ctx context.Context, in *MemifDelete) (*MemifDeleteReply, error) { + out := new(MemifDeleteReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) MemifSocketFilenameAddDel(ctx context.Context, in *MemifSocketFilenameAddDel) (*MemifSocketFilenameAddDelReply, error) { + out := new(MemifSocketFilenameAddDelReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the GoVPP api package it is being compiled against. +// A compilation error at this line likely means your copy of the +// GoVPP api package needs to be updated. +const _ = api.GoVppAPIPackageIsVersion1 // please upgrade the GoVPP api package + +// Reference imports to suppress errors if they are not otherwise used. +var _ = api.RegisterMessage +var _ = bytes.NewBuffer +var _ = context.Background +var _ = io.Copy +var _ = strconv.Itoa +var _ = struc.Pack diff --git a/topology/probes/vpp/bin_api/vpe/vpe.ba.go b/topology/probes/vpp/bin_api/vpe/vpe.ba.go index a87dea4e03..da83222ad5 100644 --- a/topology/probes/vpp/bin_api/vpe/vpe.ba.go +++ b/topology/probes/vpp/bin_api/vpe/vpe.ba.go @@ -1,41 +1,35 @@ -// Code generated by GoVPP binapi-generator. DO NOT EDIT. -// source: /usr/share/vpp/api/vpe.api.json +// Code generated by GoVPP's binapi-generator. DO NOT EDIT. +// source: /usr/share/vpp/api/vpe.api.json /* - Package vpe is a generated from VPP binary API module 'vpe'. +Package vpe is a generated VPP binary API for 'vpe' module. - It contains following objects: - 9 services +It consists of: 1 type 18 messages + 9 services */ package vpe -import api "git.fd.io/govpp.git/api" -import struc "github.com/lunixbochs/struc" -import bytes "bytes" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = api.RegisterMessage -var _ = struc.Pack -var _ = bytes.NewBuffer - -// Services represents VPP binary API services: -type Services interface { - AddNodeNext(*AddNodeNext) (*AddNodeNextReply, error) - Cli(*Cli) (*CliReply, error) - CliInband(*CliInband) (*CliInbandReply, error) - ControlPing(*ControlPing) (*ControlPingReply, error) - GetNextIndex(*GetNextIndex) (*GetNextIndexReply, error) - GetNodeGraph(*GetNodeGraph) (*GetNodeGraphReply, error) - GetNodeIndex(*GetNodeIndex) (*GetNodeIndexReply, error) - ShowThreads(*ShowThreads) (*ShowThreadsReply, error) - ShowVersion(*ShowVersion) (*ShowVersionReply, error) -} - -/* Types */ - -// ThreadData represents VPP binary API type 'thread_data': +import ( + bytes "bytes" + context "context" + api "git.fd.io/govpp.git/api" + struc "github.com/lunixbochs/struc" + io "io" + strconv "strconv" +) + +const ( + // ModuleName is the name of this module. + ModuleName = "vpe" + // APIVersion is the API version of this module. + APIVersion = "1.1.0" + // VersionCrc is the CRC of this module. + VersionCrc = 0x2cc8d629 +) + +// ThreadData represents VPP binary API type 'thread_data'. type ThreadData struct { ID uint32 Name []byte `struc:"[64]byte"` @@ -53,9 +47,7 @@ func (*ThreadData) GetCrcString() string { return "0f57094e" } -/* Messages */ - -// AddNodeNext represents VPP binary API message 'add_node_next': +// AddNodeNext represents VPP binary API message 'add_node_next'. type AddNodeNext struct { NodeName []byte `struc:"[64]byte"` NextName []byte `struc:"[64]byte"` @@ -71,7 +63,7 @@ func (*AddNodeNext) GetMessageType() api.MessageType { return api.RequestMessage } -// AddNodeNextReply represents VPP binary API message 'add_node_next_reply': +// AddNodeNextReply represents VPP binary API message 'add_node_next_reply'. type AddNodeNextReply struct { Retval int32 NextIndex uint32 @@ -87,7 +79,7 @@ func (*AddNodeNextReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// Cli represents VPP binary API message 'cli': +// Cli represents VPP binary API message 'cli'. type Cli struct { CmdInShmem uint64 } @@ -102,7 +94,7 @@ func (*Cli) GetMessageType() api.MessageType { return api.RequestMessage } -// CliInband represents VPP binary API message 'cli_inband': +// CliInband represents VPP binary API message 'cli_inband'. type CliInband struct { XXX_CmdLen uint32 `struc:"sizeof=Cmd"` Cmd string @@ -118,7 +110,7 @@ func (*CliInband) GetMessageType() api.MessageType { return api.RequestMessage } -// CliInbandReply represents VPP binary API message 'cli_inband_reply': +// CliInbandReply represents VPP binary API message 'cli_inband_reply'. type CliInbandReply struct { Retval int32 XXX_ReplyLen uint32 `struc:"sizeof=Reply"` @@ -135,7 +127,7 @@ func (*CliInbandReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// CliReply represents VPP binary API message 'cli_reply': +// CliReply represents VPP binary API message 'cli_reply'. type CliReply struct { Retval int32 ReplyInShmem uint64 @@ -151,7 +143,7 @@ func (*CliReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// ControlPing represents VPP binary API message 'control_ping': +// ControlPing represents VPP binary API message 'control_ping'. type ControlPing struct{} func (*ControlPing) GetMessageName() string { @@ -164,7 +156,7 @@ func (*ControlPing) GetMessageType() api.MessageType { return api.RequestMessage } -// ControlPingReply represents VPP binary API message 'control_ping_reply': +// ControlPingReply represents VPP binary API message 'control_ping_reply'. type ControlPingReply struct { Retval int32 ClientIndex uint32 @@ -181,7 +173,7 @@ func (*ControlPingReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// GetNextIndex represents VPP binary API message 'get_next_index': +// GetNextIndex represents VPP binary API message 'get_next_index'. type GetNextIndex struct { NodeName []byte `struc:"[64]byte"` NextName []byte `struc:"[64]byte"` @@ -197,7 +189,7 @@ func (*GetNextIndex) GetMessageType() api.MessageType { return api.RequestMessage } -// GetNextIndexReply represents VPP binary API message 'get_next_index_reply': +// GetNextIndexReply represents VPP binary API message 'get_next_index_reply'. type GetNextIndexReply struct { Retval int32 NextIndex uint32 @@ -213,7 +205,7 @@ func (*GetNextIndexReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// GetNodeGraph represents VPP binary API message 'get_node_graph': +// GetNodeGraph represents VPP binary API message 'get_node_graph'. type GetNodeGraph struct{} func (*GetNodeGraph) GetMessageName() string { @@ -226,7 +218,7 @@ func (*GetNodeGraph) GetMessageType() api.MessageType { return api.RequestMessage } -// GetNodeGraphReply represents VPP binary API message 'get_node_graph_reply': +// GetNodeGraphReply represents VPP binary API message 'get_node_graph_reply'. type GetNodeGraphReply struct { Retval int32 ReplyInShmem uint64 @@ -242,7 +234,7 @@ func (*GetNodeGraphReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// GetNodeIndex represents VPP binary API message 'get_node_index': +// GetNodeIndex represents VPP binary API message 'get_node_index'. type GetNodeIndex struct { NodeName []byte `struc:"[64]byte"` } @@ -257,7 +249,7 @@ func (*GetNodeIndex) GetMessageType() api.MessageType { return api.RequestMessage } -// GetNodeIndexReply represents VPP binary API message 'get_node_index_reply': +// GetNodeIndexReply represents VPP binary API message 'get_node_index_reply'. type GetNodeIndexReply struct { Retval int32 NodeIndex uint32 @@ -273,7 +265,7 @@ func (*GetNodeIndexReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// ShowThreads represents VPP binary API message 'show_threads': +// ShowThreads represents VPP binary API message 'show_threads'. type ShowThreads struct{} func (*ShowThreads) GetMessageName() string { @@ -286,7 +278,7 @@ func (*ShowThreads) GetMessageType() api.MessageType { return api.RequestMessage } -// ShowThreadsReply represents VPP binary API message 'show_threads_reply': +// ShowThreadsReply represents VPP binary API message 'show_threads_reply'. type ShowThreadsReply struct { Retval int32 Count uint32 `struc:"sizeof=ThreadData"` @@ -303,7 +295,7 @@ func (*ShowThreadsReply) GetMessageType() api.MessageType { return api.ReplyMessage } -// ShowVersion represents VPP binary API message 'show_version': +// ShowVersion represents VPP binary API message 'show_version'. type ShowVersion struct{} func (*ShowVersion) GetMessageName() string { @@ -316,7 +308,7 @@ func (*ShowVersion) GetMessageType() api.MessageType { return api.RequestMessage } -// ShowVersionReply represents VPP binary API message 'show_version_reply': +// ShowVersionReply represents VPP binary API message 'show_version_reply'. type ShowVersionReply struct { Retval int32 XXX_ProgramLen uint32 `struc:"sizeof=Program"` @@ -360,23 +352,142 @@ func init() { api.RegisterMessage((*ShowVersionReply)(nil), "vpe.ShowVersionReply") } -var Messages = []api.Message{ - (*AddNodeNext)(nil), - (*AddNodeNextReply)(nil), - (*Cli)(nil), - (*CliInband)(nil), - (*CliInbandReply)(nil), - (*CliReply)(nil), - (*ControlPing)(nil), - (*ControlPingReply)(nil), - (*GetNextIndex)(nil), - (*GetNextIndexReply)(nil), - (*GetNodeGraph)(nil), - (*GetNodeGraphReply)(nil), - (*GetNodeIndex)(nil), - (*GetNodeIndexReply)(nil), - (*ShowThreads)(nil), - (*ShowThreadsReply)(nil), - (*ShowVersion)(nil), - (*ShowVersionReply)(nil), -} +// Messages returns list of all messages in this module. +func AllMessages() []api.Message { + return []api.Message{ + (*AddNodeNext)(nil), + (*AddNodeNextReply)(nil), + (*Cli)(nil), + (*CliInband)(nil), + (*CliInbandReply)(nil), + (*CliReply)(nil), + (*ControlPing)(nil), + (*ControlPingReply)(nil), + (*GetNextIndex)(nil), + (*GetNextIndexReply)(nil), + (*GetNodeGraph)(nil), + (*GetNodeGraphReply)(nil), + (*GetNodeIndex)(nil), + (*GetNodeIndexReply)(nil), + (*ShowThreads)(nil), + (*ShowThreadsReply)(nil), + (*ShowVersion)(nil), + (*ShowVersionReply)(nil), + } +} + +// RPCService represents RPC service API for vpe module. +type RPCService interface { + AddNodeNext(ctx context.Context, in *AddNodeNext) (*AddNodeNextReply, error) + Cli(ctx context.Context, in *Cli) (*CliReply, error) + CliInband(ctx context.Context, in *CliInband) (*CliInbandReply, error) + ControlPing(ctx context.Context, in *ControlPing) (*ControlPingReply, error) + GetNextIndex(ctx context.Context, in *GetNextIndex) (*GetNextIndexReply, error) + GetNodeGraph(ctx context.Context, in *GetNodeGraph) (*GetNodeGraphReply, error) + GetNodeIndex(ctx context.Context, in *GetNodeIndex) (*GetNodeIndexReply, error) + ShowThreads(ctx context.Context, in *ShowThreads) (*ShowThreadsReply, error) + ShowVersion(ctx context.Context, in *ShowVersion) (*ShowVersionReply, error) +} + +type serviceClient struct { + ch api.Channel +} + +func NewServiceClient(ch api.Channel) RPCService { + return &serviceClient{ch} +} + +func (c *serviceClient) AddNodeNext(ctx context.Context, in *AddNodeNext) (*AddNodeNextReply, error) { + out := new(AddNodeNextReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) Cli(ctx context.Context, in *Cli) (*CliReply, error) { + out := new(CliReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) CliInband(ctx context.Context, in *CliInband) (*CliInbandReply, error) { + out := new(CliInbandReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) ControlPing(ctx context.Context, in *ControlPing) (*ControlPingReply, error) { + out := new(ControlPingReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) GetNextIndex(ctx context.Context, in *GetNextIndex) (*GetNextIndexReply, error) { + out := new(GetNextIndexReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) GetNodeGraph(ctx context.Context, in *GetNodeGraph) (*GetNodeGraphReply, error) { + out := new(GetNodeGraphReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) GetNodeIndex(ctx context.Context, in *GetNodeIndex) (*GetNodeIndexReply, error) { + out := new(GetNodeIndexReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) ShowThreads(ctx context.Context, in *ShowThreads) (*ShowThreadsReply, error) { + out := new(ShowThreadsReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) ShowVersion(ctx context.Context, in *ShowVersion) (*ShowVersionReply, error) { + out := new(ShowVersionReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the GoVPP api package it is being compiled against. +// A compilation error at this line likely means your copy of the +// GoVPP api package needs to be updated. +const _ = api.GoVppAPIPackageIsVersion1 // please upgrade the GoVPP api package + +// Reference imports to suppress errors if they are not otherwise used. +var _ = api.RegisterMessage +var _ = bytes.NewBuffer +var _ = context.Background +var _ = io.Copy +var _ = strconv.Itoa +var _ = struc.Pack diff --git a/topology/probes/vpp/metadata.go b/topology/probes/vpp/metadata.go new file mode 100644 index 0000000000..8972b4e799 --- /dev/null +++ b/topology/probes/vpp/metadata.go @@ -0,0 +1,52 @@ +//go:generate go run github.com/skydive-project/skydive/scripts/gendecoder -package github.com/skydive-project/skydive/topology/probes/vpp +//go:generate go run github.com/safchain/easyjson/easyjson $GOFILE + +/* + * Copyright (C) 2019 Red Hat, Inc. + * + * 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 ofthe 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 specificlanguage governing permissions and + * limitations under the License. + * + */ + +package vpp + +import ( + "encoding/json" + "fmt" + + "github.com/skydive-project/skydive/common" +) + +// Metadata describes the metadata for a VPP interface +// easyjson:json +// gendecoder +type Metadata struct { + SocketFilename string + ID int64 + SocketID int64 + Master bool + Mode string + RingSize int64 + BufferSize int64 + LinkUpDown bool +} + +// MetadataDecoder implements a json message raw decoder +func MetadataDecoder(raw json.RawMessage) (common.Getter, error) { + var m Metadata + if err := json.Unmarshal(raw, &m); err != nil { + return nil, fmt.Errorf("unable to unmarshal VPP metadata %s: %s", string(raw), err) + } + + return &m, nil +} diff --git a/topology/probes/vpp/metadata_easyjson.go b/topology/probes/vpp/metadata_easyjson.go new file mode 100644 index 0000000000..afe65bccd5 --- /dev/null +++ b/topology/probes/vpp/metadata_easyjson.go @@ -0,0 +1,134 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package vpp + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesVpp(in *jlexer.Lexer, out *Metadata) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "SocketFilename": + out.SocketFilename = string(in.String()) + case "ID": + out.ID = int64(in.Int64()) + case "SocketID": + out.SocketID = int64(in.Int64()) + case "Master": + out.Master = bool(in.Bool()) + case "Mode": + out.Mode = string(in.String()) + case "RingSize": + out.RingSize = int64(in.Int64()) + case "BufferSize": + out.BufferSize = int64(in.Int64()) + case "LinkUpDown": + out.LinkUpDown = bool(in.Bool()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesVpp(out *jwriter.Writer, in Metadata) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"SocketFilename\":" + out.RawString(prefix[1:]) + out.String(string(in.SocketFilename)) + } + { + const prefix string = ",\"ID\":" + out.RawString(prefix) + out.Int64(int64(in.ID)) + } + { + const prefix string = ",\"SocketID\":" + out.RawString(prefix) + out.Int64(int64(in.SocketID)) + } + { + const prefix string = ",\"Master\":" + out.RawString(prefix) + out.Bool(bool(in.Master)) + } + { + const prefix string = ",\"Mode\":" + out.RawString(prefix) + out.String(string(in.Mode)) + } + { + const prefix string = ",\"RingSize\":" + out.RawString(prefix) + out.Int64(int64(in.RingSize)) + } + { + const prefix string = ",\"BufferSize\":" + out.RawString(prefix) + out.Int64(int64(in.BufferSize)) + } + { + const prefix string = ",\"LinkUpDown\":" + out.RawString(prefix) + out.Bool(bool(in.LinkUpDown)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v Metadata) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesVpp(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v Metadata) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonBa0ee0e3EncodeGithubComSkydiveProjectSkydiveTopologyProbesVpp(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *Metadata) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesVpp(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *Metadata) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonBa0ee0e3DecodeGithubComSkydiveProjectSkydiveTopologyProbesVpp(l, v) +} diff --git a/topology/probes/vpp/metadata_gendecoder.go b/topology/probes/vpp/metadata_gendecoder.go new file mode 100644 index 0000000000..5bba66cb38 --- /dev/null +++ b/topology/probes/vpp/metadata_gendecoder.go @@ -0,0 +1,96 @@ +// Code generated - DO NOT EDIT. + +package vpp + +import ( + "github.com/skydive-project/skydive/common" + "strings" +) + +func (obj *Metadata) GetFieldBool(key string) (bool, error) { + switch key { + case "Master": + return obj.Master, nil + case "LinkUpDown": + return obj.LinkUpDown, nil + } + + return false, common.ErrFieldNotFound +} + +func (obj *Metadata) GetFieldInt64(key string) (int64, error) { + switch key { + case "ID": + return int64(obj.ID), nil + case "SocketID": + return int64(obj.SocketID), nil + case "RingSize": + return int64(obj.RingSize), nil + case "BufferSize": + return int64(obj.BufferSize), nil + } + return 0, common.ErrFieldNotFound +} + +func (obj *Metadata) GetFieldString(key string) (string, error) { + switch key { + case "SocketFilename": + return string(obj.SocketFilename), nil + case "Mode": + return string(obj.Mode), nil + } + return "", common.ErrFieldNotFound +} + +func (obj *Metadata) GetFieldKeys() []string { + return []string{ + "SocketFilename", + "ID", + "SocketID", + "Master", + "Mode", + "RingSize", + "BufferSize", + "LinkUpDown", + } +} + +func (obj *Metadata) MatchBool(key string, predicate common.BoolPredicate) bool { + if b, err := obj.GetFieldBool(key); err == nil { + return predicate(b) + } + return false +} + +func (obj *Metadata) MatchInt64(key string, predicate common.Int64Predicate) bool { + if b, err := obj.GetFieldInt64(key); err == nil { + return predicate(b) + } + return false +} + +func (obj *Metadata) MatchString(key string, predicate common.StringPredicate) bool { + if b, err := obj.GetFieldString(key); err == nil { + return predicate(b) + } + return false +} + +func (obj *Metadata) GetField(key string) (interface{}, error) { + if s, err := obj.GetFieldString(key); err == nil { + return s, nil + } + + if i, err := obj.GetFieldInt64(key); err == nil { + return i, nil + } + + if b, err := obj.GetFieldBool(key); err == nil { + return b, nil + } + return nil, common.ErrFieldNotFound +} + +func init() { + strings.Index("", ".") +} diff --git a/topology/probes/vpp/vpp.go b/topology/probes/vpp/vpp.go index edefb32395..b72ee2efe0 100644 --- a/topology/probes/vpp/vpp.go +++ b/topology/probes/vpp/vpp.go @@ -2,6 +2,7 @@ //go:generate go run git.fd.io/govpp.git/cmd/binapi-generator --input-file=/usr/share/vpp/api/interface.api.json --output-dir=./bin_api //go:generate go run git.fd.io/govpp.git/cmd/binapi-generator --input-file=/usr/share/vpp/api/vpe.api.json --output-dir=./bin_api +//go:generate go run git.fd.io/govpp.git/cmd/binapi-generator --input-file=/usr/share/vpp/api/memif.api.json --output-dir=./bin_api /* * Copyright (C) 2018 Red Hat, Inc. @@ -24,26 +25,35 @@ package vpp import ( "context" + "errors" "fmt" "io/ioutil" "net" "os" + "os/exec" + "path" + "path/filepath" "strings" "sync" "time" + "github.com/skydive-project/skydive/common" + govpp "git.fd.io/govpp.git" "git.fd.io/govpp.git/api" "git.fd.io/govpp.git/core" "github.com/sirupsen/logrus" + "github.com/skydive-project/skydive/config" "github.com/skydive-project/skydive/graffiti/graph" "github.com/skydive-project/skydive/probe" "github.com/skydive-project/skydive/topology" "github.com/skydive-project/skydive/topology/probes" tp "github.com/skydive-project/skydive/topology/probes" + "github.com/skydive-project/skydive/topology/probes/docker" "github.com/skydive-project/skydive/topology/probes/vpp/bin_api/interfaces" + "github.com/skydive-project/skydive/topology/probes/vpp/bin_api/memif" "github.com/skydive-project/skydive/topology/probes/vpp/bin_api/vpe" ) @@ -54,16 +64,27 @@ const ( HealthCheckInterval = 3 * time.Second ) +var memifModes = map[uint8]string{ + 0: "ethernet", + 1: "ip", + 2: "punt/inject", +} + // Probe is an instance of a VPP probe in a namespace type Probe struct { sync.Mutex *graph.EventHandler + graph.DefaultGraphListener Ctx tp.Context addr string // VPP address (unix or SHM) conn *core.Connection // VPP connection interfaceMap map[uint32]*interfaces.SwInterfaceDetails // map of VPP interfaces intfIndexer *graph.MetadataIndexer // index of created nodes by the probe vppRootNode *graph.Node // root node for ownership + socketsDirs []string + masterMemifs *graph.NodeIndex + slaveMemifs *graph.NodeIndex + seeds map[int64]*exec.Cmd } func interfaceName(name []byte) string { @@ -107,16 +128,32 @@ func (p *Probe) getInterface(index uint32) *graph.Node { return node } -func (p *Probe) createOrUpdateInterface(ch api.Channel, intf *interfaces.SwInterfaceDetails) *graph.Node { +func (p *Probe) createOrUpdateInterface(ch api.Channel, intf *interfaces.SwInterfaceDetails, metadata graph.Metadata) *graph.Node { vrfID := p.getInterfaceVrfID(ch, intf.SwIfIndex) + name := interfaceName(intf.InterfaceName) p.Ctx.Graph.Lock() defer p.Ctx.Graph.Unlock() + metadata["Driver"] = "vpp" + metadata["Type"] = "interface" + metadata["Name"] = name + metadata["IfIndex"] = int64(intf.SwIfIndex) + metadata["MAC"] = interfaceMAC(intf.L2Address[:intf.L2AddressLength]) + metadata["MTU"] = int64(intf.LinkMtu) + metadata["Speed"] = int64(intf.LinkSpeed) + metadata["State"] = interfaceUpDown(intf.AdminUpDown) + metadata["Duplex"] = interfaceDuplex(intf.LinkDuplex) + metadata["VrfID"] = vrfID + + if strings.HasPrefix(name, "host-") { + metadata["InterfaceName"] = name[5:] + } + var err error node := p.getInterface(intf.SwIfIndex) if node == nil { - node, err = p.Ctx.Graph.NewNode(graph.GenID(), graph.Metadata{"IfIndex": int64(intf.SwIfIndex), "Type": "vpp"}) + node, err = p.Ctx.Graph.NewNode(graph.GenID(), metadata) if err != nil { p.Ctx.Logger.Error(err) return nil @@ -127,24 +164,10 @@ func (p *Probe) createOrUpdateInterface(ch api.Channel, intf *interfaces.SwInter p.Ctx.Logger.Error(err) return nil } + } else { + p.Ctx.Graph.SetMetadata(node, metadata) + p.NotifyEvent(graph.NodeUpdated, node) } - - tr := p.Ctx.Graph.StartMetadataTransaction(node) - tr.AddMetadata("Driver", "vpp") - tr.AddMetadata("Name", interfaceName(intf.InterfaceName)) - tr.AddMetadata("IfIndex", int64(intf.SwIfIndex)) - tr.AddMetadata("MAC", interfaceMAC(intf.L2Address[:intf.L2AddressLength])) - tr.AddMetadata("MTU", int64(intf.LinkMtu)) - tr.AddMetadata("Speed", int64(intf.LinkSpeed)) - state := interfaceUpDown(intf.AdminUpDown) - tr.AddMetadata("State", state) - if state != "DOWN" { - tr.AddMetadata("Duplex", interfaceDuplex(intf.LinkDuplex)) - } - tr.AddMetadata("VrfID", vrfID) - tr.Commit() - - p.NotifyEvent(graph.NodeUpdated, node) return node } @@ -154,8 +177,8 @@ func interfaceNeedUpdate(i1, i2 *interfaces.SwInterfaceDetails) bool { i1.LinkDuplex != i2.LinkDuplex } -func (p *Probe) eventAddInterface(ch api.Channel, intf *interfaces.SwInterfaceDetails) { - p.createOrUpdateInterface(ch, intf) +func (p *Probe) eventAddInterface(ch api.Channel, intf *interfaces.SwInterfaceDetails, metadata graph.Metadata) *graph.Node { + return p.createOrUpdateInterface(ch, intf, metadata) } func (p *Probe) eventDelInterface(node *graph.Node) { @@ -176,6 +199,43 @@ func (p *Probe) interfaceEventsEnableDisable(ch api.Channel, enable bool) { } } +type memifSocket struct { + *memif.MemifDetails + filename string +} + +func (p *Probe) fetchMemif(ch api.Channel) (map[uint32]*memifSocket, error) { + sharedMemifSockets := make(map[uint32]*memifSocket) + + req := &memif.MemifSocketFilenameDump{} + msg := &memif.MemifSocketFilenameDetails{} + reqCtx := ch.SendMultiRequest(req) + for { + if lastReply, err := reqCtx.ReceiveReply(msg); lastReply { + break + } else if err != nil { + return nil, err + } + + sharedMemifSockets[msg.SocketID] = &memifSocket{filename: interfaceName(msg.SocketFilename)} + } + + req2 := &memif.MemifDump{} + msg2 := &memif.MemifDetails{} + reqCtx = ch.SendMultiRequest(req2) + for { + if lastReply, err := reqCtx.ReceiveReply(msg2); lastReply { + break + } else if err != nil { + return nil, err + } + + sharedMemifSockets[msg2.SocketID].MemifDetails = msg2 + } + + return sharedMemifSockets, nil +} + func (p *Probe) synchronize(ch api.Channel) error { foundInterfaces := make(map[uint32]struct{}) needUpdate := make(map[uint32]struct{}) @@ -187,8 +247,7 @@ func (p *Probe) synchronize(ch api.Channel) error { stop, err := reqCtx.ReceiveReply(msg) if stop { break - } - if err != nil { + } else if err != nil { return err } @@ -203,10 +262,38 @@ func (p *Probe) synchronize(ch api.Channel) error { } /* Update interface metadata */ + var sharedMemifSockets map[uint32]*memifSocket for index := range needUpdate { + metadata := make(graph.Metadata) msg := p.interfaceMap[index] - p.Ctx.Logger.Debugf("Add/Update interface %s idx %d up/down %s", interfaceName(msg.InterfaceName), int64(msg.SwIfIndex), interfaceUpDown(msg.AdminUpDown)) - p.eventAddInterface(ch, msg) + ifName := interfaceName(msg.InterfaceName) + p.Ctx.Logger.Debugf("Add/Update interface %s idx %d up/down %s", ifName, int64(msg.SwIfIndex), interfaceUpDown(msg.AdminUpDown)) + + var socket, id int + if _, err := fmt.Sscanf(string(ifName), "memif%d/%d", &socket, &id); err == nil { + metadata["Type"] = "memif" + + if sharedMemifSockets == nil { + if sharedMemifSockets, err = p.fetchMemif(ch); err != nil { + return err + } + } + + if memifSock, ok := sharedMemifSockets[uint32(socket)]; ok { + metadata["VPP"] = &Metadata{ + SocketFilename: memifSock.filename, + ID: int64(memifSock.ID), + SocketID: int64(socket), + Master: memifSock.Role == 0, + Mode: memifModes[memifSock.Mode], + RingSize: int64(memifSock.RingSize), + BufferSize: int64(memifSock.BufferSize), + LinkUpDown: memifSock.LinkUpDown == 1, + } + } + } + + p.eventAddInterface(ch, msg, metadata) } /* Remove interface that didn't exist anymore */ @@ -228,6 +315,134 @@ func (p *Probe) synchronize(ch api.Channel) error { return nil } +func (p *Probe) getHostSocketFilename(socketFilename string, n *graph.Node) (string, error) { + vppNode := topology.GetOwner(p.Ctx.Graph, n) + if vppNode == nil { + return "", fmt.Errorf("No owner found for node %s", n.ID) + } + + rootNode := topology.GetOwner(p.Ctx.Graph, vppNode) + if rootNode == nil { + return "", fmt.Errorf("No root owner found for node %s", vppNode.ID) + } + + containerNode := p.Ctx.Graph.LookupFirstChild(rootNode, graph.Metadata{"Type": "container"}) + if containerNode == nil { + return "", fmt.Errorf("No container found in node %s", rootNode.ID) + } + + if dockerMetadata, err := containerNode.GetField("Docker"); err == nil { + dockerMetadata := dockerMetadata.(*docker.Metadata) + for _, mount := range dockerMetadata.Mounts { + if filepath.HasPrefix(socketFilename, mount.Destination) { + if hostPath, err := filepath.Rel(mount.Destination, socketFilename); err == nil { + return filepath.Join(mount.Source, hostPath), nil + } + } + } + } + + return "", nil +} + +func (p *Probe) indexSocketFilename(socketFilename string, intfNode *graph.Node) { + socketFilename, err := p.getHostSocketFilename(socketFilename, intfNode) + + if err != nil { + p.Ctx.Logger.Error(err) + return + } + + if socketFilename == "" { + return + } + + if isMaster, _ := intfNode.GetFieldBool("VPP.Master"); isMaster { + p.masterMemifs.Index(intfNode.ID, intfNode, map[string]interface{}{socketFilename: nil}) + } else { + p.slaveMemifs.Index(intfNode.ID, intfNode, map[string]interface{}{socketFilename: nil}) + } + + p.Ctx.Logger.Debugf("Indexed %s", socketFilename) +} + +// Register a seed with the specified mount namespace +func (p *Probe) startSeed(pid int64, root *graph.Node) (*exec.Cmd, error) { + if config.GetString("agent.auth.api.backend") != "noauth" { + return nil, errors.New("Starting seeds is only supported with the 'noauth' authentication backend") + } + + seed := os.Getenv("SKYDIVE_SEED_EXECUTABLE") + if seed == "" { + seed = os.Args[0] + } + nsPath := fmt.Sprintf("/proc/%d/ns", pid) + sa, _ := common.ServiceAddressFromString(config.GetString("agent.listen")) + command := exec.Command(seed, "seed", + "--root="+string(root.ID), + "--pid="+path.Join(nsPath, "pid"), + "--mount="+path.Join(nsPath, "mnt"), + "--agent="+fmt.Sprintf("%s:%d", sa.Addr, sa.Port), + fmt.Sprintf("--filter=G.V('%s').Descendants().Subgraph()", root.ID), + "vpp") + command.Env = append(command.Env, fmt.Sprintf("SKYDIVE_LOGGING_LEVEL=%s", p.Ctx.Config.GetString("logging.level"))) + command.Env = append(command.Env, fmt.Sprintf("SKYDIVE_HOST_ID=vpp-%s", root.ID)) + command.Stdout = os.Stdout + command.Stderr = os.Stderr + p.Ctx.Logger.Debugf("Starting seed in pid and mount namespaces of process %d (%s)", pid, strings.Join(command.Args, " ")) + + if err := command.Start(); err != nil { + return nil, fmt.Errorf("failed to start command %s", err) + } + + go command.Wait() + + return command, nil +} + +func (p *Probe) OnEdgeAdded(e *graph.Edge) { + if edgeType, _ := e.GetFieldString("RelationType"); edgeType != topology.OwnershipLink { + return + } + + intfNode := p.Ctx.Graph.GetNode(e.Child) + if s, _ := intfNode.GetFieldString("VPP.SocketFilename"); s != "" { + p.indexSocketFilename(s, intfNode) + } else if pid, err := intfNode.GetFieldInt64("InitProcessPID"); err == nil { + parent := p.Ctx.Graph.GetNode(e.Parent) + if t, _ := parent.GetFieldString("Type"); t == "netns" { + if _, found := p.seeds[pid]; !found { + seed, err := p.startSeed(pid, parent) + if err != nil { + p.Ctx.Logger.Errorf("Failed to start seed for %d: %s", pid, err) + return + } + p.seeds[pid] = seed + } + } + } +} + +func (p *Probe) GetABLinks(node *graph.Node) (edges []*graph.Edge) { + socketFilename, _ := node.GetFieldString("VPP.SocketFilename") + socketFilename, _ = p.getHostSocketFilename(socketFilename, node) + nodes, _ := p.slaveMemifs.Get(socketFilename) + for _, slave := range nodes { + edges = append(edges, topology.NewLink(p.Ctx.Graph, node, slave, "memif", nil)) + } + return +} + +func (p *Probe) GetBALinks(node *graph.Node) (edges []*graph.Edge) { + socketFilename, _ := node.GetFieldString("VPP.SocketFilename") + socketFilename, _ = p.getHostSocketFilename(socketFilename, node) + nodes, _ := p.masterMemifs.Get(socketFilename) + for _, master := range nodes { + edges = append(edges, topology.NewLink(p.Ctx.Graph, master, node, "memif", nil)) + } + return +} + func (p *Probe) handleInterfaceEvent(msg *interfaces.SwInterfaceEvent) { p.Ctx.Graph.Lock() if node := p.getInterface(msg.SwIfIndex); node != nil { @@ -252,7 +467,7 @@ func (p *Probe) run(ctx context.Context) { } ch.SetReplyTimeout(HealthCheckReplyTimeout) - notifChan := make(chan api.Message, 100) + notifChan := make(chan api.Message, 10) sub, err := ch.SubscribeNotification(notifChan, &interfaces.SwInterfaceEvent{}) if err != nil { p.Ctx.Logger.Error(err) @@ -262,14 +477,14 @@ func (p *Probe) run(ctx context.Context) { p.Ctx.Logger.Debugf("Registering for VPP events") p.interfaceEventsEnableDisable(ch, true) - pollingTicker := time.NewTicker(VPPPollingTime) - defer pollingTicker.Stop() - if err := p.synchronize(ch); err != nil { p.Ctx.Logger.Error(err) return } + pollingTicker := time.NewTicker(VPPPollingTime) + defer pollingTicker.Stop() + pingTimer := time.NewTimer(HealthCheckInterval) defer pingTimer.Stop() @@ -294,6 +509,7 @@ LOOP: } if err != nil { + p.Ctx.Logger.Error(err) break } @@ -353,11 +569,26 @@ func (p *Probe) Do(ctx context.Context, wg *sync.WaitGroup) error { go func() { defer wg.Done() + hostNameIndexer := graph.NewMetadataIndexer(p.Ctx.Graph, p.Ctx.Graph, graph.Metadata{"Type": "veth"}, "Name") + vppNameIndexer := graph.NewMetadataIndexer(p.Ctx.Graph, p, nil, "InterfaceName") + nameLinker := graph.NewMetadataIndexerLinker(p.Ctx.Graph, hostNameIndexer, vppNameIndexer, topology.Layer2Metadata()) + p.intfIndexer.Start() defer p.intfIndexer.Stop() + hostNameIndexer.Start() + defer hostNameIndexer.Stop() + + vppNameIndexer.Start() + defer vppNameIndexer.Stop() + + nameLinker.Start() + defer nameLinker.Stop() + p.Ctx.Graph.RLock() p.intfIndexer.Sync() + hostNameIndexer.Sync() + vppNameIndexer.Sync() p.Ctx.Graph.RUnlock() p.run(ctx) @@ -375,9 +606,19 @@ func NewProbe(ctx tp.Context, bundle *probe.Bundle) (probe.Handler, error) { Ctx: ctx, addr: addr, interfaceMap: make(map[uint32]*interfaces.SwInterfaceDetails), + masterMemifs: graph.NewNodeIndex(ctx.Graph, false), + slaveMemifs: graph.NewNodeIndex(ctx.Graph, false), + seeds: make(map[int64]*exec.Cmd), } - p.intfIndexer = graph.NewMetadataIndexer(p.Ctx.Graph, p, nil, "IfIndex") + p.intfIndexer = graph.NewMetadataIndexer(p.Ctx.Graph, p, graph.Metadata{"Host": ctx.Graph.GetHost()}, "IfIndex") + + // This linkers creates edges between memif interfaces. + // It is started in the Init method so that links are created by + // the agent (not the seeds), even if VPP is not running on the host + // (only in the containers) + memifLinker := graph.NewResourceLinker(p.Ctx.Graph, []graph.ListenerHandler{p.masterMemifs}, []graph.ListenerHandler{p.slaveMemifs}, p, nil) + memifLinker.Start() /* Forward all govpp logging to Skydive logging */ l := logrus.New() @@ -385,6 +626,8 @@ func NewProbe(ctx tp.Context, bundle *probe.Bundle) (probe.Handler, error) { l.Hooks.Add(p) core.SetLogger(l) + ctx.Graph.AddEventListener(p) + return probes.NewProbeWrapper(p), nil } From 1c253894a32862d2457fe7d736b6911c61f69326 Mon Sep 17 00:00:00 2001 From: Filip Gschwandtner Date: Thu, 13 Jun 2019 17:10:02 +0200 Subject: [PATCH 11/15] test: added functional tests for topology probe of VPP running in docker container Signed-off-by: Filip Gschwandtner --- scripts/ci/jobs/jobs.yml | 4 +- tests/vpp_test.go | 124 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 2 deletions(-) diff --git a/scripts/ci/jobs/jobs.yml b/scripts/ci/jobs/jobs.yml index 896751a1ce..0d2afafe7d 100644 --- a/scripts/ci/jobs/jobs.yml +++ b/scripts/ci/jobs/jobs.yml @@ -374,7 +374,7 @@ builders: - skydive-cleanup - skydive-test: - test: BACKEND=elasticsearch ARGS="-ovs.oflow.native" scripts/ci/run-functional-tests.sh + test: BACKEND=elasticsearch WITH_DOCKER_VPP=true ARGS="-ovs.oflow.native" scripts/ci/run-functional-tests.sh publishers: - junit: results: tests.xml @@ -392,7 +392,7 @@ builders: - skydive-cleanup - skydive-test: - test: BACKEND=orientdb scripts/ci/run-functional-tests.sh + test: BACKEND=orientdb WITH_DOCKER_VPP=true scripts/ci/run-functional-tests.sh publishers: - junit: results: tests.xml diff --git a/tests/vpp_test.go b/tests/vpp_test.go index 22762a73a6..a5405e5e6c 100644 --- a/tests/vpp_test.go +++ b/tests/vpp_test.go @@ -2,6 +2,7 @@ /* * Copyright (C) 2019 Red Hat, Inc. + * Copyright (c) 2019 PANTHEON.tech s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,9 +28,15 @@ import ( "time" "github.com/skydive-project/skydive/graffiti/graph" + "github.com/skydive-project/skydive/gremlin" "github.com/skydive-project/skydive/topology/probes/vpp" ) +const ( + dockerImageWithRunningVPP = "ligato/vpp-base:19.04" + vppWaitScript = "sh -c 'retry=%d;until docker exec %s vppctl sh version || [ $retry -eq 0 ]; do retry=$(( retry-1 ));sleep 0.5s;echo \"VPP not ready-retries left \"$retry;done'" +) + func createLoopback(t *testing.T) string { cmd := "vppctl loopback create-interface" out, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() @@ -99,3 +106,120 @@ func TestVPPLoopback(t *testing.T) { } RunTest(t, test) } + +func TestVPPInDocker(t *testing.T) { + test := &Test{ + setupCmds: []Cmd{ + {fmt.Sprintf("docker run -d -t -i --privileged --name test-skydive-docker-running-vpp %s", dockerImageWithRunningVPP), false}, + {fmt.Sprintf(vppWaitScript, 30, "test-skydive-docker-running-vpp"), true}, + }, + + tearDownCmds: []Cmd{ + {"docker rm -f test-skydive-docker-running-vpp", false}, + }, + + mode: Replay, + + checks: []CheckFunction{func(c *CheckContext) error { + return assertOneEndNode(c, c.gremlin.V().Has("Type", "netns"). + Out("Type", "vpp")) + }}, + } + + RunTest(t, test) +} + +func TestVPPConnectingToVeth(t *testing.T) { + test := &Test{ + setupCmds: []Cmd{ + {fmt.Sprintf("docker run -d -t -i --privileged --name test-skydive-docker-vpp-to-veth %s", dockerImageWithRunningVPP), false}, + {fmt.Sprintf(vppWaitScript, 30, "test-skydive-docker-vpp-to-veth"), true}, + {"docker exec test-skydive-docker-vpp-to-veth ip link add name veth-container type veth peer name veth-host", true}, // creating veth tunnel (that can be used to tunnel docker container and docker host) + {"docker exec test-skydive-docker-vpp-to-veth ip link set dev veth-container up", true}, + {"docker exec test-skydive-docker-vpp-to-veth ip link set dev veth-host up", true}, // no need for this test to actually push veth-host to network namespace of docker host OS + {"docker exec test-skydive-docker-vpp-to-veth vppctl create host-interface name veth-container", true}, // grabbing and using veth-container end of tunnel in VPP + {"docker exec test-skydive-docker-vpp-to-veth vppctl set int state host-veth-container up", true}, + }, + + tearDownCmds: []Cmd{ + {"docker rm -f test-skydive-docker-vpp-to-veth", false}, + }, + + mode: Replay, + + checks: []CheckFunction{func(c *CheckContext) error { + return assertOneEndNode(c, c.gremlin.V().Has("Type", "interface", "Driver", "vpp", "Name", "host-veth-container"). + In("Type", "veth", "Name", "veth-container")) + }}, + } + + RunTest(t, test) +} + +func TestVPPMemifTunnel(t *testing.T) { + vpp1Container := "test-skydive-docker-vpp1-with-memif-tunnel" + vpp2Container := "test-skydive-docker-vpp2-with-memif-tunnel" + test := &Test{ + setupCmds: []Cmd{ + // prepare container-shared folder (docker would create it automatically, but creating it now and with user that is running test resolves permission problems in teardown) + {"mkdir /tmp/skydivetests-dockervpp-sockets", false}, + + // starting docker contrainers + {fmt.Sprintf("docker run -d -t -i -v /tmp/skydivetests-dockervpp-sockets/:/run/othersockets/ --privileged --name %s %s", vpp1Container, dockerImageWithRunningVPP), false}, + {fmt.Sprintf("docker run -d -t -i -v /tmp/skydivetests-dockervpp-sockets/:/run/othersockets/ --privileged --name %s %s", vpp2Container, dockerImageWithRunningVPP), false}, + + // waiting for VPPs to start inside containers + {fmt.Sprintf(vppWaitScript, 30, vpp1Container), true}, + {fmt.Sprintf(vppWaitScript, 30, vpp2Container), true}, + + // creating memif tunnel + {fmt.Sprintf("docker exec %s vppctl create memif socket id 1 filename /run/othersockets/another-memif.sock", vpp1Container), true}, + {fmt.Sprintf("docker exec %s vppctl create interface memif socket-id 1 id 0 master", vpp1Container), true}, + {fmt.Sprintf("docker exec %s vppctl set int state memif1/0 up", vpp1Container), true}, + {fmt.Sprintf("docker exec %s vppctl create memif socket id 1 filename /run/othersockets/another-memif.sock", vpp2Container), true}, + {fmt.Sprintf("docker exec %s vppctl create interface memif socket-id 1 id 0 slave", vpp2Container), true}, + {fmt.Sprintf("docker exec %s vppctl set int state memif1/0 up", vpp2Container), true}, + }, + + tearDownCmds: []Cmd{ + // removing memif socket file (it was created by VPP,but removing it from VPP doesn't remove the physical + // file->removing reference from VPPs and removing it on docker container level to prevent permission problems) + {fmt.Sprintf("docker exec %s vppctl delete interface memif memif1/0", vpp1Container), true}, + {fmt.Sprintf("docker exec %s vppctl delete interface memif memif1/0", vpp2Container), true}, + {fmt.Sprintf("docker exec %s vppctl delete memif socket id 1", vpp1Container), true}, + {fmt.Sprintf("docker exec %s vppctl delete memif socket id 1", vpp2Container), true}, + {fmt.Sprintf("docker exec %s rm -rf /run/othersockets/another-memif.sock", vpp1Container), true}, + + // removing docker containers + {fmt.Sprintf("docker rm -f %s", vpp1Container), false}, + {fmt.Sprintf("docker rm -f %s", vpp2Container), false}, + + // removing container-shared folder for memif socket file + {"rm -rf /tmp/skydivetests-dockervpp-sockets", true}, + }, + + mode: Replay, + + checks: []CheckFunction{func(c *CheckContext) error { + return assertOneEndNode(c, c.gremlin.V().Has("Type", "vpp", "Program", "vpe"). + Out("Type", "interface", "Name", "memif1/0", "VPP.SocketFilename", "/run/othersockets/another-memif.sock", "VPP.Master", true). + Out("Type", "interface", "Name", "memif1/0", "VPP.SocketFilename", "/run/othersockets/another-memif.sock", "VPP.Master", false). + In("Type", "vpp", "Program", "vpe")) + }}, + } + + RunTest(t, test) +} + +func assertOneEndNode(c *CheckContext, queryString gremlin.QueryString) error { + nodes, err := c.gh.GetNodes(queryString) + if err != nil { + return err + } + + if len(nodes) != 1 { + return fmt.Errorf("expected 1 end node, got %+v", nodes) + } + + return nil +} From 009060adb89f4ba5236adbfbefc1ab2c67cf2a1e Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Wed, 18 Sep 2019 10:44:46 +0200 Subject: [PATCH 12/15] tests: build skydive executable to run VPP tests --- scripts/ci/jobs/jobs.yml | 2 +- scripts/ci/run-hw-functional-tests.sh | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100755 scripts/ci/run-hw-functional-tests.sh diff --git a/scripts/ci/jobs/jobs.yml b/scripts/ci/jobs/jobs.yml index 0d2afafe7d..15ca0d81c8 100644 --- a/scripts/ci/jobs/jobs.yml +++ b/scripts/ci/jobs/jobs.yml @@ -825,7 +825,7 @@ builders: - skydive-cleanup - skydive-test: - test: BACKEND=elasticsearch WITH_EBPF=true WITH_VPP=true TEST_PATTERN='(EBPF|SRIOV|VPP|Libvirt)' TAGS="$TAGS libvirt_tests sriov_tests" scripts/ci/run-functional-tests.sh + test: scripts/ci/run-hw-functional-tests.sh publishers: - junit: results: tests.xml diff --git a/scripts/ci/run-hw-functional-tests.sh b/scripts/ci/run-hw-functional-tests.sh new file mode 100755 index 0000000000..978b0d1ea5 --- /dev/null +++ b/scripts/ci/run-hw-functional-tests.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -v +set -e + +DIR="$(dirname "$0")" + +. "$DIR/run-tests-utils.sh" +network_setup + +# Build the skydive executable for starting seeds +make WITH_VPP=true + +WITH_OVN=true WITH_OPENCONTRAIL=false WITH_EBPF=true WITH_VPP=true \ +SKYDIVE_SEED_EXECUTABLE=$GOPATH/bin/skydive \ +BACKEND=elasticsearch TEST_PATTERN='(EBPF|SRIOV|VPP|Libvirt)' \ +TAGS="$TAGS libvirt_tests sriov_tests" tests_run + +exit $RETCODE From cb3aa7875ca866ef55e69e482da2f2092e45c421 Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Thu, 19 Sep 2019 20:21:59 +0200 Subject: [PATCH 13/15] graffiti: fix races when a subscriber with a filter connects --- graffiti/common/subscriber_endpoint.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/graffiti/common/subscriber_endpoint.go b/graffiti/common/subscriber_endpoint.go index 9384949652..e846464f7e 100644 --- a/graffiti/common/subscriber_endpoint.go +++ b/graffiti/common/subscriber_endpoint.go @@ -87,14 +87,16 @@ func (t *SubscriberEndpoint) OnConnected(c ws.Speaker) { if gremlinFilter != "" { host := c.GetRemoteHost() - subscriber, err := t.newSubscriber(host, gremlinFilter, false) + subscriber, err := t.newSubscriber(host, gremlinFilter, true) if err != nil { logging.GetLogger().Error(err) return } logging.GetLogger().Infof("Client %s subscribed with filter %s during the connection", host, gremlinFilter) + t.Lock() t.subscribers[c] = subscriber + t.Unlock() } } From 948f49aefe247cc3d417b409be677402c6b02ecb Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Thu, 19 Sep 2019 20:54:53 +0200 Subject: [PATCH 14/15] docker: use pointer for metadata --- topology/probes/docker/docker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topology/probes/docker/docker.go b/topology/probes/docker/docker.go index 18e4ae514c..e6258db58c 100644 --- a/topology/probes/docker/docker.go +++ b/topology/probes/docker/docker.go @@ -106,7 +106,7 @@ func (p *ProbeHandler) registerContainer(id string) { pid := int64(info.State.Pid) - dockerMetadata := Metadata{ + dockerMetadata := &Metadata{ ContainerID: info.ID, ContainerName: info.Name[1:], } From 5685f7defc84ad998c08ca978a37429519a60719 Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Fri, 20 Sep 2019 10:05:49 +0200 Subject: [PATCH 15/15] graffiti: ensure indexer do not return nil nodes --- graffiti/graph/indexer.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/graffiti/graph/indexer.go b/graffiti/graph/indexer.go index 9ff8dbd70b..378a4c0dfc 100644 --- a/graffiti/graph/indexer.go +++ b/graffiti/graph/indexer.go @@ -62,8 +62,10 @@ type Indexer struct { func (i *NodeIndex) FromHash(hash string) (nodes []*Node, values []interface{}) { if ids, found := i.hashToValues[hash]; found { for id, obj := range ids { - nodes = append(nodes, i.graph.GetNode(id)) - values = append(values, obj) + if node := i.graph.GetNode(id); node != nil { + nodes = append(nodes, node) + values = append(values, obj) + } } } return