def _analyse_classes(self): all_classes = list(tc.classes(self.device_name)) root_class = self._root_class(all_classes) default_class = self._default_class(all_classes) all_classes.remove(root_class) all_classes.remove(default_class) return TcClasses(all_classes, default_class, root_class)
def report_network_qos(netinfo): """Augment netinfo information with QoS data for the engine""" qdiscs = defaultdict(list) for qdisc in tc.qdiscs(dev=None): # None -> all dev qdiscs qdiscs[qdisc['dev']].append(qdisc) for net, attrs in netinfo['networks'].iteritems(): iface = attrs['iface'] if iface in netinfo['bridges']: host_ports = [port for port in attrs['ports'] if not port.startswith('vnet')] if not host_ports: # Port-less bridge continue iface, = host_ports if iface in netinfo['vlans']: vlan_id = netinfo['vlans'][iface]['vlanid'] iface = netinfo['vlans'][iface]['iface'] iface_qdiscs = qdiscs.get(iface) if iface_qdiscs is None: continue class_id = (get_root_qdisc(iface_qdiscs)['handle'] + '%x' % vlan_id) else: iface_qdiscs = qdiscs.get(iface) if iface_qdiscs is None: continue class_id = (get_root_qdisc(iface_qdiscs)['handle'] + DEFAULT_CLASSID) # Now that iface is either a bond or a nic, let's get the QoS info classes = [cls for cls in tc.classes(iface, classid=class_id) if cls['kind'] == 'hfsc'] if classes: cls, = classes attrs['hostQos'] = {'out': cls['hfsc']}
def _uses_classes(device, root_qdisc_handle=None): """Returns true iff there's traffic classes in the device, ignoring the root class and a default unused class""" if root_qdisc_handle is None: root_qdisc = netinfo_qos.get_root_qdisc(tc.qdiscs(device)) root_qdisc_handle = root_qdisc['handle'] classes = [cls for cls in tc.classes(device, parent=root_qdisc_handle) if not cls.get('root')] return (classes and not(len(classes) == 1 and not ifaceUsed(device) and classes[0]['handle'] == root_qdisc_handle + _DEFAULT_CLASSID))
def _qdisc_conf_out(dev, root_qdisc_handle, vlan_tag, class_id, qos): """Adds the traffic class and filtering to the current hfsc qdisc""" flow_id = _ROOT_QDISC_HANDLE + class_id def filt_flow_id(filt, kind): return filt.get(kind, {}).get('flowid') filters = [ filt for filt in tc._filters(dev, parent=root_qdisc_handle) if flow_id in (filt_flow_id(filt, 'basic'), filt_flow_id(filt, 'u32')) ] # 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, root_qdisc_handle, class_id, **qos) if class_id == _DEFAULT_CLASSID: _add_non_vlanned_filter(dev, root_qdisc_handle) else: if not _is_explicit_defined_default_class(dev): default_class, = [ c['hfsc'] for c in tc.classes(dev) if c['handle'] == _ROOT_QDISC_HANDLE + _DEFAULT_CLASSID ] ls_max_rate = _max_hfsc_ls_rate(dev) default_class['ls']['m2'] = ls_max_rate tc.cls.delete(dev, classid=_ROOT_QDISC_HANDLE + _DEFAULT_CLASSID) _add_hfsc_cls(dev, _ROOT_QDISC_HANDLE, _DEFAULT_CLASSID, ls=default_class['ls']) _add_fair_qdisc(dev, _ROOT_QDISC_HANDLE, _DEFAULT_CLASSID) _add_vlan_filter(dev, vlan_tag, root_qdisc_handle, class_id) _add_fair_qdisc(dev, root_qdisc_handle, class_id)
def test_classes(self): cmd_line_ls_10 = 3200 cmd_line_ls_m1_20 = 6400 cmd_line_ls_d_20 = 152 cmd_line_ls_m2_20 = 3200 cmd_line_ls_30 = 3500 cmd_line_ls_m2_5000 = 40000 data = '\n'.join(( 'class hfsc 1: root', 'class hfsc 1:10 parent 1: leaf 10: sc m1 0bit d 0us ' 'm2 {0}Kbit'.format(cmd_line_ls_10), # end of previous line 'class hfsc 1:20 parent 1: leaf 20: ls m1 {0}Kibit d {1}us ' 'm2 {2}Kbit ul m1 0bit d 0us m2 30000Kbit'.format( cmd_line_ls_m1_20, cmd_line_ls_d_20, cmd_line_ls_m2_20), 'class hfsc 1:30 parent 1: leaf 40: sc m1 0bit d 0us ' 'm2 {0}bit'.format(cmd_line_ls_30), # end of previous line 'class hfsc 1:5000 parent 1: leaf 5000: ls m1 0bit d 0us ' 'm2 {0}Kbit'.format(cmd_line_ls_m2_5000), # end of previous line )) reported_ls_10 = cmd_line_ls_10 * 1000 / 8 reported_ls_m1_20 = cmd_line_ls_m1_20 * 1024 / 8 reported_ls_d_20 = cmd_line_ls_d_20 / 8 reported_ls_m2_20 = cmd_line_ls_m2_20 * 1000 / 8 reported_ls_30 = cmd_line_ls_30 / 8 reported_ls_5000 = cmd_line_ls_m2_5000 * 1000 / 8 classes = ( {'kind': 'hfsc', 'root': True, 'handle': '1:'}, {'kind': 'hfsc', 'handle': '1:10', 'parent': '1:', 'leaf': '10:', 'hfsc': {'ls': {'m1': 0, 'd': 0, 'm2': reported_ls_10}, 'rt': {'m1': 0, 'd': 0, 'm2': reported_ls_10}}}, {'kind': 'hfsc', 'handle': '1:20', 'parent': '1:', 'leaf': '20:', 'hfsc': {'ls': {'m1': reported_ls_m1_20, 'd': reported_ls_d_20, 'm2': reported_ls_m2_20}, 'ul': {'m1': 0, 'd': 0, 'm2': 30000 * 1000}}}, {'kind': 'hfsc', 'handle': '1:30', 'parent': '1:', 'leaf': '40:', 'hfsc': {'ls': {'m1': 0, 'd': 0, 'm2': reported_ls_30}, 'rt': {'m1': 0, 'd': 0, 'm2': reported_ls_30}}}, {'kind': 'hfsc', 'handle': '1:5000', 'parent': '1:', 'leaf': '5000:', 'hfsc': {'ls': {'m1': 0, 'd': 0, 'm2': reported_ls_5000}}}, ) for parsed, correct in zip_longest(tc.classes(None, out=data), classes): self.assertEqual(parsed, correct)
def report_network_qos(nets_info, devs_info): """Augment netinfo information with QoS data for the engine""" qdiscs = defaultdict(list) for qdisc in tc.qdiscs(dev=None): # None -> all dev qdiscs qdiscs[qdisc['dev']].append(qdisc) for net, attrs in six.viewitems(nets_info): iface = attrs['iface'] if iface in devs_info['bridges']: host_ports = [ port for port in attrs['ports'] if not port.startswith('vnet') ] if not host_ports: # Port-less bridge continue if len(host_ports) > 1: logging.error( 'Multiple southbound ports per network detected,' ' ignoring this network for the QoS report ' '(network: %s, ports: %s)', net, host_ports, ) continue (iface, ) = host_ports if iface in devs_info['vlans']: vlan_id = devs_info['vlans'][iface]['vlanid'] iface = devs_info['vlans'][iface]['iface'] iface_qdiscs = qdiscs.get(iface) if iface_qdiscs is None: continue class_id = get_root_qdisc(iface_qdiscs)['handle'] + '%x' % vlan_id else: iface_qdiscs = qdiscs.get(iface) if iface_qdiscs is None: continue class_id = get_root_qdisc(iface_qdiscs)['handle'] + DEFAULT_CLASSID # Now that iface is either a bond or a nic, let's get the QoS info classes = [ cls for cls in tc.classes(iface, classid=class_id) if cls['kind'] == 'hfsc' ] if classes: (cls, ) = classes attrs['hostQos'] = {'out': cls['hfsc']}
def _qdisc_conf_out(dev, root_qdisc_handle, vlan_tag, class_id, qos): """Adds the traffic class and filtering to the current hfsc qdisc""" flow_id = _ROOT_QDISC_HANDLE + class_id def filt_flow_id(filt, kind): return filt.get(kind, {}).get('flowid') filters = [filt for filt in tc._filters(dev, parent=root_qdisc_handle) if flow_id in (filt_flow_id(filt, 'basic'), filt_flow_id(filt, 'u32'))] # 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, root_qdisc_handle, class_id, **qos) if class_id == _DEFAULT_CLASSID: _add_non_vlanned_filter(dev, root_qdisc_handle) else: if not _is_explicit_defined_default_class(dev): default_class, = [c['hfsc'] for c in tc.classes( dev) if c['handle'] == _ROOT_QDISC_HANDLE + _DEFAULT_CLASSID] ls_max_rate = _max_hfsc_ls_rate(dev) default_class['ls']['m2'] = ls_max_rate tc.cls.delete(dev, classid=_ROOT_QDISC_HANDLE + _DEFAULT_CLASSID) _add_hfsc_cls(dev, _ROOT_QDISC_HANDLE, _DEFAULT_CLASSID, ls=default_class['ls']) _add_fair_qdisc(dev, _ROOT_QDISC_HANDLE, _DEFAULT_CLASSID) _add_vlan_filter(dev, vlan_tag, root_qdisc_handle, class_id) _add_fair_qdisc(dev, root_qdisc_handle, class_id)
def report_network_qos(nets_info, devs_info): """Augment netinfo information with QoS data for the engine""" qdiscs = defaultdict(list) for qdisc in tc.qdiscs(dev=None): # None -> all dev qdiscs qdiscs[qdisc['dev']].append(qdisc) for net, attrs in six.viewitems(nets_info): iface = attrs['iface'] if iface in devs_info['bridges']: host_ports = [port for port in attrs['ports'] if not port.startswith('vnet')] if not host_ports: # Port-less bridge continue if len(host_ports) > 1: logging.error('Multiple southbound ports per network detected,' ' ignoring this network for the QoS report ' '(network: %s, ports: %s)', net, host_ports) continue iface, = host_ports if iface in devs_info['vlans']: vlan_id = devs_info['vlans'][iface]['vlanid'] iface = devs_info['vlans'][iface]['iface'] iface_qdiscs = qdiscs.get(iface) if iface_qdiscs is None: continue class_id = (get_root_qdisc(iface_qdiscs)['handle'] + '%x' % vlan_id) else: iface_qdiscs = qdiscs.get(iface) if iface_qdiscs is None: continue class_id = (get_root_qdisc(iface_qdiscs)['handle'] + DEFAULT_CLASSID) # Now that iface is either a bond or a nic, let's get the QoS info classes = [cls for cls in tc.classes(iface, classid=class_id) if cls['kind'] == 'hfsc'] if classes: cls, = classes attrs['hostQos'] = {'out': cls['hfsc']}
def report_network_qos(nets_info, devs_info): """Augment netinfo information with QoS data for the engine""" qdiscs = defaultdict(list) for qdisc in tc.qdiscs(dev=None): # None -> all dev qdiscs qdiscs[qdisc['dev']].append(qdisc) for net, attrs in six.viewitems(nets_info): iface = attrs['iface'] if iface in devs_info['bridges']: host_ports = [ port for port in attrs['ports'] if not port.startswith('vnet') ] if not host_ports: # Port-less bridge continue iface, = host_ports if iface in devs_info['vlans']: vlan_id = devs_info['vlans'][iface]['vlanid'] iface = devs_info['vlans'][iface]['iface'] iface_qdiscs = qdiscs.get(iface) if iface_qdiscs is None: continue class_id = (get_root_qdisc(iface_qdiscs)['handle'] + '%x' % vlan_id) else: iface_qdiscs = qdiscs.get(iface) if iface_qdiscs is None: continue class_id = (get_root_qdisc(iface_qdiscs)['handle'] + DEFAULT_CLASSID) # Now that iface is either a bond or a nic, let's get the QoS info classes = [ cls for cls in tc.classes(iface, classid=class_id) if cls['kind'] == 'hfsc' ] if classes: cls, = classes attrs['hostQos'] = {'out': cls['hfsc']}
def _max_hfsc_ls_rate(dev): return max([ cls['hfsc']['ls']['m2'] for cls in tc.classes(dev) if cls['kind'] == 'hfsc' and 'root' not in cls ])
def _max_hfsc_ls_rate(dev): return max([cls['hfsc']['ls']['m2'] for cls in tc.classes(dev) if cls['kind'] == 'hfsc' and 'root' not in cls])