The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7968
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) ===
From 9a0cf626779c141f59b358963cede5632c988563 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 1 Oct 2020 17:07:39 +0100 Subject: [PATCH 1/3] lxd/network/network/utils: Adds GetNeighbourV6Addresses function Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/network_utils.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lxd/network/network_utils.go b/lxd/network/network_utils.go index c195228a3d..a4ead17f6f 100644 --- a/lxd/network/network_utils.go +++ b/lxd/network/network_utils.go @@ -805,6 +805,34 @@ func GetHostDevice(parent string, vlan string) string { return defaultVlan } +// GetNeighbourV6Addresses returns the IPv6 addresses in the neighbour cache for a particular interface and MAC. +func GetNeighbourV6Addresses(interfaceName string, hwaddr string) ([]net.IP, error) { + addresses := []net.IP{} + + // Look for neighbour entries for IPv6. + out, err := shared.RunCommand("ip", "-6", "neigh", "show", "dev", interfaceName) + if err == nil { + for _, line := range strings.Split(out, "\n") { + // Split fields and early validation. + fields := strings.Fields(line) + if len(fields) != 4 { + continue + } + + if fields[2] != hwaddr { + continue + } + + ip := net.ParseIP(fields[0]) + if ip != nil { + addresses = append(addresses, ip) + } + } + } + + return addresses, nil +} + // GetLeaseAddresses returns the lease addresses for a network and hwaddr. func GetLeaseAddresses(s *state.State, networkName string, hwaddr string) ([]api.InstanceStateNetworkAddress, error) { addresses := []api.InstanceStateNetworkAddress{} From 6ba197ad54e2dff9416ff698cdbbc2c6e836aa1c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 1 Oct 2020 17:46:42 +0100 Subject: [PATCH 2/3] lxd/network/network/utils: Updates GetLeaseAddresses to return only net.IP list - Removes IPv6 neighbour look as was out of scope for this function's name. - Returns []net.IP rather than []api.InstanceStateNetworkAddress. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/network_utils.go | 79 ++++-------------------------------- 1 file changed, 9 insertions(+), 70 deletions(-) diff --git a/lxd/network/network_utils.go b/lxd/network/network_utils.go index a4ead17f6f..96d57465ed 100644 --- a/lxd/network/network_utils.go +++ b/lxd/network/network_utils.go @@ -834,48 +834,10 @@ func GetNeighbourV6Addresses(interfaceName string, hwaddr string) ([]net.IP, err } // GetLeaseAddresses returns the lease addresses for a network and hwaddr. -func GetLeaseAddresses(s *state.State, networkName string, hwaddr string) ([]api.InstanceStateNetworkAddress, error) { - addresses := []api.InstanceStateNetworkAddress{} - - // Look for neighborhood entries for IPv6. - out, err := shared.RunCommand("ip", "-6", "neigh", "show", "dev", networkName) - if err == nil { - for _, line := range strings.Split(out, "\n") { - // Split fields and early validation. - fields := strings.Fields(line) - if len(fields) != 4 { - continue - } - - if fields[2] != hwaddr { - continue - } - - // Prepare the entry. - addr := api.InstanceStateNetworkAddress{} - addr.Address = fields[0] - addr.Family = "inet6" - - if strings.HasPrefix(fields[0], "fe80::") { - addr.Scope = "link" - } else { - addr.Scope = "global" - } - - addresses = append(addresses, addr) - } - } - - // Look for DHCP leases. +func GetLeaseAddresses(networkName string, hwaddr string) ([]net.IP, error) { leaseFile := shared.VarPath("networks", networkName, "dnsmasq.leases") if !shared.PathExists(leaseFile) { - return addresses, nil - } - - // Pass project.Default here, as currently dnsmasq (bridged) networks do not support projects. - dbInfo, err := LoadByName(s, project.Default, networkName) - if err != nil { - return nil, err + return nil, fmt.Errorf("Leases file not found for network %q", networkName) } content, err := ioutil.ReadFile(leaseFile) @@ -883,13 +845,15 @@ func GetLeaseAddresses(s *state.State, networkName string, hwaddr string) ([]api return nil, err } + addresses := []net.IP{} + for _, lease := range strings.Split(string(content), "\n") { fields := strings.Fields(lease) if len(fields) < 5 { continue } - // Parse the MAC + // Parse the MAC. mac := GetMACSlice(fields[1]) macStr := strings.Join(mac, ":") @@ -901,36 +865,11 @@ func GetLeaseAddresses(s *state.State, networkName string, hwaddr string) ([]api continue } - // Parse the IP - addr := api.InstanceStateNetworkAddress{ - Address: fields[2], - Scope: "global", - } - - ip := net.ParseIP(addr.Address) - if ip == nil { - continue - } - - if ip.To4() != nil { - addr.Family = "inet" - - _, subnet, _ := net.ParseCIDR(dbInfo.Config()["ipv4.address"]) - if subnet != nil { - mask, _ := subnet.Mask.Size() - addr.Netmask = fmt.Sprintf("%d", mask) - } - } else { - addr.Family = "inet6" - - _, subnet, _ := net.ParseCIDR(dbInfo.Config()["ipv6.address"]) - if subnet != nil { - mask, _ := subnet.Mask.Size() - addr.Netmask = fmt.Sprintf("%d", mask) - } + // Parse the IP. + ip := net.ParseIP(fields[2]) + if ip != nil { + addresses = append(addresses, ip) } - - addresses = append(addresses, addr) } return addresses, nil From 5d2b5543d6a62aa4d77e4a3a8fedc59765045fc6 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 1 Oct 2020 17:21:54 +0100 Subject: [PATCH 3/3] lxd/device/nic/bridged: Updates State() to return partial data - Only tries to parse dnsmasq leases file if parent network is managed. - If parent network is not managed, no longer treat this as complete failure. - Try and find IPv6 addresses from IP neighbour cache using network.GetNeighbourV6Addresses. - Load interface MTU using NIC's `host_name` rather than parent interface (should be the same but more consistent with how OVN NIC does it). - Also means that if the NIC's host veth interface is missing, then this call will not return any results. - If interface is available, will return interface stats even with no IPs found. - Guess link-local address netmask size based on IP family. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/nic_bridged.go | 77 ++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go index f8a255e4d8..47b0d67379 100644 --- a/lxd/device/nic_bridged.go +++ b/lxd/device/nic_bridged.go @@ -1091,24 +1091,81 @@ func (d *nicBridged) State() (*api.InstanceStateNetwork, error) { // Populate device config with volatile fields if needed. networkVethFillFromVolatile(d.config, v) - if d.config["hwaddr"] == "" { - return nil, nil + ips := []net.IP{} + + // Check if parent is managed network and load config. + // Pass project.Default here, as currently dnsmasq (bridged) networks do not support projects. + n, err := network.LoadByName(d.state, project.Default, d.config["parent"]) + if err == nil && d.config["hwaddr"] != "" { + // Parse the leases file if parent network is managed. + leaseIPs, err := network.GetLeaseAddresses(n.Name(), d.config["hwaddr"]) + if err == nil { + for _, leaseIP := range leaseIPs { + ips = append(ips, leaseIP) + } + } } - // Parse the leases file. - addresses, err := network.GetLeaseAddresses(d.state, d.config["parent"], d.config["hwaddr"]) - if err != nil { - return nil, err + // Get IPv6 addresses from IP neighbour cache if present. + neighIPs, err := network.GetNeighbourV6Addresses(d.config["parent"], d.config["hwaddr"]) + if err == nil { + for _, neighIP := range neighIPs { + ips = append(ips, neighIP) + } + } + + // Extract subnet sizes from bridge addresses if available. + var v4mask string + var v6mask string + + if n != nil { + netConfig := n.Config() + _, v4subnet, _ := net.ParseCIDR(netConfig["ipv4.address"]) + _, v6subnet, _ := net.ParseCIDR(netConfig["ipv6.address"]) + + if v4subnet != nil { + mask, _ := v4subnet.Mask.Size() + v4mask = fmt.Sprintf("%d", mask) + } + + if v6subnet != nil { + mask, _ := v6subnet.Mask.Size() + v6mask = fmt.Sprintf("%d", mask) + } } - if len(addresses) == 0 { - return nil, nil + // Convert IPs to InstanceStateNetworkAddresses. + addresses := []api.InstanceStateNetworkAddress{} + for _, ip := range ips { + addr := api.InstanceStateNetworkAddress{} + addr.Address = ip.String() + addr.Family = "inet" + addr.Netmask = v4mask + + if ip.To4() == nil { + addr.Family = "inet6" + addr.Netmask = v6mask + } + + if ip.IsLinkLocalUnicast() { + addr.Scope = "link" + + if addr.Family == "inet6" { + addr.Netmask = "64" // Link-local IPv6 addresses are /64. + } else { + addr.Netmask = "16" // Local-local IPv4 addresses are /16. + } + } else { + addr.Scope = "global" + } + + addresses = append(addresses, addr) } // Get MTU. - iface, err := net.InterfaceByName(d.config["parent"]) + iface, err := net.InterfaceByName(d.config["host_name"]) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "Failed getting host interface state") } // Retrieve the host counters, as we report the values from the instance's point of view,
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel