© W. David Ashley 2019
W. David AshleyFoundations of Libvirt Development https://doi.org/10.1007/978-1-4842-4862-1_7

7. Network Interfaces

W. David Ashley1 
(1)
Austin, TX, USA
 

You can configure network interfaces on physical hosts with the methods in the virInterface class . This is useful for setting up the host to share one physical interface between the multiple guest domains that you want connected directly to the network (briefly, you can enslave a physical interface to the bridge and then create a tap device for each VM that is sharing the interface), as well as for general host network interface management. In addition to configuring the physical hardware, you can use the methods to configure bridges, bonded interfaces, and VLAN interfaces.

The virInterface class is not used to configure virtual networks (which are used to conceal the guest domain’s interface behind a NAT); virtual networks are instead configured using the virNetwork class described in Chapter 6.

Each host interface is represented by an instance of the virInterface class, and each of these instances has a single unique identifier: name.

The name method returns a string unique among all interfaces (active or inactive) on a host. This is the same string used by the operating system to identify the interface (e.g., eth0 or br1).

Each interface object also has a second, nonunique index that can be duplicated in other interfaces on the same host.

The MACString method returns an ASCII string representation of the MAC address of this interface. Since multiple interfaces can share the same MAC address (for example, in the case of VLANs), this is not a unique identifier. However, it can still be used to search for an interface.

All interfaces configured with libvirt should be considered as persistent since libvirt is actually changing the host’s own persistent configuration data (usually contained in files somewhere under /etc) and not the interface itself.

When a new interface is defined (using the interfaceDefineXML method) or the configuration of an existing interface is changed (again, with the interfaceDefineXML method), this configuration will be stored on the host. The live configuration of the interface itself will not be changed until the interface is restarted manually or the host is rebooted.

This chapter covers the management of physical network interfaces using the libvirt virInterface class.

XML Interface Description Format

The current Relax-NG definition of the XML that is produced and accepted by interfaceDefineXML and XMLDesc can be found in the file data/xml/interface.rng of the netcf package, available at http://git.fedorahosted.org/git/netcf.git?p=netcf.git;a=tree . Listings 7-1 through 7-4 provide some examples of common interface configurations.
<interface type="ethernet" name="eth0">
  <start mode="onboot"/>
  <mac address='aa:bb:cc:dd:ee:ff'/>
  <protocol family="ipv4">
    <dhcp/>
  </protocol>
</interface>
Listing 7-1

XML Definition of an Ethernet Interface Using DHCP

<interface type="ethernet" name="eth0">
  <start mode="onboot"/>
  <mac address='aa:bb:cc:dd:ee:ff'/>
  <protocol family="ipv4">
    <ip address="192.168.0.5" prefix="24"/>
    <route gateway="192.168.0.1"/>
  </protocol>
</interface>
Listing 7-2

XML Definition of an Ethernet Interface with Static IP

<interface type="bridge" name="br0">
  <start mode="onboot"/>
  <mtu size="1500"/>
  <protocol family="ipv4">
    <dhcp/>
  </protocol>
  <bridge stp="off" delay="0.01">
    <interface type="ethernet" name="eth0">
      <mac address="ab:bb:cc:dd:ee:ff"/>
    </interface>
    <interface type="ethernet" name="eth1"/>
  </bridge>
</interface>
Listing 7-3

XML Definition of a Bridge Device with eth0 and eth1 Attached

<interface type="vlan" name="eth0.42">
  <start mode="onboot"/>
  <protocol family="ipv4">
    <dhcp peerdns="no"/>
  </protocol>
  <vlan tag="42">
    <interface name="eth0"/>
  </vlan>
</interface>
Listing 7-4

XML Definition of a VLAN Interface Associated with eth0

Retrieving Information About Interfaces

You can retrieve information about network interfaces using several methods. The following examples show how to obtain that information.

Enumerating Interfaces

Once you have a connection to a host, you can determine the number of interfaces on the host with the numOfInterfaces and numOfDefinedInterfaces methods . You can obtain a list of those interfaces’ names with the listInterfaces method and the listDefinedInterfaces method (“defined” interfaces are those that have been defined but are currently inactive). The list methods return a Python list. All four functions return None if an error is encountered.

Listing 7-5 shows how to get a list of the active network interfaces from a domain. Note that error handling has been omitted for clarity.
# Example-5.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
ifaceNames = conn.listInterfaces()
print("Active host interfaces:")
for ifaceName in ifaceNames:
    print('  '+ifaceName)
conn.close()
exit(0)
Listing 7-5

Getting a List of Active (“Up”) Interfaces on a Host

Listing 7-6 shows how to get a list of the inactive domains from a domain.
# Example-6.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
ifaceNames = conn.listDefinedInterfaces()
print("Inactive host interfaces:")
for ifaceName in ifaceNames:
    print('  '+ifaceName)
conn.close()
exit(0)
Listing 7-6

Getting a List of Inactive (“Down”) Interfaces on a Host

Obtaining a virInterface Instance for an Interface

Many operations require that you have an instance of virInterface , but you may have only the name or MAC address of the interface. You can use interfaceLookupByName and interfaceLookupByMACString to get the virInterface instance in these cases.

Listing 7-7 shows how to obtain a virInterface for a given domain interface name. Note that error handling has been omitted for clarity.

# Example-7.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
iface = conn.interfaceLookupByName('eth0')
print("The interface name is: "+iface.name())
conn.close()
exit(0)
Listing 7-7

Fetching the virInterface Instance for a Given Interface Name

Listing 7-8 shows how to obtain a virInterface for a given domain MAC address. Note that error handling has been omitted for clarity.
# Example-8.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
iface = conn.interfaceLookupByMACString('00:01:02:03:04:05')
print("The interface name is: "+iface.name())
conn.close()
exit(0)
Listing 7-8

Fetching the virInterface Instance for a Given Interface MAC Address

Retrieving Detailed Interface Information

You may also find yourself with a virInterface instance and need the name or MAC address of the interface or want to examine the full interface configuration. The name, MACString, and XMLDesc methods provide this capability.

Listing 7-9 shows how to obtain detailed information about a domain interface.
# Example-9.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
iface = conn.interfaceLookupByName('eth0')
print("The interface name is: "+iface.name())
print("The interface mac string is: "+iface.MACString())
conn.close()
exit(0)
Listing 7-9

Fetching the name and mac Addresses from an Interface Object

Listing 7-10 shows how to obtain configuration information about a domain interface.
# Example-10.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
iface = conn.interfaceLookupByName('eth0')
print("The interface XML description is: "+iface.XMLDesc(0))
conn.close()
exit(0)
Listing 7-10

Fetching the XML Configuration String from an Interface Object

Retrieving Interface Network Addresses

You may find yourself with a virDomain instance and need the IP addresses of one or more guest domain interfaces. The interfaceAddresses method provides this capability.

Listing 7-11 shows how to obtain the IP addresses of a given domain interface.
# Example-14.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
domainName = 'CentOS7'
dom = conn.lookupByName(domainName)
if dom == None:
    print('Failed to get the domain object', file=sys.stderr)
ifaces =
  dom.interfaceAddresses(libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT,
                         0)
print("The interface IP addresses:")
for (name, val) in ifaces.iteritems():
    if val['addrs']:
        for ipaddr in val['addrs']:
            if ipaddr['type'] == libvirt.VIR_IP_ADDR_TYPE_IPV4:
                print(ipaddr['addr'] + " VIR_IP_ADDR_TYPE_IPV4")
            elif ipaddr['type'] == libvirt.VIR_IP_ADDR_TYPE_IPV6:
                print(ipaddr['addr'] + " VIR_IP_ADDR_TYPE_IPV6")
conn.close()
exit(0)
Listing 7-11

Fetching the IP Addresses of All the Guest Domain Network Interfaces

Managing Interface Configuration Files

In libvirt, defining an interface means creating or changing the configuration, and undefining means deleting that configuration from the system. Newcomers may sometimes confuse these two operations with Create/Delete (which actually are used to activate and deactivate an existing interface; see the section called “Interface Lifecycle Management” later in this chapter).

Defining an Interface Configuration

The interfaceDefineXML method is used for both adding new interface configurations and modifying existing configurations. It either adds a new interface (with all information, including the interface name, given in the XML data) or modifies the configuration of an existing interface. The newly defined interface will be inactive until separate action is taken to make the new configuration take effect (for example, rebooting the host or calling Create, as described in the section “Interface Lifecycle Management”).

If the interface is successfully added/modified in the host's configuration, interfaceDefineXML returns a virInterface instance. This can be used as a handle to perform further actions on the new interface, for example, making it active with create.

Currently, the flags parameter should always be 0.

Listing 7-12 shows how to define a new interface to a domain.
# Example-11.py
from __future__ import print_function
import sys
import libvirt
xml = """"
<interface type="ethernet" name="eth0">
  <start mode="onboot"/>
  <mac address='aa:bb:cc:dd:ee:ff'/>
  <protocol family="ipv4">
    <ip address="192.168.0.5" prefix="24"/>
    <route gateway="192.168.0.1"/>
  </protocol>
</interface>"""
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to create the interface eth0',
          file=sys.stderr)
    exit(1)
# create/modify a network interface
iface = conn.interfaceDefineXML(xml, 0)
# activate the interface
iface.create(0)
print("The interface name is: "+iface.name())
conn.close()
exit(0)
Listing 7-12

Defining a New Interface

The undefine method completely and permanently removes the configuration for the given interface from the host’s configuration files. If you want to re-create this configuration in the future, you should invoke the XMLDesc method and save the string prior to the undefine method. Listing 7-13 shows how to undefine an interface from a domain.
# Example-12.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
iface = conn.interfaceLookupByName('br0')
# get the xml prior to undefining the interface
xml = iface.XMLDesc(0)
# now undefine the interface
iface.undefine()
# the interface is now undefined and the iface variable
#     is no longer be usable
conn.close()
exit(0)
Listing 7-13

Undefining the br0 Interface After Saving Its XML Data

Using changeRollback

This method rolls back all defined interface definitions since the last call to the changeCommit method.

Listing 7-14 shows how to change the rollback for a domain. Note that an error will be thrown if no interface definitions are pending.
# Example-30.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
iface = conn.changeRollback()
conn.close()
exit(0)
Listing 7-14

Using changeRollback

Using changeBegin

The changeBegin method creates a restore point to which one can return later by calling the changeRollback method. This function should be called before any transaction with the interface configuration. Once it is known that a new configuration works, it can be committed via the changeCommit method, which frees the restore point.

Listing 7-15 shows how to create a restore point for a domain. If the changeBegin method is called when a transaction is already opened, an error will be thrown.
# Example-31.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
iface = conn.changeBegin()
conn.close()
exit(0)
Listing 7-15

Using changeBegin

Using changeCommit

This method commits the changes made to interfaces and frees the restore point created by the changeBegin method.

Listing 7-16 shows how to commit a change to a domain.
# Example-32.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
conn.changeCommit()
conn.close()
exit(0)
Listing 7-16

Using changeCommit

The changeRollback method can be used to roll back an uncommited change.

Interface Lifecycle Management

In libvirt parlance, creating an interface means making it active, or “bringing it up,” and deleting an interface means making it inactive, or “bringing it down.” On hosts that are using the netcf back end for interface configuration, such as Fedora and Red Hat Enterprise Linux, this is the same as calling the system shell scripts ifup and ifdown for the interface.

Activating an Interface

The create method makes the given inactive interface active (“up”). On success, it returns 0. If there is any problem making the interface active, -1 is returned. Listing 7-12 showed a typical usage of this method.

Deactivating an Interface

The destroy method makes the given interface inactive (“down”). On success, it returns 0. If there is any problem making the interface active, -1 is returned.

Listing 7-17 shows how to temporarily bring down an interface in a domain.
# Example-12.py
from __future__ import print_function
import sys
import libvirt
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system',
          file=sys.stderr)
    exit(1)
iface = conn.interfaceLookupByName('br0')
# get the xml prior to undefining the interface
xml = iface.XMLDesc(0)
# now undefine the interface
iface.undefine()
# the interface is now undefined and the iface variable
#     is no longer be usable
conn.close()
exit(0)
Listing 7-17

Temporarily Bring Down eth2, Then Bring It Back Up

Summary

This chapter showed how to manipulate interfaces belonging to a domain. There are methods for creating interfaces, deleting them, obtaining information, and manipulating commits to domain interfaces.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.69.151