[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