Add support for SR-IOV NICs to VMs
This commit is contained in:
@ -373,23 +373,28 @@ def getDomainNetworks(parsed_xml, stats_data):
|
||||
net_type = device.attrib.get('type')
|
||||
except Exception:
|
||||
net_type = None
|
||||
|
||||
try:
|
||||
net_mac = device.mac.attrib.get('address')
|
||||
except Exception:
|
||||
net_mac = None
|
||||
|
||||
try:
|
||||
net_bridge = device.source.attrib.get(net_type)
|
||||
except Exception:
|
||||
net_bridge = None
|
||||
|
||||
try:
|
||||
net_model = device.model.attrib.get('type')
|
||||
except Exception:
|
||||
net_model = None
|
||||
|
||||
try:
|
||||
net_stats_list = [x for x in stats_data.get('net_stats', []) if x.get('bridge') == net_bridge]
|
||||
net_stats = net_stats_list[0]
|
||||
except Exception:
|
||||
net_stats = {}
|
||||
|
||||
net_rd_bytes = net_stats.get('rd_bytes', 0)
|
||||
net_rd_packets = net_stats.get('rd_packets', 0)
|
||||
net_rd_errors = net_stats.get('rd_errors', 0)
|
||||
@ -398,10 +403,16 @@ def getDomainNetworks(parsed_xml, stats_data):
|
||||
net_wr_packets = net_stats.get('wr_packets', 0)
|
||||
net_wr_errors = net_stats.get('wr_errors', 0)
|
||||
net_wr_drops = net_stats.get('wr_drops', 0)
|
||||
if net_type in ['direct', 'hostdev']:
|
||||
net_vni = device.source.attrib.get('dev')
|
||||
|
||||
if net_type == 'direct':
|
||||
net_vni = 'macvtap:' + device.source.attrib.get('dev')
|
||||
net_bridge = device.source.attrib.get('dev')
|
||||
elif net_type == 'hostdev':
|
||||
net_vni = 'hostdev:' + str(device.sriov_device)
|
||||
net_bridge = str(device.sriov_device)
|
||||
else:
|
||||
net_vni = re_match(r'[vm]*br([0-9a-z]+)', net_bridge).group(1)
|
||||
|
||||
net_obj = {
|
||||
'type': net_type,
|
||||
'vni': net_vni,
|
||||
|
@ -806,7 +806,7 @@ def set_sriov_vf_config(zkhandler, node, vf, vlan_id=None, vlan_qos=None, tx_rat
|
||||
return False, 'Failed to modify configuration of SR-IOV VF "{}" on node "{}".'.format(vf, node)
|
||||
|
||||
|
||||
def set_sriov_vf_vm(zkhandler, node, vf, vm_name, vm_macaddr):
|
||||
def set_sriov_vf_vm(zkhandler, vm_uuid, node, vf, vf_macaddr, vf_type):
|
||||
# Verify node is valid
|
||||
valid_node = common.verifyNode(zkhandler, node)
|
||||
if not valid_node:
|
||||
@ -817,11 +817,19 @@ def set_sriov_vf_vm(zkhandler, node, vf, vm_name, vm_macaddr):
|
||||
if not vf_information:
|
||||
return False
|
||||
|
||||
zkhandler.write([
|
||||
update_list = [
|
||||
(('node.sriov.vf', node, 'sriov_vf.used', vf), 'True'),
|
||||
(('node.sriov.vf', node, 'sriov_vf.used_by', vf), vm_name),
|
||||
(('node.sriov.vf', node, 'sriov_vf.mac', vf), vm_macaddr),
|
||||
])
|
||||
(('node.sriov.vf', node, 'sriov_vf.used_by', vf), vm_uuid),
|
||||
(('node.sriov.vf', node, 'sriov_vf.mac', vf), vf_macaddr),
|
||||
]
|
||||
|
||||
# Hostdev type SR-IOV prevents the guest from live migrating
|
||||
if vf_type == 'hostdev':
|
||||
update_list.append(
|
||||
(('domain.meta.migrate_method', vm_uuid), 'shutdown')
|
||||
)
|
||||
|
||||
zkhandler.write(update_list)
|
||||
|
||||
return True
|
||||
|
||||
@ -837,9 +845,11 @@ def unset_sriov_vf_vm(zkhandler, node, vf):
|
||||
if not vf_information:
|
||||
return False
|
||||
|
||||
zkhandler.write([
|
||||
update_list = [
|
||||
(('node.sriov.vf', node, 'sriov_vf.used', vf), 'False'),
|
||||
(('node.sriov.vf', node, 'sriov_vf.used_by', vf), ''),
|
||||
])
|
||||
]
|
||||
|
||||
zkhandler.write(update_list)
|
||||
|
||||
return True
|
||||
|
@ -27,6 +27,7 @@ import lxml.etree
|
||||
import daemon_lib.common as common
|
||||
|
||||
import daemon_lib.ceph as ceph
|
||||
from daemon_lib.network import set_sriov_vf_vm, unset_sriov_vf_vm
|
||||
|
||||
|
||||
#
|
||||
@ -191,6 +192,21 @@ def define_vm(zkhandler, config_data, target_node, node_limit, node_selector, no
|
||||
if not valid_node:
|
||||
return False, 'ERROR: Specified node "{}" is invalid.'.format(target_node)
|
||||
|
||||
# If a SR-IOV network device is being added, set its used state
|
||||
dnetworks = common.getDomainNetworks(parsed_xml, {})
|
||||
for network in dnetworks:
|
||||
if network['type'] in ['direct', 'hostdev']:
|
||||
dom_node = zkhandler.read(('domain.node', dom_uuid))
|
||||
|
||||
# Check if the network is already in use
|
||||
is_used = zkhandler.read(('node.sriov.vf', dom_node, 'sriov_vf.used', network['source']))
|
||||
if is_used == 'True':
|
||||
used_by_name = searchClusterByUUID(zkhandler, zkhandler.read(('node.sriov.vf', dom_node, 'sriov_vf.used_by', network['source'])))
|
||||
return False, 'ERROR: Attempted to use SR-IOV network "{}" which is already used by VM "{}" on node "{}".'.format(network['source'], used_by_name, dom_node)
|
||||
|
||||
# We must update the "used" section
|
||||
set_sriov_vf_vm(zkhandler, dom_uuid, dom_node, network['source'], network['mac'], network['type'])
|
||||
|
||||
# Obtain the RBD disk list using the common functions
|
||||
ddisks = common.getDomainDisks(parsed_xml, {})
|
||||
rbd_list = []
|
||||
@ -211,7 +227,7 @@ def define_vm(zkhandler, config_data, target_node, node_limit, node_selector, no
|
||||
formatted_rbd_list = ''
|
||||
|
||||
# Add the new domain to Zookeeper
|
||||
result = zkhandler.write([
|
||||
zkhandler.write([
|
||||
(('domain', dom_uuid), dom_name),
|
||||
(('domain.xml', dom_uuid), config_data),
|
||||
(('domain.state', dom_uuid), initial_state),
|
||||
@ -230,10 +246,7 @@ def define_vm(zkhandler, config_data, target_node, node_limit, node_selector, no
|
||||
(('domain.migrate.sync_lock', dom_uuid), ''),
|
||||
])
|
||||
|
||||
if result:
|
||||
return True, 'Added new VM with Name "{}" and UUID "{}" to database.'.format(dom_name, dom_uuid)
|
||||
else:
|
||||
return False, 'ERROR: Failed to add new VM.'
|
||||
return True, 'Added new VM with Name "{}" and UUID "{}" to database.'.format(dom_name, dom_uuid)
|
||||
|
||||
|
||||
def modify_vm_metadata(zkhandler, domain, node_limit, node_selector, node_autostart, provisioner_profile, migration_method):
|
||||
@ -276,7 +289,36 @@ def modify_vm(zkhandler, domain, restart, new_vm_config):
|
||||
try:
|
||||
parsed_xml = lxml.objectify.fromstring(new_vm_config)
|
||||
except Exception:
|
||||
return False, 'ERROR: Failed to parse XML data.'
|
||||
return False, 'ERROR: Failed to parse new XML data.'
|
||||
|
||||
# If a SR-IOV network device is being added, set its used state
|
||||
dnetworks = common.getDomainNetworks(parsed_xml, {})
|
||||
for network in dnetworks:
|
||||
if network['type'] in ['direct', 'hostdev']:
|
||||
dom_node = zkhandler.read(('domain.node', dom_uuid))
|
||||
|
||||
# Check if the network is already in use
|
||||
is_used = zkhandler.read(('node.sriov.vf', dom_node, 'sriov_vf.used', network['source']))
|
||||
if is_used == 'True':
|
||||
used_by_name = searchClusterByUUID(zkhandler, zkhandler.read(('node.sriov.vf', dom_node, 'sriov_vf.used_by', network['source'])))
|
||||
return False, 'ERROR: Attempted to use SR-IOV network "{}" which is already used by VM "{}" on node "{}".'.format(network['source'], used_by_name, dom_node)
|
||||
|
||||
# We must update the "used" section
|
||||
set_sriov_vf_vm(zkhandler, dom_uuid, dom_node, network['source'], network['mac'], network['type'])
|
||||
|
||||
# If a SR-IOV network device is being removed, unset its used state
|
||||
old_vm_config = zkhandler.read(('domain.xml', dom_uuid))
|
||||
try:
|
||||
old_parsed_xml = lxml.objectify.fromstring(old_vm_config)
|
||||
except Exception:
|
||||
return False, 'ERROR: Failed to parse old XML data.'
|
||||
old_dnetworks = common.getDomainNetworks(old_parsed_xml, {})
|
||||
for network in old_dnetworks:
|
||||
if network['type'] in ['direct', 'hostdev']:
|
||||
if network['mac'] not in [n['mac'] for n in dnetworks]:
|
||||
dom_node = zkhandler.read(('domain.node', dom_uuid))
|
||||
# We must update the "used" section
|
||||
unset_sriov_vf_vm(zkhandler, dom_node, network['source'])
|
||||
|
||||
# Obtain the RBD disk list using the common functions
|
||||
ddisks = common.getDomainDisks(parsed_xml, {})
|
||||
|
Reference in New Issue
Block a user