ret.append(_str_from_xml(n))
return ret
-def _otherconfig_to_xml(xml, parent, val, attrs):
- otherconfig = xml.createElement("other_config")
- parent.appendChild(otherconfig)
+def _map_to_xml(xml, parent, tag, val, attrs):
+ e = xml.createElement(tag)
+ parent.appendChild(e)
for n,v in val.items():
- if not n in attrs:
- raise Error("Unknown other-config attribute: %s" % n)
- _str_to_xml(xml, otherconfig, n, v)
-def _otherconfig_from_xml(n, attrs):
+ if n in attrs:
+ _str_to_xml(xml, e, n, v)
+ else:
+ log("Unknown other-config attribute: %s" % n)
+
+def _map_from_xml(n, attrs):
ret = {}
for n in n.childNodes:
if n.nodeName in attrs:
ret[n.nodeName] = _str_from_xml(n)
return ret
+def _otherconfig_to_xml(xml, parent, val, attrs):
+ return _map_to_xml(xml, parent, "other_config", val, attrs)
+def _otherconfig_from_xml(n, attrs):
+ return _map_from_xml(n, attrs)
+
#
# Definitions of the database objects (and their attributes) used by interface-reconfigure.
#
_PIF_XML_TAG = "pif"
_VLAN_XML_TAG = "vlan"
+_TUNNEL_XML_TAG = "tunnel"
_BOND_XML_TAG = "bond"
_NETWORK_XML_TAG = "network"
+_POOL_XML_TAG = "pool"
-_ETHTOOL_OTHERCONFIG_ATTRS = ['ethtool-%s' % x for x in 'autoneg', 'speed', 'duplex', 'rx', 'tx', 'sg', 'tso', 'ufo', 'gso' ]
+_ETHTOOL_OTHERCONFIG_ATTRS = ['ethtool-%s' % x for x in 'autoneg', 'speed', 'duplex', 'rx', 'tx', 'sg', 'tso', 'ufo', 'gso', 'gro', 'lro' ]
_PIF_OTHERCONFIG_ATTRS = [ 'domain', 'peerdns', 'defaultroute', 'mtu', 'static-routes' ] + \
- [ 'bond-%s' % x for x in 'mode', 'miimon', 'downdelay', 'updelay', 'use_carrier' ] + \
+ [ 'bond-%s' % x for x in 'mode', 'miimon', 'downdelay',
+ 'updelay', 'use_carrier', 'hashing-algorithm' ] + \
+ [ 'vlan-bug-workaround' ] + \
_ETHTOOL_OTHERCONFIG_ATTRS
_PIF_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
'VLAN_master_of': (_str_to_xml,_str_from_xml),
'VLAN_slave_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 'VLAN_slave_of', 'master', v),
lambda n: _strlist_from_xml(n, 'VLAN_slave_Of', 'master')),
+ 'tunnel_access_PIF_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 'tunnel_access_PIF_of', 'pif', v),
+ lambda n: _strlist_from_xml(n, 'tunnel_access_PIF_of', 'pif')),
+ 'tunnel_transport_PIF_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 'tunnel_transport_PIF_of', 'pif', v),
+ lambda n: _strlist_from_xml(n, 'tunnel_transport_PIF_of', 'pif')),
'ip_configuration_mode': (_str_to_xml,_str_from_xml),
'IP': (_str_to_xml,_str_from_xml),
'netmask': (_str_to_xml,_str_from_xml),
'untagged_PIF': (_str_to_xml,_str_from_xml),
}
+_TUNNEL_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
+ 'access_PIF': (_str_to_xml,_str_from_xml),
+ 'transport_PIF': (_str_to_xml,_str_from_xml),
+ }
_BOND_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
'master': (_str_to_xml,_str_from_xml),
'slaves': (lambda x, p, t, v: _strlist_to_xml(x, p, 'slaves', 'slave', v),
lambda n: _strlist_from_xml(n, 'slaves', 'slave')),
}
-_NETWORK_OTHERCONFIG_ATTRS = [ 'mtu', 'static-routes' ] + _ETHTOOL_OTHERCONFIG_ATTRS
+_NETWORK_OTHERCONFIG_ATTRS = [ 'mtu',
+ 'static-routes',
+ 'vswitch-controller-fail-mode',
+ 'vswitch-disable-in-band' ] \
+ + _ETHTOOL_OTHERCONFIG_ATTRS
_NETWORK_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
'bridge': (_str_to_xml,_str_from_xml),
lambda n: _otherconfig_from_xml(n, _NETWORK_OTHERCONFIG_ATTRS)),
}
+_POOL_OTHERCONFIG_ATTRS = ['vswitch-controller-fail-mode']
+
+_POOL_ATTRS = { 'other_config': (lambda x, p, t, v: _otherconfig_to_xml(x, p, v, _POOL_OTHERCONFIG_ATTRS),
+ lambda n: _otherconfig_from_xml(n, _POOL_OTHERCONFIG_ATTRS)),
+ }
+
#
# Database Cache object
#
def __get_vlan_records_from_xapi(self, session):
self.__vlans = {}
- for v in session.xenapi.VLAN.get_all():
- rec = session.xenapi.VLAN.get_record(v)
+ for (v,rec) in session.xenapi.VLAN.get_all_records().items():
if not self.__pif_on_host(rec['untagged_PIF']):
continue
self.__vlans[v] = {}
for f in _VLAN_ATTRS:
self.__vlans[v][f] = rec[f]
+ def __get_tunnel_records_from_xapi(self, session):
+ self.__tunnels = {}
+ for t in session.xenapi.tunnel.get_all():
+ rec = session.xenapi.tunnel.get_record(t)
+ if not self.__pif_on_host(rec['transport_PIF']):
+ continue
+ self.__tunnels[t] = {}
+ for f in _TUNNEL_ATTRS:
+ self.__tunnels[t][f] = rec[f]
+
def __get_bond_records_from_xapi(self, session):
self.__bonds = {}
- for b in session.xenapi.Bond.get_all():
- rec = session.xenapi.Bond.get_record(b)
+ for (b,rec) in session.xenapi.Bond.get_all_records().items():
if not self.__pif_on_host(rec['master']):
continue
self.__bonds[b] = {}
def __get_network_records_from_xapi(self, session):
self.__networks = {}
- for n in session.xenapi.network.get_all():
- rec = session.xenapi.network.get_record(n)
+ for (n,rec) in session.xenapi.network.get_all_records().items():
self.__networks[n] = {}
for f in _NETWORK_ATTRS:
if f == "PIFs":
# drop PIFs on other hosts
self.__networks[n][f] = [p for p in rec[f] if self.__pif_on_host(p)]
+ elif f == "MTU" and f not in rec:
+ # XenServer 5.5 network records did not have an
+ # MTU field, so allow this to be missing.
+ pass
else:
self.__networks[n][f] = rec[f]
self.__networks[n]['other_config'] = {}
if not rec['other_config'].has_key(f): continue
self.__networks[n]['other_config'][f] = rec['other_config'][f]
+ def __get_pool_records_from_xapi(self, session):
+ self.__pools = {}
+ for p in session.xenapi.pool.get_all():
+ rec = session.xenapi.pool.get_record(p)
+
+ self.__pools[p] = {}
+
+ for f in _POOL_ATTRS:
+ self.__pools[p][f] = rec[f]
+
+ for f in _POOL_OTHERCONFIG_ATTRS:
+ if rec['other_config'].has_key(f):
+ self.__pools[p]['other_config'][f] = rec['other_config'][f]
+
def __to_xml(self, xml, parent, key, ref, rec, attrs):
"""Encode a database object as XML"""
e = xml.createElement(key)
host = session.xenapi.host.get_by_uuid(inventory['INSTALLATION_UUID'])
self.__get_pif_records_from_xapi(session, host)
-
+ self.__get_pool_records_from_xapi(session)
+ self.__get_tunnel_records_from_xapi(session)
self.__get_vlan_records_from_xapi(session)
self.__get_bond_records_from_xapi(session)
self.__get_network_records_from_xapi(session)
self.__pifs = {}
self.__bonds = {}
self.__vlans = {}
+ self.__pools = {}
+ self.__tunnels = {}
self.__networks = {}
assert(len(xml.childNodes) == 1)
elif n.nodeName == _VLAN_XML_TAG:
(ref,rec) = self.__from_xml(n, _VLAN_ATTRS)
self.__vlans[ref] = rec
+ elif n.nodeName == _TUNNEL_XML_TAG:
+ (ref,rec) = self.__from_xml(n, _TUNNEL_ATTRS)
+ self.__vlans[ref] = rec
elif n.nodeName == _NETWORK_XML_TAG:
(ref,rec) = self.__from_xml(n, _NETWORK_ATTRS)
self.__networks[ref] = rec
+ elif n.nodeName == _POOL_XML_TAG:
+ (ref,rec) = self.__from_xml(n, _POOL_ATTRS)
+ self.__pools[ref] = rec
else:
raise Error("Unknown XML element %s" % n.nodeName)
self.__to_xml(xml, xml.documentElement, _BOND_XML_TAG, ref, rec, _BOND_ATTRS)
for (ref,rec) in self.__vlans.items():
self.__to_xml(xml, xml.documentElement, _VLAN_XML_TAG, ref, rec, _VLAN_ATTRS)
+ for (ref,rec) in self.__tunnels.items():
+ self.__to_xml(xml, xml.documentElement, _TUNNEL_XML_TAG, ref, rec, _TUNNEL_ATTRS)
for (ref,rec) in self.__networks.items():
self.__to_xml(xml, xml.documentElement, _NETWORK_XML_TAG, ref, rec,
_NETWORK_ATTRS)
+ for (ref,rec) in self.__pools.items():
+ self.__to_xml(xml, xml.documentElement, _POOL_XML_TAG, ref, rec, _POOL_ATTRS)
- f = open(cache_file, 'w')
+ temp_file = cache_file + ".%d" % os.getpid()
+ f = open(temp_file, 'w')
f.write(xml.toprettyxml())
f.close()
+ os.rename(temp_file, cache_file)
def get_pif_by_uuid(self, uuid):
pifs = map(lambda (ref,rec): ref,
filter(lambda (ref,rec): rec['device'] == device,
self.__pifs.items()))
+ def get_networks_with_bridge(self, bridge):
+ return map(lambda (ref,rec): ref,
+ filter(lambda (ref,rec): rec['bridge'] == bridge,
+ self.__networks.items()))
+
+ def get_network_by_bridge(self, bridge):
+ #Assumes one network has bridge.
+ try:
+ return self.get_networks_with_bridge(bridge)[0]
+ except KeyError:
+ return None
+
def get_pif_by_bridge(self, bridge):
- networks = map(lambda (ref,rec): ref,
- filter(lambda (ref,rec): rec['bridge'] == bridge,
- self.__networks.items()))
+ networks = self.get_networks_with_bridge(bridge)
+
if len(networks) == 0:
raise Error("No matching network \"%s\"" % bridge)
else:
return None
+ def get_pool_record(self):
+ if len(self.__pools) > 0:
+ return self.__pools.values()[0]
+
#
#
#
+PIF_OTHERCONFIG_DEFAULTS = {'gro': 'off', 'lro': 'off'}
-def ethtool_settings(oc):
+def ethtool_settings(oc, defaults = {}):
settings = []
if oc.has_key('ethtool-speed'):
val = oc['ethtool-speed']
log("Invalid value for ethtool-speed = %s. Must be 10|100|1000." % val)
if oc.has_key('ethtool-duplex'):
val = oc['ethtool-duplex']
- if val in ["10", "100", "1000"]:
- settings += ['duplex', 'val']
+ if val in ["half", "full"]:
+ settings += ['duplex', val]
else:
log("Invalid value for ethtool-duplex = %s. Must be half|full." % val)
if oc.has_key('ethtool-autoneg'):
else:
log("Invalid value for ethtool-autoneg = %s. Must be on|true|off|false." % val)
offload = []
- for opt in ("rx", "tx", "sg", "tso", "ufo", "gso"):
+ for opt in ("rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro"):
if oc.has_key("ethtool-" + opt):
val = oc["ethtool-" + opt]
if val in ["true", "on"]:
offload += [opt, 'off']
else:
log("Invalid value for ethtool-%s = %s. Must be on|true|off|false." % (opt, val))
+ elif opt in defaults:
+ offload += [opt, defaults[opt]]
return settings,offload
# By default the MTU is taken from the Network.MTU setting for VIF,
vlans = [db().get_vlan_record(v) for v in pifrec['VLAN_slave_of']]
return [v['untagged_PIF'] for v in vlans if v and db().pif_exists(v['untagged_PIF'])]
+#
+# Tunnel PIFs
+#
+def pif_is_tunnel(pif):
+ return len(db().get_pif_record(pif)['tunnel_access_PIF_of']) > 0
+
#
# Datapath base class
#
def __init__(self, pif):
self._pif = pif
+ @classmethod
+ def rewrite(cls):
+ """Class method called when write action is called. Can be used
+ to update any backend specific configuration."""
+ pass
+
def configure_ipdev(self, cfg):
"""Write ifcfg TYPE field for an IPdev, plus any type specific
fields to cfg
Should assume any configuration files changed attached in
the preconfigure stage are applied and bring up the
- necesary devices to provide the datapath for the
+ necessary devices to provide the datapath for the
PIF.
Should not bring up the IPdev.
"""
raise NotImplementedError
-def DatapathFactory(pif):
+def DatapathFactory():
# XXX Need a datapath object for bridgeless PIFs
try:
if network_backend == "bridge":
from InterfaceReconfigureBridge import DatapathBridge
- return DatapathBridge(pif)
- elif network_backend == "vswitch":
+ return DatapathBridge
+ elif network_backend in ["openvswitch", "vswitch"]:
from InterfaceReconfigureVswitch import DatapathVswitch
- return DatapathVswitch(pif)
+ return DatapathVswitch
else:
raise Error("unknown network backend %s" % network_backend)