From 257014bb74a19274b66aeda9b66c7fe7ee0c679d Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Mon, 5 Feb 2018 17:52:10 +0000 Subject: Fix error in address input format in "_ip_range_action_partial" IP address format introduced in [1] should be unicode instead of string. "ipaddress.IPv4Address(min_value)" doesn't parse correctly the input parameter unless the parameter is in unicode format; this is valid both for Python version 2 and 3. Execution error if the parameter is a string: >>> int(ipaddress.IPv4Address('10.0.3.2')) Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python2.7/dist-packages/ipaddress.py", line 1391, in __init__ self._check_packed_address(address, 4) File "/usr/local/lib/python2.7/dist-packages/ipaddress.py", line 554, in _check_packed_address expected_len, self._version)) ipaddress.AddressValueError: '10.0.3.2' (len 8 != 4) is not permitted as an IPv4 address. Did you pass in a bytes (str in Python 2) instead of a unic [1]https://github.com/opnfv/yardstick/blob/e5775e7efbc55f116b4d4ac11ff87b8d8553247e/yardstick/network_services/traffic_profile/traffic_profile.py#L87-L88 JIRA: YARDSTICK-996 Change-Id: Ic727a79044834b181c99789f0f5efc21c68f0ff2 Signed-off-by: Rodolfo Alonso Hernandez --- .../traffic_profile/test_traffic_profile.py | 45 ++++++++--- yardstick/common/exceptions.py | 3 + .../traffic_profile/traffic_profile.py | 86 +++++++++++----------- 3 files changed, 80 insertions(+), 54 deletions(-) diff --git a/tests/unit/network_services/traffic_profile/test_traffic_profile.py b/tests/unit/network_services/traffic_profile/test_traffic_profile.py index 0bb0a88a6..37b9a08d0 100644 --- a/tests/unit/network_services/traffic_profile/test_traffic_profile.py +++ b/tests/unit/network_services/traffic_profile/test_traffic_profile.py @@ -13,14 +13,15 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# -from __future__ import absolute_import +import ipaddress -import unittest import mock +import six +import unittest from tests.unit import STL_MOCKS +from yardstick.common import exceptions as y_exc STLClient = mock.MagicMock() stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) @@ -215,11 +216,27 @@ class TestTrexProfile(unittest.TestCase): TrexProfile(TrafficProfile) self.assertEqual({}, trex_profile.generate_imix_data(False)) - def test__get_start_end_ipv6(self): - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertRaises(SystemExit, trex_profile._get_start_end_ipv6, - "1.1.1.3", "1.1.1.1") + def test__count_ip_ipv4(self): + start, end, count = TrexProfile._count_ip('1.1.1.1', '1.2.3.4') + self.assertEqual('1.1.1.1', str(start)) + self.assertEqual('1.2.3.4', str(end)) + diff = (int(ipaddress.IPv4Address(six.u('1.2.3.4'))) - + int(ipaddress.IPv4Address(six.u('1.1.1.1')))) + self.assertEqual(diff, count) + + def test__count_ip_ipv6(self): + start_ip = '0064:ff9b:0:0:0:0:9810:6414' + end_ip = '0064:ff9b:0:0:0:0:9810:6420' + start, end, count = TrexProfile._count_ip(start_ip, end_ip) + self.assertEqual(0x98106414, start) + self.assertEqual(0x98106420, end) + self.assertEqual(0x98106420 - 0x98106414, count) + + def test__count_ip_ipv6_exception(self): + start_ip = '0064:ff9b:0:0:0:0:9810:6420' + end_ip = '0064:ff9b:0:0:0:0:9810:6414' + with self.assertRaises(y_exc.IPv6RangeError): + TrexProfile._count_ip(start_ip, end_ip) def test__dscp_range_action_partial_actual_count_zero(self): traffic_profile = TrexProfile(TrafficProfile) @@ -258,13 +275,17 @@ class TestTrexProfile(unittest.TestCase): def test__general_single_action_partial(self): trex_profile = TrexProfile(TrafficProfile) - trex_profile._general_single_action_partial(ETHERNET)(SRC)(self.EXAMPLE_ETHERNET_ADDR) - self.assertEqual(self.EXAMPLE_ETHERNET_ADDR, trex_profile.ether_packet.src) + trex_profile._general_single_action_partial(ETHERNET)(SRC)( + self.EXAMPLE_ETHERNET_ADDR) + self.assertEqual(self.EXAMPLE_ETHERNET_ADDR, + trex_profile.ether_packet.src) - trex_profile._general_single_action_partial(IP)(DST)(self.EXAMPLE_IP_ADDR) + trex_profile._general_single_action_partial(IP)(DST)( + self.EXAMPLE_IP_ADDR) self.assertEqual(self.EXAMPLE_IP_ADDR, trex_profile.ip_packet.dst) - trex_profile._general_single_action_partial(IPv6)(DST)(self.EXAMPLE_IPv6_ADDR) + trex_profile._general_single_action_partial(IPv6)(DST)( + self.EXAMPLE_IPv6_ADDR) self.assertEqual(self.EXAMPLE_IPv6_ADDR, trex_profile.ip6_packet.dst) trex_profile._general_single_action_partial(UDP)(SRC_PORT)(5060) diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index a86d863db..3e0635e46 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -65,5 +65,8 @@ class HeatTemplateError(YardstickException): '"%(stack_name)"') +class IPv6RangeError(YardstickException): + message = 'Start IP "%(start_ip)s" is greater than end IP "%(end_ip)s"' + class DPDKSetupDriverError(YardstickException): message = '"igb_uio" driver is not loaded' diff --git a/yardstick/network_services/traffic_profile/traffic_profile.py b/yardstick/network_services/traffic_profile/traffic_profile.py index 3b19ff9be..8cde5e4a7 100644 --- a/yardstick/network_services/traffic_profile/traffic_profile.py +++ b/yardstick/network_services/traffic_profile/traffic_profile.py @@ -11,16 +11,16 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -""" Trex Traffic Profile definitions """ -from __future__ import absolute_import import struct import socket import logging from random import SystemRandom -import six import ipaddress +import six + +from yardstick.common import exceptions as y_exc from yardstick.network_services.traffic_profile.base import TrafficProfile from trex_stl_lib.trex_stl_client import STLStream from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats @@ -78,31 +78,32 @@ class TrexProfile(TrafficProfile): op='inc', step=1) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='mac_{}'.format(direction), - pkt_offset='Ether.{}'.format(direction)) + stl_vm_wr_flow_var = STLVmWrFlowVar( + fv_name='mac_{}'.format(direction), + pkt_offset='Ether.{}'.format(direction)) self.vm_flow_vars.append(stl_vm_wr_flow_var) return partial def _ip_range_action_partial(self, direction, count=1): # pylint: disable=unused-argument def partial(min_value, max_value, count): - ip1 = int(ipaddress.IPv4Address(min_value)) - ip2 = int(ipaddress.IPv4Address(max_value)) - actual_count = (ip2 - ip1) + _, _, actual_count = self._count_ip(min_value, max_value) if not actual_count: count = 1 elif actual_count < int(count): count = actual_count - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="ip4_{}".format(direction), - min_value=min_value, - max_value=max_value, - size=4, - limit=int(count), - seed=0x1235) + stl_vm_flow_var = STLVmFlowVarRepeatableRandom( + name="ip4_{}".format(direction), + min_value=min_value, + max_value=max_value, + size=4, + limit=int(count), + seed=0x1235) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip4_{}'.format(direction), - pkt_offset='IP.{}'.format(direction)) + stl_vm_wr_flow_var = STLVmWrFlowVar( + fv_name='ip4_{}'.format(direction), + pkt_offset='IP.{}'.format(direction)) self.vm_flow_vars.append(stl_vm_wr_flow_var) stl_vm_fix_ipv4 = STLVmFixIpv4(offset="IP") self.vm_flow_vars.append(stl_vm_fix_ipv4) @@ -111,7 +112,7 @@ class TrexProfile(TrafficProfile): def _ip6_range_action_partial(self, direction, _): def partial(min_value, max_value, count): # pylint: disable=unused-argument - min_value, max_value = self._get_start_end_ipv6(min_value, max_value) + min_value, max_value, _ = self._count_ip(min_value, max_value) stl_vm_flow_var = STLVmFlowVar(name="ip6_{}".format(direction), min_value=min_value, max_value=max_value, @@ -119,9 +120,10 @@ class TrexProfile(TrafficProfile): op='random', step=1) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip6_{}'.format(direction), - pkt_offset='IPv6.{}'.format(direction), - offset_fixup=8) + stl_vm_wr_flow_var = STLVmWrFlowVar( + fv_name='ip6_{}'.format(direction), + pkt_offset='IPv6.{}'.format(direction), + offset_fixup=8) self.vm_flow_vars.append(stl_vm_wr_flow_var) return partial @@ -149,15 +151,17 @@ class TrexProfile(TrafficProfile): elif int(count) > actual_count: count = actual_count - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="port_{}".format(field), - min_value=min_value, - max_value=max_value, - size=2, - limit=int(count), - seed=0x1235) + stl_vm_flow_var = STLVmFlowVarRepeatableRandom( + name="port_{}".format(field), + min_value=min_value, + max_value=max_value, + size=2, + limit=int(count), + seed=0x1235) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='port_{}'.format(field), - pkt_offset=self.udp[field]) + stl_vm_wr_flow_var = STLVmWrFlowVar( + fv_name='port_{}'.format(field), + pkt_offset=self.udp[field]) self.vm_flow_vars.append(stl_vm_wr_flow_var) return partial @@ -448,20 +452,18 @@ class TrexProfile(TrafficProfile): self.profile = STLProfile(self.streams) @classmethod - def _get_start_end_ipv6(cls, start_ip, end_ip): - try: - ip1 = socket.inet_pton(socket.AF_INET6, start_ip) - ip2 = socket.inet_pton(socket.AF_INET6, end_ip) - hi1, lo1 = struct.unpack('!QQ', ip1) - hi2, lo2 = struct.unpack('!QQ', ip2) - if ((hi1 << 64) | lo1) > ((hi2 << 64) | lo2): - raise SystemExit("IPv6: start_ip is greater then end_ip") - max_p1 = abs(int(lo1) - int(lo2)) - base_p1 = lo1 - except Exception as ex_error: - raise SystemExit(ex_error) - else: - return base_p1, max_p1 + base_p1 + def _count_ip(cls, start_ip, end_ip): + start = ipaddress.ip_address(six.u(start_ip)) + end = ipaddress.ip_address(six.u(end_ip)) + if start.version == 4: + return start, end, int(end) - int(start) + elif start.version == 6: + if int(start) > int(end): + raise y_exc.IPv6RangeError(start_ip=str(start), + end_ip=str(end)) + _, lo1 = struct.unpack('!QQ', start.packed) + _, lo2 = struct.unpack('!QQ', end.packed) + return lo1, lo2, lo2 - lo1 @classmethod def _get_random_value(cls, min_port, max_port): -- cgit 1.2.3-korg