[lxc-devel] [lxd/master] lxd/resources: Add GetNetworkState and GetNetworkCounters
stgraber on Github
lxc-bot at linuxcontainers.org
Tue Nov 24 19:11:45 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 448 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20201124/00e785cb/attachment-0001.bin>
-------------- next part --------------
From 52e73d97455e075b5791e1448fbe0c9115ed1cf7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 24 Nov 2020 14:10:55 -0500
Subject: [PATCH] lxd/resources: Add GetNetworkState and GetNetworkCounters
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Will be useful for external consumption by MAAS.
Also improves error handling slightly.
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/device/nic_bridged.go | 7 +-
lxd/device/nic_ovn.go | 7 +-
lxd/networks.go | 12 +-
lxd/networks_utils.go | 180 ---------------------------
lxd/resources/network.go | 248 ++++++++++++++++++++++++++++++++++++++
shared/network.go | 51 --------
6 files changed, 265 insertions(+), 240 deletions(-)
diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index f79fd3549c..21f70b8a3d 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -26,6 +26,7 @@ import (
"github.com/lxc/lxd/lxd/network"
"github.com/lxc/lxd/lxd/network/openvswitch"
"github.com/lxc/lxd/lxd/project"
+ "github.com/lxc/lxd/lxd/resources"
"github.com/lxc/lxd/lxd/revert"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
@@ -1192,7 +1193,11 @@ func (d *nicBridged) State() (*api.InstanceStateNetwork, error) {
// Retrieve the host counters, as we report the values from the instance's point of view,
// those counters need to be reversed below.
- hostCounters := shared.NetworkGetCounters(d.config["host_name"])
+ hostCounters, err := resources.GetNetworkCounters(d.config["host_name"])
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed getting network interface counters")
+ }
+
network := api.InstanceStateNetwork{
Addresses: addresses,
Counters: api.InstanceStateNetworkCounters{
diff --git a/lxd/device/nic_ovn.go b/lxd/device/nic_ovn.go
index 8669939e9a..415f5271cc 100644
--- a/lxd/device/nic_ovn.go
+++ b/lxd/device/nic_ovn.go
@@ -17,6 +17,7 @@ import (
"github.com/lxc/lxd/lxd/network"
"github.com/lxc/lxd/lxd/network/openvswitch"
"github.com/lxc/lxd/lxd/project"
+ "github.com/lxc/lxd/lxd/resources"
"github.com/lxc/lxd/lxd/revert"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
@@ -586,7 +587,11 @@ func (d *nicOVN) State() (*api.InstanceStateNetwork, error) {
// Retrieve the host counters, as we report the values from the instance's point of view,
// those counters need to be reversed below.
- hostCounters := shared.NetworkGetCounters(d.config["host_name"])
+ hostCounters, err := resources.GetNetworkCounters(d.config["host_name"])
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed getting network interface counters")
+ }
+
network := api.InstanceStateNetwork{
Addresses: addresses,
Counters: api.InstanceStateNetworkCounters{
diff --git a/lxd/networks.go b/lxd/networks.go
index 09ea358629..dc444a9892 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -23,6 +23,7 @@ import (
"github.com/lxc/lxd/lxd/network"
"github.com/lxc/lxd/lxd/network/openvswitch"
"github.com/lxc/lxd/lxd/project"
+ "github.com/lxc/lxd/lxd/resources"
"github.com/lxc/lxd/lxd/response"
"github.com/lxc/lxd/lxd/revert"
"github.com/lxc/lxd/lxd/state"
@@ -1134,13 +1135,10 @@ func networkStateGet(d *Daemon, r *http.Request) response.Response {
name := mux.Vars(r)["name"]
- // Get some information
- osInfo, _ := net.InterfaceByName(name)
-
- // Sanity check
- if osInfo == nil {
- return response.NotFound(fmt.Errorf("Interface '%s' not found", name))
+ state, err := resources.GetNetworkState(name)
+ if err != nil {
+ return response.SmartError(err)
}
- return response.SyncResponse(true, networkGetState(*osInfo))
+ return response.SyncResponse(true, state)
}
diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go
index dc8e834353..35f4c16748 100644
--- a/lxd/networks_utils.go
+++ b/lxd/networks_utils.go
@@ -1,10 +1,7 @@
package main
import (
- "fmt"
"io/ioutil"
- "net"
- "path/filepath"
"strconv"
"strings"
@@ -13,8 +10,6 @@ import (
"github.com/lxc/lxd/lxd/network"
"github.com/lxc/lxd/lxd/project"
"github.com/lxc/lxd/lxd/state"
- "github.com/lxc/lxd/shared"
- "github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
)
@@ -70,178 +65,3 @@ func networkUpdateForkdnsServersTask(s *state.State, heartbeatData *cluster.APIH
return nil
}
-
-func networkGetState(netIf net.Interface) api.NetworkState {
- netState := "down"
- netType := "unknown"
-
- if netIf.Flags&net.FlagBroadcast > 0 {
- netType = "broadcast"
- }
-
- if netIf.Flags&net.FlagPointToPoint > 0 {
- netType = "point-to-point"
- }
-
- if netIf.Flags&net.FlagLoopback > 0 {
- netType = "loopback"
- }
-
- if netIf.Flags&net.FlagUp > 0 {
- netState = "up"
- }
-
- network := api.NetworkState{
- Addresses: []api.NetworkStateAddress{},
- Counters: api.NetworkStateCounters{},
- Hwaddr: netIf.HardwareAddr.String(),
- Mtu: netIf.MTU,
- State: netState,
- Type: netType,
- }
-
- // Populate address information.
- addrs, err := netIf.Addrs()
- if err == nil {
- for _, addr := range addrs {
- fields := strings.SplitN(addr.String(), "/", 2)
- if len(fields) != 2 {
- continue
- }
-
- family := "inet"
- if strings.Contains(fields[0], ":") {
- family = "inet6"
- }
-
- scope := "global"
- if strings.HasPrefix(fields[0], "127") {
- scope = "local"
- }
-
- if fields[0] == "::1" {
- scope = "local"
- }
-
- if strings.HasPrefix(fields[0], "169.254") {
- scope = "link"
- }
-
- if strings.HasPrefix(fields[0], "fe80:") {
- scope = "link"
- }
-
- address := api.NetworkStateAddress{}
- address.Family = family
- address.Address = fields[0]
- address.Netmask = fields[1]
- address.Scope = scope
-
- network.Addresses = append(network.Addresses, address)
- }
- }
-
- // Populate bond details.
- bondPath := fmt.Sprintf("/sys/class/net/%s/bonding", netIf.Name)
- if shared.PathExists(bondPath) {
- bonding := api.NetworkStateBond{}
-
- // Bond mode.
- strValue, err := ioutil.ReadFile(filepath.Join(bondPath, "mode"))
- if err == nil {
- bonding.Mode = strings.Split(strings.TrimSpace(string(strValue)), " ")[0]
- }
-
- // Bond transmit policy.
- strValue, err = ioutil.ReadFile(filepath.Join(bondPath, "xmit_hash_policy"))
- if err == nil {
- bonding.TransmitPolicy = strings.Split(strings.TrimSpace(string(strValue)), " ")[0]
- }
-
- // Up delay.
- uintValue, err := readUint(filepath.Join(bondPath, "updelay"))
- if err == nil {
- bonding.UpDelay = uintValue
- }
-
- // Down delay.
- uintValue, err = readUint(filepath.Join(bondPath, "downdelay"))
- if err == nil {
- bonding.DownDelay = uintValue
- }
-
- // MII frequency.
- uintValue, err = readUint(filepath.Join(bondPath, "miimon"))
- if err == nil {
- bonding.MIIFrequency = uintValue
- }
-
- // MII state.
- strValue, err = ioutil.ReadFile(filepath.Join(bondPath, "mii_status"))
- if err == nil {
- bonding.MIIState = strings.TrimSpace(string(strValue))
- }
-
- // Lower devices.
- strValue, err = ioutil.ReadFile(filepath.Join(bondPath, "slaves"))
- if err == nil {
- bonding.LowerDevices = strings.Split(strings.TrimSpace(string(strValue)), " ")
- }
-
- network.Bond = &bonding
- }
-
- // Populate bridge details.
- bridgePath := fmt.Sprintf("/sys/class/net/%s/bridge", netIf.Name)
- if shared.PathExists(bridgePath) {
- bridge := api.NetworkStateBridge{}
-
- // Bridge ID.
- strValue, err := ioutil.ReadFile(filepath.Join(bridgePath, "bridge_id"))
- if err == nil {
- bridge.ID = strings.TrimSpace(string(strValue))
- }
-
- // Bridge STP.
- uintValue, err := readUint(filepath.Join(bridgePath, "stp_state"))
- if err == nil {
- bridge.STP = uintValue == 1
- }
-
- // Bridge forward delay.
- uintValue, err = readUint(filepath.Join(bridgePath, "forward_delay"))
- if err == nil {
- bridge.ForwardDelay = uintValue
- }
-
- // Bridge default VLAN.
- uintValue, err = readUint(filepath.Join(bridgePath, "default_pvid"))
- if err == nil {
- bridge.VLANDefault = uintValue
- }
-
- // Bridge VLAN filtering.
- uintValue, err = readUint(filepath.Join(bridgePath, "vlan_filtering"))
- if err == nil {
- bridge.VLANFiltering = uintValue == 1
- }
-
- // Upper devices.
- bridgeIfPath := fmt.Sprintf("/sys/class/net/%s/brif", netIf.Name)
- if shared.PathExists(bridgeIfPath) {
- entries, err := ioutil.ReadDir(bridgeIfPath)
- if err == nil {
- bridge.UpperDevices = []string{}
- for _, entry := range entries {
- bridge.UpperDevices = append(bridge.UpperDevices, entry.Name())
- }
- }
- }
-
- network.Bridge = &bridge
- }
-
- // Get counters.
- network.Counters = shared.NetworkGetCounters(netIf.Name)
- return network
-}
diff --git a/lxd/resources/network.go b/lxd/resources/network.go
index 3ab64405be..034e5b8190 100644
--- a/lxd/resources/network.go
+++ b/lxd/resources/network.go
@@ -1,8 +1,12 @@
package resources
import (
+ "fmt"
"io/ioutil"
+ "net"
+ "os"
"path/filepath"
+ "strconv"
"strings"
"github.com/jaypipes/pcidb"
@@ -428,3 +432,247 @@ func GetNetwork() (*api.ResourcesNetwork, error) {
return &network, nil
}
+
+// GetNetworkState returns the OS configuration for the network interface.
+func GetNetworkState(name string) (*api.NetworkState, error) {
+ // Get some information
+ netIf, err := net.InterfaceByName(name)
+ if err != nil {
+ return nil, fmt.Errorf("Network interface %q not found", name)
+ }
+
+ netState := "down"
+ netType := "unknown"
+
+ if netIf.Flags&net.FlagBroadcast > 0 {
+ netType = "broadcast"
+ }
+
+ if netIf.Flags&net.FlagPointToPoint > 0 {
+ netType = "point-to-point"
+ }
+
+ if netIf.Flags&net.FlagLoopback > 0 {
+ netType = "loopback"
+ }
+
+ if netIf.Flags&net.FlagUp > 0 {
+ netState = "up"
+ }
+
+ network := api.NetworkState{
+ Addresses: []api.NetworkStateAddress{},
+ Counters: api.NetworkStateCounters{},
+ Hwaddr: netIf.HardwareAddr.String(),
+ Mtu: netIf.MTU,
+ State: netState,
+ Type: netType,
+ }
+
+ // Populate address information.
+ addrs, err := netIf.Addrs()
+ if err == nil {
+ for _, addr := range addrs {
+ fields := strings.SplitN(addr.String(), "/", 2)
+ if len(fields) != 2 {
+ continue
+ }
+
+ family := "inet"
+ if strings.Contains(fields[0], ":") {
+ family = "inet6"
+ }
+
+ scope := "global"
+ if strings.HasPrefix(fields[0], "127") {
+ scope = "local"
+ }
+
+ if fields[0] == "::1" {
+ scope = "local"
+ }
+
+ if strings.HasPrefix(fields[0], "169.254") {
+ scope = "link"
+ }
+
+ if strings.HasPrefix(fields[0], "fe80:") {
+ scope = "link"
+ }
+
+ address := api.NetworkStateAddress{}
+ address.Family = family
+ address.Address = fields[0]
+ address.Netmask = fields[1]
+ address.Scope = scope
+
+ network.Addresses = append(network.Addresses, address)
+ }
+ }
+
+ // Populate bond details.
+ bondPath := fmt.Sprintf("/sys/class/net/%s/bonding", name)
+ if sysfsExists(bondPath) {
+ bonding := api.NetworkStateBond{}
+
+ // Bond mode.
+ strValue, err := ioutil.ReadFile(filepath.Join(bondPath, "mode"))
+ if err == nil {
+ bonding.Mode = strings.Split(strings.TrimSpace(string(strValue)), " ")[0]
+ }
+
+ // Bond transmit policy.
+ strValue, err = ioutil.ReadFile(filepath.Join(bondPath, "xmit_hash_policy"))
+ if err == nil {
+ bonding.TransmitPolicy = strings.Split(strings.TrimSpace(string(strValue)), " ")[0]
+ }
+
+ // Up delay.
+ uintValue, err := readUint(filepath.Join(bondPath, "updelay"))
+ if err == nil {
+ bonding.UpDelay = uintValue
+ }
+
+ // Down delay.
+ uintValue, err = readUint(filepath.Join(bondPath, "downdelay"))
+ if err == nil {
+ bonding.DownDelay = uintValue
+ }
+
+ // MII frequency.
+ uintValue, err = readUint(filepath.Join(bondPath, "miimon"))
+ if err == nil {
+ bonding.MIIFrequency = uintValue
+ }
+
+ // MII state.
+ strValue, err = ioutil.ReadFile(filepath.Join(bondPath, "mii_status"))
+ if err == nil {
+ bonding.MIIState = strings.TrimSpace(string(strValue))
+ }
+
+ // Lower devices.
+ strValue, err = ioutil.ReadFile(filepath.Join(bondPath, "slaves"))
+ if err == nil {
+ bonding.LowerDevices = strings.Split(strings.TrimSpace(string(strValue)), " ")
+ }
+
+ network.Bond = &bonding
+ }
+
+ // Populate bridge details.
+ bridgePath := fmt.Sprintf("/sys/class/net/%s/bridge", name)
+ if sysfsExists(bridgePath) {
+ bridge := api.NetworkStateBridge{}
+
+ // Bridge ID.
+ strValue, err := ioutil.ReadFile(filepath.Join(bridgePath, "bridge_id"))
+ if err == nil {
+ bridge.ID = strings.TrimSpace(string(strValue))
+ }
+
+ // Bridge STP.
+ uintValue, err := readUint(filepath.Join(bridgePath, "stp_state"))
+ if err == nil {
+ bridge.STP = uintValue == 1
+ }
+
+ // Bridge forward delay.
+ uintValue, err = readUint(filepath.Join(bridgePath, "forward_delay"))
+ if err == nil {
+ bridge.ForwardDelay = uintValue
+ }
+
+ // Bridge default VLAN.
+ uintValue, err = readUint(filepath.Join(bridgePath, "default_pvid"))
+ if err == nil {
+ bridge.VLANDefault = uintValue
+ }
+
+ // Bridge VLAN filtering.
+ uintValue, err = readUint(filepath.Join(bridgePath, "vlan_filtering"))
+ if err == nil {
+ bridge.VLANFiltering = uintValue == 1
+ }
+
+ // Upper devices.
+ bridgeIfPath := fmt.Sprintf("/sys/class/net/%s/brif", name)
+ if sysfsExists(bridgeIfPath) {
+ entries, err := ioutil.ReadDir(bridgeIfPath)
+ if err == nil {
+ bridge.UpperDevices = []string{}
+ for _, entry := range entries {
+ bridge.UpperDevices = append(bridge.UpperDevices, entry.Name())
+ }
+ }
+ }
+
+ network.Bridge = &bridge
+ }
+
+ // Get counters.
+ counters, err := GetNetworkCounters(name)
+ if err != nil {
+ return nil, err
+ }
+
+ network.Counters = *counters
+
+ return &network, nil
+}
+
+// GetNetworkCounters returns the current packet counters for the network interface.
+func GetNetworkCounters(name string) (*api.NetworkStateCounters, error) {
+ counters := api.NetworkStateCounters{}
+
+ // Get counters
+ content, err := ioutil.ReadFile("/proc/net/dev")
+ if err != nil {
+ if os.IsNotExist(err) {
+ return &counters, nil
+ }
+
+ return nil, err
+ }
+
+ for _, line := range strings.Split(string(content), "\n") {
+ fields := strings.Fields(line)
+
+ if len(fields) != 17 {
+ continue
+ }
+
+ intName := strings.TrimSuffix(fields[0], ":")
+ if intName != name {
+ continue
+ }
+
+ rxBytes, err := strconv.ParseInt(fields[1], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ rxPackets, err := strconv.ParseInt(fields[2], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ txBytes, err := strconv.ParseInt(fields[9], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ txPackets, err := strconv.ParseInt(fields[10], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ counters.BytesSent = txBytes
+ counters.BytesReceived = rxBytes
+ counters.PacketsSent = txPackets
+ counters.PacketsReceived = rxPackets
+ break
+ }
+
+ return &counters, nil
+}
diff --git a/shared/network.go b/shared/network.go
index 3a49052850..c1ab480de9 100644
--- a/shared/network.go
+++ b/shared/network.go
@@ -9,14 +9,11 @@ import (
"io/ioutil"
"net"
"net/http"
- "strconv"
- "strings"
"sync"
"time"
"github.com/gorilla/websocket"
- "github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
)
@@ -501,51 +498,3 @@ func AllocatePort() (int, error) {
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}
-
-func NetworkGetCounters(ifName string) api.NetworkStateCounters {
- counters := api.NetworkStateCounters{}
- // Get counters
- content, err := ioutil.ReadFile("/proc/net/dev")
- if err == nil {
- for _, line := range strings.Split(string(content), "\n") {
- fields := strings.Fields(line)
-
- if len(fields) != 17 {
- continue
- }
-
- intName := strings.TrimSuffix(fields[0], ":")
- if intName != ifName {
- continue
- }
-
- rxBytes, err := strconv.ParseInt(fields[1], 10, 64)
- if err != nil {
- continue
- }
-
- rxPackets, err := strconv.ParseInt(fields[2], 10, 64)
- if err != nil {
- continue
- }
-
- txBytes, err := strconv.ParseInt(fields[9], 10, 64)
- if err != nil {
- continue
- }
-
- txPackets, err := strconv.ParseInt(fields[10], 10, 64)
- if err != nil {
- continue
- }
-
- counters.BytesSent = txBytes
- counters.BytesReceived = rxBytes
- counters.PacketsSent = txPackets
- counters.PacketsReceived = rxPackets
- break
- }
- }
-
- return counters
-}
More information about the lxc-devel
mailing list