aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Trautman <ctrautma@redhat.com>2018-06-18 19:13:58 +0000
committerGerrit Code Review <gerrit@opnfv.org>2018-06-18 19:13:58 +0000
commitd45a59c342f0b12f9e9f7f5652e121868b7b270b (patch)
tree8bd1acfe7530cd0153f67814232a7de79b06c4a9
parent7e3db8dbc23d91484cc608bd8cb1d42ea7729396 (diff)
parent11be4868b77d49174afafcd515d1037325796d04 (diff)
Merge "Xena_Flow_Fix: Fixes multistream of greater than 64k values"HEADmaster
-rw-r--r--docs/testing/user/configguide/trafficgen.rst8
-rw-r--r--tools/pkt_gen/xena/XenaDriver.py150
-rw-r--r--tools/pkt_gen/xena/json/xena_json.py106
-rwxr-xr-xtools/pkt_gen/xena/xena.py18
4 files changed, 211 insertions, 71 deletions
diff --git a/docs/testing/user/configguide/trafficgen.rst b/docs/testing/user/configguide/trafficgen.rst
index 42141c5..2636626 100644
--- a/docs/testing/user/configguide/trafficgen.rst
+++ b/docs/testing/user/configguide/trafficgen.rst
@@ -682,6 +682,14 @@ or modify the length of the learning by modifying the following settings.
TRAFFICGEN_XENA_CONT_PORT_LEARNING_ENABLED = False
TRAFFICGEN_XENA_CONT_PORT_LEARNING_DURATION = 3
+Multistream Modifier
+~~~~~~~~~~~~~~~~~~~~
+
+Xena has a modifier maximum value or 64k in size. For this reason when specifying
+Multistream values of greater than 64k for Layer 2 or Layer 3 it will use two
+modifiers that may be modified to a value that can be square rooted to create the
+two modifiers. You will see a log notification for the new value that was calculated.
+
MoonGen
-------
diff --git a/tools/pkt_gen/xena/XenaDriver.py b/tools/pkt_gen/xena/XenaDriver.py
index cdc8283..ac9cef1 100644
--- a/tools/pkt_gen/xena/XenaDriver.py
+++ b/tools/pkt_gen/xena/XenaDriver.py
@@ -30,6 +30,7 @@ through socket commands and returning different statistics.
"""
import locale
import logging
+import math
import socket
import struct
import sys
@@ -86,6 +87,26 @@ CMD_VERSION = 'c_versionno ?'
_LOCALE = locale.getlocale()[1]
_LOGGER = logging.getLogger(__name__)
+class ModSet(object):
+ """
+ Mod set attribute tracker
+ """
+ def __init__(self, **kwargs):
+ """ Constructor
+ All mods default to False
+ :param kwargs: Any class attribute can be set here.
+ """
+ self.mod_src_mac = False
+ self.mod_dst_mac = False
+ self.mod_src_ip = False
+ self.mod_dst_ip = False
+ self.mod_src_port = False
+ self.mod_dst_port = False
+
+ for (key, value) in kwargs.items():
+ if hasattr(self, key):
+ setattr(self, key, value)
+
class SimpleSocket(object):
"""
@@ -639,57 +660,98 @@ class XenaStream(object):
"""
return self._stream_id
- def enable_multistream(self, flows, layer):
+ def enable_multistream(self, flows, mod_class):
"""
- Basic implementation of multi stream. Enable multi stream by setting
- modifiers on the stream
- :param flows: Numbers of flows or end range
- :param layer: layer to enable multi stream as str. Acceptable values
- are L2, L3, or L4
+ Implementation of multi stream. Enable multi stream by setting
+ modifiers on the stream. If no mods are selected, src_ip mod will be used.
+ :param flows: Numbers of flows, Values greater than 65535 will square rooted
+ to the closest value. Xena mods are limited to 4 bytes.
+ :param mod_class: ModSet object
:return: True if success False otherwise
"""
if not self._header_protocol:
raise RuntimeError(
"Please set a protocol header before calling this method.")
-
- # byte offsets for setting the modifier
- offsets = {
- 'L2': [0, 6],
- 'L3': [32, 36] if 'VLAN' in self._header_protocol else [28, 32],
- 'L4': [38, 40] if 'VLAN' in self._header_protocol else [34, 36]
- }
-
- responses = list()
- if layer in offsets.keys() and flows > 0:
- command = make_port_command(
- CMD_STREAM_MODIFIER_COUNT + ' [{}]'.format(self._stream_id) +
- ' 2', self._xena_port)
- responses.append(self._manager.driver.ask_verify(command))
- command = make_port_command(
- CMD_STREAM_MODIFIER + ' [{},0] {} 0xFFFF0000 INC 1'.format(
- self._stream_id, offsets[layer][0]), self._xena_port)
- responses.append(self._manager.driver.ask_verify(command))
- command = make_port_command(
- CMD_STREAM_MODIFIER_RANGE + ' [{},0] 0 1 {}'.format(
- self._stream_id, flows), self._xena_port)
- responses.append(self._manager.driver.ask_verify(command))
- command = make_port_command(
- CMD_STREAM_MODIFIER + ' [{},1] {} 0xFFFF0000 INC 1'.format(
- self._stream_id, offsets[layer][1]), self._xena_port)
- responses.append(self._manager.driver.ask_verify(command))
- command = make_port_command(
- CMD_STREAM_MODIFIER_RANGE + ' [{},1] 0 1 {}'.format(
- self._stream_id, flows), self._xena_port)
- responses.append(self._manager.driver.ask_verify(command))
- return all(responses) # return True if they all worked
- elif flows < 1:
- _LOGGER.warning(
- 'No flows specified in enable multistream. Bypassing...')
- return False
+ # maximum value for a Xena modifier is 65535 (unsigned int). If flows
+ # is greater than 65535 we have to do two mods getting as close as we
+ # can with square rooting the flow count.
+ if flows > 4294836225:
+ _LOGGER.debug('Flow mods exceeds highest value, changing to 4294836225')
+ flows = 4294836225
+ if flows <= 65535:
+ mod1 = flows
+ mod2 = 0
else:
- raise NotImplementedError(
- "Non-implemented stream layer in method enable multistream ",
- "layer=", layer)
+ mod1, mod2 = int(math.sqrt(flows)), int(math.sqrt(flows))
+ _LOGGER.debug('Flow count modified to %s', mod1*mod2)
+ offset_list = list()
+ if not any([mod_class.mod_src_mac, mod_class.mod_dst_mac, mod_class.mod_src_ip,
+ mod_class.mod_dst_ip, mod_class.mod_src_port, mod_class.mod_dst_port]):
+ # no mods were selected, default to src ip only
+ mod_class.mod_src_ip = True
+ if mod_class.mod_src_mac:
+ offset_list.append(3)
+ if mod_class.mod_dst_mac:
+ offset_list.append(9)
+ if mod_class.mod_src_ip:
+ offset_list.append(32 if 'VLAN' in self._header_protocol else 28)
+ if mod_class.mod_dst_ip:
+ offset_list.append(36 if 'VLAN' in self._header_protocol else 32)
+ if mod_class.mod_src_port:
+ offset_list.append(38 if 'VLAN' in self._header_protocol else 34)
+ if mod_class.mod_dst_port:
+ offset_list.append(40 if 'VLAN' in self._header_protocol else 36)
+ # calculate how many mods we have to do
+ countertotal = len(offset_list)
+ if mod2:
+ # to handle flows greater than 65535 we will need more mods for
+ # layer 2 and 3
+ for mod in [mod_class.mod_src_mac, mod_class.mod_dst_mac,
+ mod_class.mod_src_ip, mod_class.mod_dst_ip]:
+ if mod:
+ countertotal += 1
+ command = make_port_command(
+ CMD_STREAM_MODIFIER_COUNT + ' [{}]'.format(self._stream_id) +
+ ' {}'.format(countertotal), self._xena_port)
+ responses = list()
+ responses.append(self._manager.driver.ask_verify(command))
+ modcounter = 0
+ for offset in offset_list:
+ if (mod_class.mod_dst_port or mod_class.mod_src_port) and \
+ (offset >= 38 if 'VLAN' in self._header_protocol else 34):
+ # only do a 1 mod for udp ports at max 65535
+ newmod1 = 65535 if flows >= 65535 else flows
+ command = make_port_command(
+ CMD_STREAM_MODIFIER + ' [{},{}] {} 0xFFFF0000 INC 1'.format(
+ self._stream_id, modcounter, offset), self._xena_port)
+ responses.append(self._manager.driver.ask_verify(command))
+ command = make_port_command(
+ CMD_STREAM_MODIFIER_RANGE + ' [{},{}] 0 1 {}'.format(
+ self._stream_id, modcounter, newmod1 - 1), self._xena_port)
+ responses.append(self._manager.driver.ask_verify(command))
+ else:
+ command = make_port_command(
+ CMD_STREAM_MODIFIER + ' [{},{}] {} 0xFFFF0000 INC 1'.format(
+ self._stream_id, modcounter, offset), self._xena_port)
+ responses.append(self._manager.driver.ask_verify(command))
+ command = make_port_command(
+ CMD_STREAM_MODIFIER_RANGE + ' [{},{}] 0 1 {}'.format(
+ self._stream_id, modcounter, mod1 - 1), self._xena_port)
+ responses.append(self._manager.driver.ask_verify(command))
+ # if we have a second modifier set the modifier to mod2 and to
+ # incremement once every full rotation of mod 1
+ if mod2:
+ modcounter += 1
+ command = make_port_command(
+ CMD_STREAM_MODIFIER + ' [{},{}] {} 0xFFFF0000 INC {}'.format(
+ self._stream_id, modcounter, offset-2, mod1), self._xena_port)
+ responses.append(self._manager.driver.ask_verify(command))
+ command = make_port_command(
+ CMD_STREAM_MODIFIER_RANGE + ' [{},{}] 0 1 {}'.format(
+ self._stream_id, modcounter, mod2), self._xena_port)
+ responses.append(self._manager.driver.ask_verify(command))
+ modcounter += 1
+ return all(responses) # return True if they all worked
def get_stream_data(self):
"""
diff --git a/tools/pkt_gen/xena/json/xena_json.py b/tools/pkt_gen/xena/json/xena_json.py
index df2aa55..e56b412 100644
--- a/tools/pkt_gen/xena/json/xena_json.py
+++ b/tools/pkt_gen/xena/json/xena_json.py
@@ -26,6 +26,7 @@ Xena JSON module
from collections import OrderedDict
import locale
import logging
+import math
import os
from tools.pkt_gen.xena.json import json_utilities
@@ -71,30 +72,87 @@ class XenaJSON(object):
3: ('Dest IP Addr', 'Src IP Addr'),
4: ('Dest Port', 'Src Port')
}
- segments = [
- {
- "Offset": 0,
- "Mask": "//8=", # mask of 255/255
- "Action": "INC",
- "StartValue": 0,
- "StopValue": stop_value,
- "StepValue": 1,
- "RepeatCount": 1,
- "SegmentId": seg_uuid,
- "FieldName": field_name[int(layer)][0]
- },
- {
- "Offset": 0,
- "Mask": "//8=", # mask of 255/255
- "Action": "INC",
- "StartValue": 0,
- "StopValue": stop_value,
- "StepValue": 1,
- "RepeatCount": 1,
- "SegmentId": seg_uuid,
- "FieldName": field_name[int(layer)][1]
- }
- ]
+
+ if stop_value > 4294836225:
+ _LOGGER.debug('Flow mods exceeds highest value, changing to 4294836225')
+ stop_value = 4294836225
+
+ if stop_value <= 65535 or layer == 4:
+ segments = [
+ {
+ "Offset": 0 if layer == 4 else 2,
+ "Mask": "//8=", # mask of 255/255
+ "Action": "INC",
+ "StartValue": 0,
+ "StopValue": stop_value - 1,
+ "StepValue": 1,
+ "RepeatCount": 1,
+ "SegmentId": seg_uuid,
+ "FieldName": field_name[int(layer)][0]
+ },
+ {
+ "Offset": 0 if layer == 4 else 2,
+ "Mask": "//8=", # mask of 255/255
+ "Action": "INC",
+ "StartValue": 0,
+ "StopValue": stop_value - 1,
+ "StepValue": 1,
+ "RepeatCount": 1,
+ "SegmentId": seg_uuid,
+ "FieldName": field_name[int(layer)][1]
+ }
+ ]
+ else:
+ stop_value = int(math.sqrt(stop_value))
+ _LOGGER.debug('Flow count modified to %s', stop_value * stop_value)
+ segments = [
+ {
+ "Offset": 0 if layer == 3 else 1,
+ "Mask": "//8=", # mask of 255/255
+ "Action": "INC",
+ "StartValue": 0,
+ "StopValue": stop_value - 1,
+ "StepValue": 1,
+ "RepeatCount": stop_value,
+ "SegmentId": seg_uuid,
+ "FieldName": field_name[int(layer)][0]
+ },
+ {
+ "Offset": 2 if layer == 3 else 3,
+ "Mask": "//8=", # mask of 255/255
+ "Action": "INC",
+ "StartValue": 0,
+ "StopValue": stop_value - 1,
+ "StepValue": 1,
+ "RepeatCount": 1,
+ "SegmentId": seg_uuid,
+ "FieldName": field_name[int(layer)][0]
+ },
+ {
+ "Offset": 0 if layer == 3 else 1,
+ "Mask": "//8=", # mask of 255/255
+ "Action": "INC",
+ "StartValue": 0,
+ "StopValue": stop_value - 1,
+ "StepValue": 1,
+ "RepeatCount": stop_value,
+ "SegmentId": seg_uuid,
+ "FieldName": field_name[int(layer)][1]
+ },
+ {
+ "Offset": 2 if layer == 3 else 3,
+ "Mask": "//8=", # mask of 255/255
+ "Action": "INC",
+ "StartValue": 0,
+ "StopValue": stop_value - 1,
+ "StepValue": 1,
+ "RepeatCount": 1,
+ "SegmentId": seg_uuid,
+ "FieldName": field_name[int(layer)][1]
+ }
+ ]
+
+
self.json_data['StreamProfileHandler']['EntityList'][entity][
'StreamConfig']['HwModifiers'] = (segments)
diff --git a/tools/pkt_gen/xena/xena.py b/tools/pkt_gen/xena/xena.py
index 3386407..3adc829 100755
--- a/tools/pkt_gen/xena/xena.py
+++ b/tools/pkt_gen/xena/xena.py
@@ -39,6 +39,7 @@ from tools.pkt_gen.trafficgen.trafficgen import ITrafficGenerator
from tools.pkt_gen.xena.XenaDriver import (
aggregate_stats,
line_percentage,
+ ModSet,
XenaSocketDriver,
XenaManager,
)
@@ -283,6 +284,9 @@ class Xena(ITrafficGenerator):
j_file = XenaJSONBlocks()
elif bonding_test:
j_file = XenaJSONPairs()
+ else: # just default to mesh config
+ self._logger.error('Invalid traffic type defaulting to Mesh config')
+ j_file = XenaJSONMesh()
j_file.set_chassis_info(
settings.getValue('TRAFFICGEN_XENA_IP'),
@@ -346,7 +350,7 @@ class Xena(ITrafficGenerator):
id=self._params['traffic']['vlan']['cfi'],
prio=self._params['traffic']['vlan']['priority'])
j_file.add_header_segments(
- flows=self._params['traffic']['multistream'],
+ flows=self._params['traffic']['multistream'] - 1,
multistream_layer=self._params['traffic']['stream_type'])
j_file.write_config(os.path.join(
@@ -454,9 +458,17 @@ class Xena(ITrafficGenerator):
port.micro_tpld_enable()
if self._params['traffic']['multistream']:
+ if self._params['traffic']['stream_type'] == 'L2':
+ modobj = ModSet(mod_src_mac=True, mod_dst_mac=True)
+ elif self._params['traffic']['stream_type'] == 'L3':
+ modobj = ModSet(mod_src_ip=True, mod_dst_ip=True)
+ elif self._params['traffic']['stream_type'] == 'L4':
+ modobj = ModSet(mod_src_port=True, mod_dst_port=True)
+ else:
+ self._logger.error('Invalid segment for multistream. Using L2..')
+ modobj = ModSet(mod_src_mac=True, mod_dst_mac=True)
stream.enable_multistream(
- flows=self._params['traffic']['multistream'],
- layer=self._params['traffic']['stream_type'])
+ flows=self._params['traffic']['multistream'], mod_class=modobj)
s1_p0 = self.xmanager.ports[0].add_stream()
setup_stream(s1_p0, self.xmanager.ports[0], 0)