def test_add_tc_qdisc_tbf(self): burst = 192000 rate = 320000 latency = 50000 priv_tc_lib.add_tc_qdisc(self.device, parent=rtnl.TC_H_ROOT, kind='tbf', burst=burst, rate=rate, latency=latency, namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(1, len(qdiscs)) self.assertEqual(rtnl.TC_H_ROOT, qdiscs[0]['parent']) self.assertEqual('tbf', tc_lib._get_attr(qdiscs[0], 'TCA_KIND')) tca_options = tc_lib._get_attr(qdiscs[0], 'TCA_OPTIONS') tca_tbf_parms = tc_lib._get_attr(tca_options, 'TCA_TBF_PARMS') self.assertEqual(rate, tca_tbf_parms['rate']) self.assertEqual( burst, tc_lib._calc_burst(tca_tbf_parms['rate'], tca_tbf_parms['buffer'])) self.assertEqual( latency, tc_lib._calc_latency_ms(tca_tbf_parms['limit'], burst, tca_tbf_parms['rate']) * 1000) priv_tc_lib.delete_tc_qdisc(self.device, parent=rtnl.TC_H_ROOT, namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(0, len(qdiscs))
def test_add_tc_filter_match32(self): priv_tc_lib.add_tc_qdisc(self.device, parent=rtnl.TC_H_ROOT, kind='htb', handle='1:', namespace=self.namespace) priv_tc_lib.add_tc_policy_class(self.device, '1:', '1:10', 'htb', namespace=self.namespace, rate=10000) keys = tc_lib._mac_to_pyroute2_keys('7a:8c:f9:1f:e5:cb', 41) priv_tc_lib.add_tc_filter_match32(self.device, '1:0', 10, '1:10', [keys[0]['key'], keys[1]['key']], namespace=self.namespace) filters = tc_lib.list_tc_filters(self.device, '1:0', namespace=self.namespace) self.assertEqual(1, len(filters)) filter_keys = filters[0]['keys'] self.assertEqual(len(keys), len(filter_keys)) for index, value in enumerate(keys): value.pop('key') self.assertEqual(value, filter_keys[index])
def test_add_tc_filter_policy(self): priv_tc_lib.add_tc_qdisc(self.device, parent=rtnl.TC_H_ROOT, kind='ingress', namespace=self.namespace) # NOTE(ralonsoh): # - rate: 320000 bytes/sec (pyroute2 units) = 2500 kbits/sec (OS units) # - burst: 192000 bytes/sec = 1500 kbits/sec priv_tc_lib.add_tc_filter_policy(self.device, 'ffff:', 49, 320000, 192000, 1200, 'drop', namespace=self.namespace) filters = tc_lib.list_tc_filters(self.device, 'ffff:', namespace=self.namespace) self.assertEqual(1, len(filters)) self.assertEqual(2500, filters[0]['rate_kbps']) self.assertEqual(1500, filters[0]['burst_kb']) self.assertEqual(1200, filters[0]['mtu'])
def test_add_tc_policy_class_htb(self): priv_tc_lib.add_tc_qdisc(self.device, parent=rtnl.TC_H_ROOT, kind='htb', handle='1:', namespace=self.namespace) for classid, rates in self.CLASSES.items(): priv_tc_lib.add_tc_policy_class(self.device, '1:', classid, 'htb', namespace=self.namespace, **rates) tc_classes = priv_tc_lib.list_tc_policy_classes( self.device, namespace=self.namespace) self.assertEqual(len(self.CLASSES), len(tc_classes)) for tc_class in tc_classes: handle = tc_lib._handle_from_hex_to_string(tc_class['handle']) tca_options = tc_lib._get_attr(tc_class, 'TCA_OPTIONS') tca_htb_params = tc_lib._get_attr(tca_options, 'TCA_HTB_PARMS') self.assertEqual(self.CLASSES[handle]['rate'], tca_htb_params['rate']) self.assertEqual(self.CLASSES[handle]['ceil'], tca_htb_params['ceil']) burst = tc_lib._calc_burst(self.CLASSES[handle]['rate'], tca_htb_params['buffer']) self.assertEqual(self.CLASSES[handle]['burst'], burst)
def test_delete_tc_policy_class_htb(self): priv_tc_lib.add_tc_qdisc(self.device, parent=rtnl.TC_H_ROOT, kind='htb', handle='1:', namespace=self.namespace) for classid, rates in self.CLASSES.items(): priv_tc_lib.add_tc_policy_class(self.device, '1:', classid, 'htb', namespace=self.namespace, **rates) tc_classes = priv_tc_lib.list_tc_policy_classes( self.device, namespace=self.namespace) self.assertEqual(len(self.CLASSES), len(tc_classes)) for classid in self.CLASSES: priv_tc_lib.delete_tc_policy_class(self.device, '1:', classid, namespace=self.namespace) tc_classes = priv_tc_lib.list_tc_policy_classes( self.device, namespace=self.namespace) for tc_class in tc_classes: handle = tc_lib._handle_from_hex_to_string(tc_class['handle']) self.assertIsNot(classid, handle) tc_classes = priv_tc_lib.list_tc_policy_classes( self.device, namespace=self.namespace) self.assertEqual(0, len(tc_classes))
def test_add_tc_qdisc_tbf(self): burst = 192000 rate = 320000 latency = 50000 priv_tc_lib.add_tc_qdisc( self.device, parent=rtnl.TC_H_ROOT, kind='tbf', burst=burst, rate=rate, latency=latency, namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(1, len(qdiscs)) self.assertEqual(rtnl.TC_H_ROOT, qdiscs[0]['parent']) self.assertEqual('tbf', tc_lib._get_attr(qdiscs[0], 'TCA_KIND')) tca_options = tc_lib._get_attr(qdiscs[0], 'TCA_OPTIONS') tca_tbf_parms = tc_lib._get_attr(tca_options, 'TCA_TBF_PARMS') self.assertEqual(rate, tca_tbf_parms['rate']) self.assertEqual(burst, tc_lib._calc_burst(tca_tbf_parms['rate'], tca_tbf_parms['buffer'])) self.assertEqual(latency, tc_lib._calc_latency_ms( tca_tbf_parms['limit'], burst, tca_tbf_parms['rate']) * 1000) priv_tc_lib.delete_tc_qdisc(self.device, parent=rtnl.TC_H_ROOT, namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(0, len(qdiscs))
def test_delete_tc_policy_class_htb(self): priv_tc_lib.add_tc_qdisc( self.device, parent=rtnl.TC_H_ROOT, kind='htb', handle='1:', namespace=self.namespace) for classid, rates in self.CLASSES.items(): priv_tc_lib.add_tc_policy_class( self.device, '1:', classid, 'htb', namespace=self.namespace, **rates) tc_classes = priv_tc_lib.list_tc_policy_classes( self.device, namespace=self.namespace) self.assertEqual(len(self.CLASSES), len(tc_classes)) for classid in self.CLASSES: priv_tc_lib.delete_tc_policy_class( self.device, '1:', classid, namespace=self.namespace) tc_classes = priv_tc_lib.list_tc_policy_classes( self.device, namespace=self.namespace) for tc_class in tc_classes: handle = tc_lib._handle_from_hex_to_string(tc_class['handle']) self.assertIsNot(classid, handle) tc_classes = priv_tc_lib.list_tc_policy_classes( self.device, namespace=self.namespace) self.assertEqual(0, len(tc_classes))
def add_tc_qdisc(device, qdisc_type, parent=None, handle=None, latency_ms=None, max_kbps=None, burst_kb=None, kernel_hz=None, namespace=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """Add/replace a TC qdisc on a device pyroute2 input parameters: - rate (min bw): bytes/second - burst: bytes - latency: us :param device: (string) device name :param qdisc_type: (string) qdisc type (TC_QDISC_TYPES) :param parent: (string) qdisc parent class ('root', '2:10') :param handle: (string, int) (required for HTB) major handler identifier (0xffff0000, '1', '1:', '1:0') [1] :param latency_ms: (string, int) (required for TBF) latency time in ms :param max_kbps: (string, int) (required for TBF) maximum bandwidth in kbits per second. :param burst_kb: (string, int) (required for TBF) maximum bandwidth in kbits. :param kernel_hz: (string, int) (required for TBF) kernel HZ. :param namespace: (string) (optional) namespace name [1] https://lartc.org/howto/lartc.qdisc.classful.html """ if qdisc_type and qdisc_type not in TC_QDISC_TYPES: raise qos_exc.TcLibQdiscTypeError(qdisc_type=qdisc_type, supported_qdisc_types=TC_QDISC_TYPES) args = {'kind': qdisc_type} if qdisc_type in ['htb', 'ingress']: if handle: args['handle'] = str(handle).split(':')[0] + ':0' elif qdisc_type == 'tbf': if not latency_ms or not max_kbps or not kernel_hz: raise qos_exc.TcLibQdiscNeededArguments( qdisc_type=qdisc_type, needed_arguments=['latency_ms', 'max_kbps', 'kernel_hz']) args['burst'] = int( _get_tbf_burst_value(max_kbps, burst_kb, kernel_hz) * 1024 / 8) args['rate'] = int(max_kbps * 1024 / 8) args['latency'] = latency_ms * 1000 if parent: args['parent'] = rtnl.TC_H_ROOT if parent == 'root' else parent priv_tc_lib.add_tc_qdisc(device, namespace=namespace, **args)
def test_add_tc_qdisc_ingress(self): priv_tc_lib.add_tc_qdisc(self.device, kind='ingress', namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(1, len(qdiscs)) self.assertEqual('ingress', tc_lib._get_attr(qdiscs[0], 'TCA_KIND')) self.assertEqual(rtnl.TC_H_INGRESS, qdiscs[0]['parent']) self.assertEqual(0xffff0000, qdiscs[0]['handle']) priv_tc_lib.delete_tc_qdisc(self.device, kind='ingress', namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(0, len(qdiscs))
def test_add_tc_qdisc_ingress(self): priv_tc_lib.add_tc_qdisc(self.device, kind='ingress', namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(1, len(qdiscs)) self.assertEqual('ingress', tc_lib._get_attr(qdiscs[0], 'TCA_KIND')) self.assertEqual(rtnl.TC_H_INGRESS, qdiscs[0]['parent']) self.assertEqual(0xffff0000, qdiscs[0]['handle']) priv_tc_lib.delete_tc_qdisc(self.device, kind='ingress', namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(0, len(qdiscs))
def test_add_tc_qdisc_htb_no_handle(self): priv_tc_lib.add_tc_qdisc( self.device, parent=rtnl.TC_H_ROOT, kind='htb', namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(1, len(qdiscs)) self.assertEqual(rtnl.TC_H_ROOT, qdiscs[0]['parent']) self.assertEqual(0, qdiscs[0]['handle'] & 0xFFFF) self.assertEqual('htb', tc_lib._get_attr(qdiscs[0], 'TCA_KIND')) priv_tc_lib.delete_tc_qdisc(self.device, parent=rtnl.TC_H_ROOT, namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(0, len(qdiscs))
def test_add_tc_qdisc_htb_no_handle(self): priv_tc_lib.add_tc_qdisc( self.device, parent=rtnl.TC_H_ROOT, kind='htb', namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(1, len(qdiscs)) self.assertEqual(rtnl.TC_H_ROOT, qdiscs[0]['parent']) self.assertEqual(0, qdiscs[0]['handle'] & 0xFFFF) self.assertEqual('htb', tc_lib._get_attr(qdiscs[0], 'TCA_KIND')) priv_tc_lib.delete_tc_qdisc(self.device, parent=rtnl.TC_H_ROOT, namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(0, len(qdiscs))
def add_tc_qdisc(device, qdisc_type, parent=None, handle=None, latency_ms=None, max_kbps=None, burst_kb=None, kernel_hz=None, namespace=None): """Add/replace a TC qdisc on a device pyroute2 input parameters: - rate (min bw): bytes/second - burst: bytes - latency: us :param device: (string) device name :param qdisc_type: (string) qdisc type (TC_QDISC_TYPES) :param parent: (string) qdisc parent class ('root', '2:10') :param handle: (string, int) (required for HTB) major handler identifier (0xffff0000, '1', '1:', '1:0') [1] :param latency_ms: (string, int) (required for TBF) latency time in ms :param max_kbps: (string, int) (required for TBF) maximum bandwidth in kbits per second. :param burst_kb: (string, int) (required for TBF) maximum bandwidth in kbits. :param kernel_hz: (string, int) (required for TBF) kernel HZ. :param namespace: (string) (optional) namespace name [1] https://lartc.org/howto/lartc.qdisc.classful.html """ if qdisc_type and qdisc_type not in TC_QDISC_TYPES: raise qos_exc.TcLibQdiscTypeError( qdisc_type=qdisc_type, supported_qdisc_types=TC_QDISC_TYPES) args = {'kind': qdisc_type} if qdisc_type in ['htb', 'ingress']: if handle: args['handle'] = str(handle).split(':')[0] + ':0' elif qdisc_type == 'tbf': if not latency_ms or not max_kbps or not kernel_hz: raise qos_exc.TcLibQdiscNeededArguments( qdisc_type=qdisc_type, needed_arguments=['latency_ms', 'max_kbps', 'kernel_hz']) args['burst'] = int( _get_tbf_burst_value(max_kbps, burst_kb, kernel_hz) * 1024 / 8) args['rate'] = int(max_kbps * 1024 / 8) args['latency'] = latency_ms * 1000 if parent: args['parent'] = rtnl.TC_H_ROOT if parent == 'root' else parent priv_tc_lib.add_tc_qdisc(device, namespace=namespace, **args)
def test_delete_tc_qdisc_ingress_twice(self): priv_tc_lib.add_tc_qdisc(self.device, kind='ingress', namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(1, len(qdiscs)) self.assertEqual('ingress', tc_lib._get_attr(qdiscs[0], 'TCA_KIND')) self.assertIsNone( priv_tc_lib.delete_tc_qdisc(self.device, kind='ingress', namespace=self.namespace)) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(0, len(qdiscs)) self.assertEqual( errno.EINVAL, priv_tc_lib.delete_tc_qdisc(self.device, kind='ingress', namespace=self.namespace, raise_qdisc_not_found=False))
def test_delete_tc_qdisc_ingress_twice(self): priv_tc_lib.add_tc_qdisc(self.device, kind='ingress', namespace=self.namespace) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(1, len(qdiscs)) self.assertEqual('ingress', tc_lib._get_attr(qdiscs[0], 'TCA_KIND')) self.assertIsNone( priv_tc_lib.delete_tc_qdisc(self.device, kind='ingress', namespace=self.namespace)) qdiscs = priv_tc_lib.list_tc_qdiscs(self.device, namespace=self.namespace) self.assertEqual(0, len(qdiscs)) self.assertEqual( errno.EINVAL, priv_tc_lib.delete_tc_qdisc(self.device, kind='ingress', namespace=self.namespace, raise_qdisc_not_found=False))
def test_add_tc_policy_class_htb(self): priv_tc_lib.add_tc_qdisc( self.device, parent=rtnl.TC_H_ROOT, kind='htb', handle='1:', namespace=self.namespace) for classid, rates in self.CLASSES.items(): priv_tc_lib.add_tc_policy_class( self.device, '1:', classid, 'htb', namespace=self.namespace, **rates) tc_classes = priv_tc_lib.list_tc_policy_classes( self.device, namespace=self.namespace) self.assertEqual(len(self.CLASSES), len(tc_classes)) for tc_class in tc_classes: handle = tc_lib._handle_from_hex_to_string(tc_class['handle']) tca_options = tc_lib._get_attr(tc_class, 'TCA_OPTIONS') tca_htb_params = tc_lib._get_attr(tca_options, 'TCA_HTB_PARMS') self.assertEqual(self.CLASSES[handle]['rate'], tca_htb_params['rate']) self.assertEqual(self.CLASSES[handle]['ceil'], tca_htb_params['ceil']) burst = tc_lib._calc_burst(self.CLASSES[handle]['rate'], tca_htb_params['buffer']) self.assertEqual(self.CLASSES[handle]['burst'], burst)