Antoni Segura Puimedon has uploaded a new change for review. Change subject: tc: [WIP] addNetwork support ......................................................................
tc: [WIP] addNetwork support Missing api schema and tests Change-Id: I4a5378870a3dac9307a6eef8d9937a9c03a0c819 Signed-off-by: Antoni S. Puimedon <[email protected]> --- M vdsm/network/api.py M vdsm/network/configurators/__init__.py A vdsm/network/configurators/qos.py M vdsm/network/models.py 4 files changed, 173 insertions(+), 0 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/67/30467/1 diff --git a/vdsm/network/api.py b/vdsm/network/api.py index ff08308..aba08b1 100755 --- a/vdsm/network/api.py +++ b/vdsm/network/api.py @@ -324,6 +324,7 @@ netEnt.configure(**options) configurator.configureLibvirtNetwork(network, netEnt) + configurator.configureQoS(qosOutbound, netEnt) def assertBridgeClean(bridge, vlan, bonding, nics): diff --git a/vdsm/network/configurators/__init__.py b/vdsm/network/configurators/__init__.py index 6e2f969..e2290d1 100644 --- a/vdsm/network/configurators/__init__.py +++ b/vdsm/network/configurators/__init__.py @@ -25,6 +25,7 @@ from vdsm.netconfpersistence import RunningConfig from . import libvirt +from . import qos from ..models import Bond, Bridge from ..sourceroute import StaticSourceRoute @@ -111,6 +112,12 @@ def removeLibvirtNetwork(self, network): self.configApplier.removeLibvirtNetwork(network) + def configureQoS(self, qosOutbound, top_device): + qos.configure_outbound(qosOutbound, top_device) + + def removeQoS(self, qosOutbound, top_device): + qos.configure_outbound(qosOutbound, top_device) + def _addSourceRoute(self, netEnt): ip = netEnt.ipConfig # bootproto is None for both static and no bootproto diff --git a/vdsm/network/configurators/qos.py b/vdsm/network/configurators/qos.py new file mode 100644 index 0000000..ff976e8 --- /dev/null +++ b/vdsm/network/configurators/qos.py @@ -0,0 +1,139 @@ +# Copyright 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Refer to the README and COPYING files for full details of the license +# +import errno +import os +from distutils.version import StrictVersion + +from .. import tc +_NON_VLANNED_ID = '%x' % 5000 +_ROOT_QDISC_HANDLE = '%x:' % 5001 # Leave 0 free for leaf qdisc of vlan tag 0 +_FAIR_QDISC_KIND = 'fq_codel' if (StrictVersion(os.uname()[2].split('-')[0]) > + StrictVersion('3.5.0')) else 'sfq' + + +def configure_outbound(qosOutbound, top_device): + description = top_device.description + vlan_tag = description.get('vlan_tag') + device = description['log_dev'] + qdiscs = list(tc._qdiscs(device)) + root_qdisc = _root_qdisc(qdiscs) + class_id = _NON_VLANNED_ID if vlan_tag is None else '%x' % vlan_tag + if root_qdisc['kind'] != 'hfsc': + _fresh_qdisc_conf_out(device, vlan_tag, class_id, + _qos_to_str_dict(qosOutbound)) + else: + _qdisc_conf_out(device, root_qdisc['handle'], vlan_tag, class_id, + _qos_to_str_dict(qosOutbound)) + + +def unconfigure_outbound(qosOutbound, top_device): + pass + + +def _fresh_qdisc_conf_out(dev, vlan_tag, class_id, qos): + """Replaces the dev qdisc with hfsc and sets up the shaping""" + # Use deletion + addition to flush children classes and filters + try: + tc.qdisc.delete(dev) # Deletes the root qdisc by default + except tc.TrafficControlException as tce: + if tce.errCode != tc.ERR_DEV_NOEXIST: + raise + tc.qdisc.add(dev, 'hfsc', root=True, handle='0x' + _ROOT_QDISC_HANDLE, + default='0x' + _NON_VLANNED_ID) + + tc.cls.add(dev, 'hfsc', parent=_ROOT_QDISC_HANDLE, + classid=_ROOT_QDISC_HANDLE, **qos) + + # Add traffic classes + _add_hfsc_cls(dev, class_id, **qos) + if class_id != _NON_VLANNED_ID: # We need to add a default class + _add_hfsc_cls(dev, _NON_VLANNED_ID, ls=qos['ls']) + + # Add filters to move the traffic into the classes we just created + _add_non_vlanned_filter(dev) + if class_id != _NON_VLANNED_ID: + _add_vlan_filter(dev, vlan_tag, class_id) + + # Add inside intra-class fairness qdisc (fq_codel/sfq) + _add_fair_qdisc(dev, class_id) + if class_id != _NON_VLANNED_ID: + _add_fair_qdisc(dev, _NON_VLANNED_ID) + + +def _qdisc_conf_out(dev, root_qdisc_handle, vlan_tag, class_id, qos): + """Adds the traffic class and filtering to the current hfsc qdisc""" + filters = [filt for filt in tc._filters(dev, parent=root_qdisc_handle) if + 'u32' in filt and filt['u32'].get('flowid') == + _ROOT_QDISC_HANDLE + class_id] + + # Clear up any previous filters to the class + for filt in filters: + try: + tc.filter.delete(dev, filt['pref'], parent=root_qdisc_handle) + except tc.TrafficControlException as tce: + if tce.errCode != errno.EINVAL: # no filters exist -> EINVAL + raise + + # Clear the class in case it exists + try: + tc.cls.delete(dev, classid=root_qdisc_handle + class_id) + except tc.TrafficControlException as tce: + if tce.errCode != errno.ENOENT: + raise + + _add_hfsc_cls(dev, _NON_VLANNED_ID, **qos) + _add_vlan_filter(dev, vlan_tag, class_id) + _add_fair_qdisc(dev, class_id) + + +def _add_vlan_filter(dev, vlan_tag, class_id): + tc.filter.replace(dev, parent=_ROOT_QDISC_HANDLE, protocol='802.1q', + u32=['match', 'u16', '0x%x' % vlan_tag, '0xFFF', 'at', + '-4', 'flowid', '0x' + class_id]) + + +def _add_non_vlanned_filter(dev): + tc.filter.replace(dev, parent=_ROOT_QDISC_HANDLE, protocol='all', + u32=['match', 'u8', '0', '0', 'flowid', + '0x' + _NON_VLANNED_ID]) + + +def _add_fair_qdisc(dev, class_id): + tc.qdisc.add(dev, _FAIR_QDISC_KIND, parent=_ROOT_QDISC_HANDLE + class_id, + handle=class_id + ':') + + +def _add_hfsc_cls(dev, class_id, *qos_opts): + tc.cls.add(dev, 'hfsc', parent=_ROOT_QDISC_HANDLE, + classid=_ROOT_QDISC_HANDLE + class_id, **qos_opts) + + +def _qos_to_str_dict(qos): + data = {} + for curve in qos: + data[curve] = ['m1', '%sbit' % curve.get('m1', '0'), + 'd', '%sus' % curve.get('d', '0'), + 'm2', '%sbit' % curve.get('m2', '0')] + return data + + +def _root_qdisc(qdiscs): + for qdisc in qdiscs: + if 'root' in qdiscs: + return qdisc diff --git a/vdsm/network/models.py b/vdsm/network/models.py index 402a4b5..5ba6f41 100644 --- a/vdsm/network/models.py +++ b/vdsm/network/models.py @@ -111,6 +111,12 @@ def __repr__(self): return 'Nic(%s)' % self.name + @property + def description(self): + """Returns a dictionary with information about the underlying hierarchy + of the device""" + return {'log_dev': self.name} + class Vlan(NetDevice): MAX_ID = 4094 @@ -147,6 +153,14 @@ 'number between 0 and %s' % cls.MAX_ID) + @property + def description(self): + """Returns a dictionary with information about the underlying hierarchy + of the device""" + description = {'vlan_tag': self.vlan} + description.update(self.device.description) + return description + class Bridge(NetDevice): '''This class represents traditional kernel bridges.''' @@ -179,6 +193,12 @@ not name.startswith('-')): raise ConfigNetworkError(ne.ERR_BAD_BRIDGE, "Bridge name isn't valid: %r" % name) + + @property + def description(self): + """Returns a dictionary with information about the underlying hierarchy + of the device""" + return self.port.description class Bond(NetDevice): @@ -324,6 +344,12 @@ return ' '.join((opt + '=' + val for (opt, val) in opts)) + @property + def description(self): + """Returns a dictionary with information about the underlying hierarchy + of the device""" + return {'log_dev': self.name} + class IPv4(object): def __init__(self, address=None, netmask=None, gateway=None, -- To view, visit http://gerrit.ovirt.org/30467 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I4a5378870a3dac9307a6eef8d9937a9c03a0c819 Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Antoni Segura Puimedon <[email protected]> _______________________________________________ vdsm-patches mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches
