Ido Barkan has uploaded a new change for review. Change subject: Support VLAN hardware offloading in hostQOS ......................................................................
Support VLAN hardware offloading in hostQOS Apparently, the tc filter that VDSM uses to classify 802.1q traffic is not working when the kernel offloads VLAN tagging to the underlying physical nic. This is because the VLAN field in the link layer header is only added by the hardware and is not present by the time the filter inspects it. Since the filter uses a straight forward matcher which only looks at the headers it fails to match and the packets aren't classified to the desired queuing discipline (qdisc). Using a kernel packet meta data matcher should work regardless of VLAN tagging offloading is enabled. Change-Id: I667a9f38f4314da309685f6ba247f705a2e9c23e Signed-off-by: Ido Barkan <[email protected]> --- M tests/tcTests.py M vdsm/network/configurators/qos.py M vdsm/network/tc/filter.py 3 files changed, 50 insertions(+), 11 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/32/47332/1 diff --git a/tests/tcTests.py b/tests/tcTests.py index f14d5a3..ade7b8e 100644 --- a/tests/tcTests.py +++ b/tests/tcTests.py @@ -417,8 +417,9 @@ self._assert_parent([vlan_qdisc], vlan_class) self.assertEqual(len(tc_filters.tagged_filters), 1) - self.assertEqual(tc_filters.tagged_filters[0]['u32']['flowid'], - ':%x' % vlan.tag) + self.assertEqual( + int(tc_filters.tagged_filters[0]['basic']['value']), + vlan.tag) def test_multiple_vlans(self): with vlan_device(self.device_name, tag=16) as vlan1: @@ -441,7 +442,7 @@ self.assertEqual(len(tc_filters.tagged_filters), 2) current_tagged_filters_flow_id = set( - f['u32']['flowid'] for f in tc_filters.tagged_filters) + f['basic']['flowid'] for f in tc_filters.tagged_filters) expected_flow_ids = set(':%x' % v.tag for v in (vlan1, vlan2)) self.assertEqual(current_tagged_filters_flow_id, expected_flow_ids) @@ -598,10 +599,7 @@ def _tagged_filters(self, filters): def tagged(f): - flow_id = f.get('u32', {}).get('flowid') - if flow_id is not None and flow_id != ':%x' % qos._NON_VLANNED_ID: - return True - return False + return f.get('basic', {}).get('object') == 'vlan' return list(f for f in filters if tagged(f)) diff --git a/vdsm/network/configurators/qos.py b/vdsm/network/configurators/qos.py index 7806239..77350dd 100644 --- a/vdsm/network/configurators/qos.py +++ b/vdsm/network/configurators/qos.py @@ -128,8 +128,13 @@ 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 = ':' + 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 - 'u32' in filt and filt['u32'].get('flowid') == flow_id] + 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: @@ -157,8 +162,9 @@ def _add_vlan_filter(dev, vlan_tag, root_qdisc_handle, class_id): tc.filter.replace(dev, parent=root_qdisc_handle, protocol='802.1q', pref=vlan_tag, - u32=['match', 'u16', '0x%x' % vlan_tag, '0xFFF', 'at', - '-4', 'flowid', '0x' + class_id]) + basic=['match', 'meta(vlan eq %s)' % vlan_tag, + 'flowid', '0x' + class_id] + ) def _add_non_vlanned_filter(dev, root_qdisc_handle): diff --git a/vdsm/network/tc/filter.py b/vdsm/network/tc/filter.py index 9b3913c..778e7ed 100644 --- a/vdsm/network/tc/filter.py +++ b/vdsm/network/tc/filter.py @@ -130,6 +130,27 @@ return data +def _parse_ematch(tokens): + """Parses tokens describing a raw ematch, (see man tc-ematch) e.g., + 'meta(vlan mask 0x00000000 eq 16)' into a data dictionary. + currently only a single 'meta' module predicate is supported""" + data = {} + for token in tokens: + if token == _parser.LINE_DELIMITER: # line break + continue + elif token == 'handle': + data[token] = _parser.parse_str(tokens) + elif token == 'flowid': + data['flowid'] = _parser.parse_str(tokens) + elif '(' in token: + module, first_arg = token.split('(') + if module != 'meta': + _parser.parse_skip_line(tokens) + data['module'] = module + data.update(_parse_ematch_match(first_arg, tokens)) + return data + + _parse_match_ip = _parser.parse_skip_line # Unimplemented, skip line @@ -142,6 +163,20 @@ _parser.consume(tokens, 'at') offset = _parser.parse_int(tokens) return {'value': value, 'mask': mask, 'offset': offset} + + +def _parse_ematch_match(first_arg, tokens): + data = {} + if first_arg in ('random', 'loadavg_1', 'nf_mark', 'vlan', 'sk_rcvbuf', + 'sk_snd_queue'): + data['object'] = first_arg + for token in tokens: + if token in ('eq', 'lt', 'gt'): + data['relation'] = token + data['value'] = next(tokens).strip(')') + elif token == 'mask': + data['mask'] = _parser.parse_str(tokens) + return data def _parse_action(tokens): @@ -199,5 +234,5 @@ 'skbedit': None, 'xt': None} -_CLASSES = {'basic': None, 'cgroup': None, 'flow': None, 'fw': None, +_CLASSES = {'basic': _parse_ematch, 'cgroup': None, 'flow': None, 'fw': None, 'route': None, 'rsvp': None, 'tcindex': None, 'u32': _parse_u32} -- To view, visit https://gerrit.ovirt.org/47332 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I667a9f38f4314da309685f6ba247f705a2e9c23e Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Ido Barkan <[email protected]> _______________________________________________ vdsm-patches mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches
