From c5661d890f83f2e118f89867a0edf73dc1da282e Mon Sep 17 00:00:00 2001 From: Flavio Castelli Date: Mon, 4 Jul 2016 19:03:45 +0200 Subject: Discover IP address of the network cards attached to a LAN When a network card is attached to a LAN the `domain.ListAllInterfaceAddresses` API cannot be used to get the IP address associated with the interfaces. The only solution to this problem is to use the [Qemu guest agent](http://wiki.libvirt.org/page/Qemu_guest_agent) to fetch this information. This PR will take advantage of the qemu guest ageint (when installed inside of the domain) to workaround the limitations of the `domain.ListAllInterfaceAddresses`. In theory this PR could also allow to relax the required version of libvirt. Signed-off-by: Flavio Castelli --- libvirt/qemu_agent.go | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 libvirt/qemu_agent.go (limited to 'libvirt/qemu_agent.go') diff --git a/libvirt/qemu_agent.go b/libvirt/qemu_agent.go new file mode 100644 index 00000000..10bf45cc --- /dev/null +++ b/libvirt/qemu_agent.go @@ -0,0 +1,90 @@ +package libvirt + +import ( + "encoding/json" + "log" + "strings" + + libvirt "github.com/dmacvicar/libvirt-go" +) + +type QemuAgentInterfacesResponse struct { + Interfaces []QemuAgentInterface `json:"return"` +} + +type QemuAgentInterface struct { + Name string `json:"name"` + Hwaddr string `json:"hardware-address"` + IpAddresses []struct { + Type string `json:"ip-address-type"` + Address string `json:"ip-address"` + Prefix uint `json:"prefix"` + } `json:"ip-addresses"` +} + +// Retrieve all the interfaces attached to a domain and their addresses. Only +// the interfaces with at least an IP address are returned. +// When wait4ipv4 is turned on the code will not report interfaces that don't +// have a ipv4 address set. This is useful when a domain gets the ipv6 address +// before the ipv4 one. +func getDomainInterfacesViaQemuAgent(domain *libvirt.VirDomain, wait4ipv4 bool) []libvirt.VirDomainInterface { + log.Print("[DEBUG] get network interfaces using qemu agent") + + var interfaces []libvirt.VirDomainInterface + + result := domain.QemuAgentCommand( + "{\"execute\":\"guest-network-get-interfaces\"}", + libvirt.VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT, + 0) + + log.Printf("[DEBUG] qemu-agent response: %s", result) + + response := QemuAgentInterfacesResponse{} + if err := json.Unmarshal([]byte(result), &response); err != nil { + log.Printf("[DEBUG] Error converting Qemu agent response about domain interfaces: %s", err) + log.Printf("[DEBUG] Original message: %s", response) + log.Print("[DEBUG] Returning an empty list of interfaces") + return interfaces + } + log.Printf("[DEBUG] Parsed response %+v", response) + + for _, iface := range response.Interfaces { + if iface.Name == "lo" { + // ignore loopback interface + continue + } + + libVirtIface := libvirt.VirDomainInterface{} + libVirtIface.Name = iface.Name + libVirtIface.Hwaddr = iface.Hwaddr + + ipv4Assigned := false + for _, addr := range iface.IpAddresses { + if addr.Address == "" { + // ignore interfaces without an address (eg. waiting for dhcp lease) + continue + } + + libVirtAddr := libvirt.VirDomainIPAddress{} + libVirtAddr.Addr = addr.Address + libVirtAddr.Prefix = addr.Prefix + switch strings.ToLower(addr.Type) { + case "ipv4": + libVirtAddr.Type = libvirt.VIR_IP_ADDR_TYPE_IPV4 + ipv4Assigned = true + case "ipv6": + libVirtAddr.Type = libvirt.VIR_IP_ADDR_TYPE_IPV6 + default: + log.Printf("[ERROR] Cannot handle unknown address type %s", addr.Type) + } + libVirtIface.Addrs = append(libVirtIface.Addrs, libVirtAddr) + } + if len(libVirtIface.Addrs) > 0 && (ipv4Assigned || !wait4ipv4) { + interfaces = append(interfaces, libVirtIface) + } + } + + log.Printf("[DEBUG] Interfaces obtained via qemu Agent: %+v", interfaces) + + return interfaces +} -- cgit v1.2.3