mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Endpoint to expose interfaces' statistics
Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
88f16a11d2
commit
5ac330aca2
5 changed files with 140 additions and 0 deletions
|
@ -51,6 +51,9 @@ type Endpoint interface {
|
||||||
|
|
||||||
// Delete and detaches this endpoint from the network.
|
// Delete and detaches this endpoint from the network.
|
||||||
Delete() error
|
Delete() error
|
||||||
|
|
||||||
|
// Retrieve the interfaces' statistics from the sandbox
|
||||||
|
Statistics() (map[string]*sandbox.InterfaceStatistics, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointOption is a option setter function type used to pass varios options to Network
|
// EndpointOption is a option setter function type used to pass varios options to Network
|
||||||
|
@ -557,6 +560,33 @@ func (ep *endpoint) Delete() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ep *endpoint) Statistics() (map[string]*sandbox.InterfaceStatistics, error) {
|
||||||
|
m := make(map[string]*sandbox.InterfaceStatistics)
|
||||||
|
|
||||||
|
ep.Lock()
|
||||||
|
n := ep.network
|
||||||
|
skey := ep.container.data.SandboxKey
|
||||||
|
ep.Unlock()
|
||||||
|
|
||||||
|
n.Lock()
|
||||||
|
c := n.ctrlr
|
||||||
|
n.Unlock()
|
||||||
|
|
||||||
|
sbox := c.sandboxGet(skey)
|
||||||
|
if sbox == nil {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for _, i := range sbox.Info().Interfaces() {
|
||||||
|
if m[i.DstName()], err = i.Statistics(); err != nil {
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ep *endpoint) deleteEndpoint() error {
|
func (ep *endpoint) deleteEndpoint() error {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
n := ep.network
|
n := ep.network
|
||||||
|
|
|
@ -1042,6 +1042,15 @@ func TestEndpointJoin(t *testing.T) {
|
||||||
t.Fatalf("Endpoint ContainerInfo returned unexpected id: %s", ep1.ContainerInfo().ID())
|
t.Fatalf("Endpoint ContainerInfo returned unexpected id: %s", ep1.ContainerInfo().ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempt retrieval of endpoint interfaces statistics
|
||||||
|
stats, err := ep1.Statistics()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, ok := stats["eth0"]; !ok {
|
||||||
|
t.Fatalf("Did not find eth0 statistics")
|
||||||
|
}
|
||||||
|
|
||||||
// Now test the container joining another network
|
// Now test the container joining another network
|
||||||
n2, err := createTestNetwork(bridgeNetType, "testnetwork2",
|
n2, err := createTestNetwork(bridgeNetType, "testnetwork2",
|
||||||
options.Generic{
|
options.Generic{
|
||||||
|
|
|
@ -2,7 +2,9 @@ package sandbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/types"
|
||||||
|
@ -153,6 +155,33 @@ func (i *nwIface) Remove() error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the sandbox's side veth interface statistics
|
||||||
|
func (i *nwIface) Statistics() (*InterfaceStatistics, error) {
|
||||||
|
i.Lock()
|
||||||
|
n := i.ns
|
||||||
|
i.Unlock()
|
||||||
|
|
||||||
|
n.Lock()
|
||||||
|
path := n.path
|
||||||
|
n.Unlock()
|
||||||
|
|
||||||
|
s := &InterfaceStatistics{}
|
||||||
|
|
||||||
|
err := nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
|
||||||
|
data, err := ioutil.ReadFile(netStatsFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open %s: %v", netStatsFile, err)
|
||||||
|
}
|
||||||
|
return scanInterfaceStats(string(data), i.DstName(), s)
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
func (n *networkNamespace) findDst(srcName string, isBridge bool) string {
|
func (n *networkNamespace) findDst(srcName string, isBridge bool) string {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
@ -311,3 +340,28 @@ func setInterfaceRoutes(iface netlink.Link, i *nwIface) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In older kernels (like the one in Centos 6.6 distro) sysctl does not have netns support. Therefore
|
||||||
|
// we cannot gather the statistics from /sys/class/net/<dev>/statistics/<counter> files. Per-netns stats
|
||||||
|
// are naturally found in /proc/net/dev in kernels which support netns (ifconfig relyes on that).
|
||||||
|
const (
|
||||||
|
netStatsFile = "/proc/net/dev"
|
||||||
|
base = "[ ]*%s:([ ]+[0-9]+){16}"
|
||||||
|
)
|
||||||
|
|
||||||
|
func scanInterfaceStats(data, ifName string, i *InterfaceStatistics) error {
|
||||||
|
var (
|
||||||
|
bktStr string
|
||||||
|
bkt uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
regex := fmt.Sprintf(base, ifName)
|
||||||
|
re := regexp.MustCompile(regex)
|
||||||
|
line := re.FindString(data)
|
||||||
|
|
||||||
|
_, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
|
||||||
|
&bktStr, &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, &bkt, &bkt, &bkt,
|
||||||
|
&bkt, &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, &bkt, &bkt, &bkt, &bkt)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package sandbox
|
package sandbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/types"
|
||||||
|
@ -146,4 +147,24 @@ type Interface interface {
|
||||||
// Remove an interface from the sandbox by renaming to original name
|
// Remove an interface from the sandbox by renaming to original name
|
||||||
// and moving it out of the sandbox.
|
// and moving it out of the sandbox.
|
||||||
Remove() error
|
Remove() error
|
||||||
|
|
||||||
|
// Statistics returns the statistics for this interface
|
||||||
|
Statistics() (*InterfaceStatistics, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceStatistics represents the interface's statistics
|
||||||
|
type InterfaceStatistics struct {
|
||||||
|
RxBytes uint64
|
||||||
|
RxPackets uint64
|
||||||
|
RxErrors uint64
|
||||||
|
RxDropped uint64
|
||||||
|
TxBytes uint64
|
||||||
|
TxPackets uint64
|
||||||
|
TxErrors uint64
|
||||||
|
TxDropped uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *InterfaceStatistics) String() string {
|
||||||
|
return fmt.Sprintf("\nRxBytes: %d, RxPackets: %d, RxErrors: %d, RxDropped: %d, TxBytes: %d, TxPackets: %d, TxErrors: %d, TxDropped: %d",
|
||||||
|
is.RxBytes, is.RxPackets, is.RxErrors, is.RxDropped, is.TxBytes, is.TxPackets, is.TxErrors, is.TxDropped)
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,3 +152,29 @@ func verifyCleanup(t *testing.T, s Sandbox, wait bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestScanStatistics(t *testing.T) {
|
||||||
|
data :=
|
||||||
|
"Inter-| Receive | Transmit\n" +
|
||||||
|
" face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n" +
|
||||||
|
" eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
|
||||||
|
" wlan0: 7787685 11141 0 0 0 0 0 0 1681390 7220 0 0 0 0 0 0\n" +
|
||||||
|
" lo: 783782 1853 0 0 0 0 0 0 783782 1853 0 0 0 0 0 0\n" +
|
||||||
|
"lxcbr0: 0 0 0 0 0 0 0 0 9006 61 0 0 0 0 0 0\n"
|
||||||
|
|
||||||
|
i := &InterfaceStatistics{}
|
||||||
|
|
||||||
|
if err := scanInterfaceStats(data, "wlan0", i); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if i.TxBytes != 1681390 || i.TxPackets != 7220 || i.RxBytes != 7787685 || i.RxPackets != 11141 {
|
||||||
|
t.Fatalf("Error scanning the statistics")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanInterfaceStats(data, "lxcbr0", i); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if i.TxBytes != 9006 || i.TxPackets != 61 || i.RxBytes != 0 || i.RxPackets != 0 {
|
||||||
|
t.Fatalf("Error scanning the statistics")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue