The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/8183
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Will be useful for external consumption by MAAS. Also improves error handling slightly. Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
From 52e73d97455e075b5791e1448fbe0c9115ed1cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@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 <stgra...@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 -}
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel