From 70eef8dd6ef160d3782984742fbc7958a35c03c7 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Fri, 20 Jul 2018 16:40:29 +0100 Subject: Improve NetworkServiceTestCase._get_ip_flow_range() function Improve the method to calculate the CIDR IP address range (first one, last one). IPv4Network or IPv6Network hosts() is an iterator throught the list of valid IPs. If the network is too big, the generation of a list [1] can be very expensive. [1]https://github.com/opnfv/yardstick/blob/master/yardstick/benchmark/scenarios/networking/vnf_generic.py#L90 JIRA: YARDSTICK-1339 Change-Id: I9352b2e7ff4925c246df8b40ecf43e8dc96c42d2 Signed-off-by: Rodolfo Alonso Hernandez --- .../benchmark/scenarios/networking/vnf_generic.py | 49 ++++++++++--------- .../scenarios/networking/test_vnf_generic.py | 56 ++++++++++++++-------- 2 files changed, 59 insertions(+), 46 deletions(-) diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py index 7a11d3e76..a7557733b 100644 --- a/yardstick/benchmark/scenarios/networking/vnf_generic.py +++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py @@ -64,37 +64,36 @@ class NetworkServiceTestCase(scenario_base.Scenario): self._mq_ids = [] def _get_ip_flow_range(self, ip_start_range): + """Retrieve a CIDR first and last viable IPs - # IP range is specified as 'x.x.x.x-y.y.y.y' + :param ip_start_range: could be the IP range itself or a dictionary + with the host name and the port. + :return: (str) IP range (min, max) with this format "x.x.x.x-y.y.y.y" + """ if isinstance(ip_start_range, six.string_types): return ip_start_range - node_name, range_or_interface = next(iter(ip_start_range.items()), (None, '0.0.0.0')) + node_name, range_or_interface = next(iter(ip_start_range.items()), + (None, '0.0.0.0')) if node_name is None: - # we are manually specifying the range - ip_addr_range = range_or_interface + return range_or_interface + + node = self.context_cfg['nodes'].get(node_name, {}) + interface = node.get('interfaces', {}).get(range_or_interface) + if interface: + ip = interface['local_ip'] + mask = interface['netmask'] else: - node = self.context_cfg["nodes"].get(node_name, {}) - try: - # the ip_range is the interface name - interface = node.get("interfaces", {})[range_or_interface] - except KeyError: - ip = "0.0.0.0" - mask = "255.255.255.0" - else: - ip = interface["local_ip"] - # we can't default these values, they must both exist to be valid - mask = interface["netmask"] - - ipaddr = ipaddress.ip_network(six.text_type('{}/{}'.format(ip, mask)), strict=False) - hosts = list(ipaddr.hosts()) - if len(hosts) > 2: - # skip the first host in case of gateway - ip_addr_range = "{}-{}".format(hosts[1], hosts[-1]) - else: - LOG.warning("Only single IP in range %s", ipaddr) - # fall back to single IP range - ip_addr_range = ip + ip = '0.0.0.0' + mask = '255.255.255.0' + + ipaddr = ipaddress.ip_network( + six.text_type('{}/{}'.format(ip, mask)), strict=False) + if ipaddr.prefixlen + 2 < ipaddr.max_prefixlen: + ip_addr_range = '{}-{}'.format(ipaddr[2], ipaddr[-2]) + else: + LOG.warning('Only single IP in range %s', ipaddr) + ip_addr_range = ip return ip_addr_range def _get_traffic_flow(self): diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py index cdb91f66d..49578b383 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py @@ -358,35 +358,49 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.assertIsNotNone(self.topology) def test__get_ip_flow_range_string(self): - self.scenario_cfg["traffic_options"]["flow"] = \ - self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml") result = '152.16.100.2-152.16.100.254' self.assertEqual(result, self.s._get_ip_flow_range( '152.16.100.2-152.16.100.254')) - def test__get_ip_flow_range(self): - self.scenario_cfg["traffic_options"]["flow"] = \ - self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml") - result = '152.16.100.2-152.16.100.254' - self.assertEqual(result, self.s._get_ip_flow_range({"tg__1": 'xe0'})) + def test__get_ip_flow_range_no_nodes(self): + self.assertEqual('0.0.0.0', self.s._get_ip_flow_range({})) - @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.ipaddress') - def test__get_ip_flow_range_no_node_data(self, mock_ipaddress): - scenario_cfg = deepcopy(self.scenario_cfg) - scenario_cfg["traffic_options"]["flow"] = \ - self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml") + def test__get_ip_flow_range_no_node_data(self): + node_data = {'tg__0': 'xe0'} + self.s.context_cfg['nodes']['tg__0'] = {} + result = self.s._get_ip_flow_range(node_data) + self.assertEqual('0.0.0.2-0.0.0.254', result) - mock_ipaddress.ip_network.return_value = ipaddr = mock.Mock() - ipaddr.hosts.return_value = [] + def test__et_ip_flow_range_ipv4(self): + node_data = {'tg__0': 'xe0'} + self.s.context_cfg['nodes']['tg__0'] = { + 'interfaces': { + 'xe0': {'local_ip': '192.168.1.15', + 'netmask': '255.255.255.128'} + } + } + result = self.s._get_ip_flow_range(node_data) + self.assertEqual('192.168.1.2-192.168.1.126', result) - expected = '0.0.0.0' - result = self.s._get_ip_flow_range({"tg__2": 'xe0'}) - self.assertEqual(result, expected) + def test__get_ip_flow_range_ipv4_mask_30(self): + node_data = {'tg__0': 'xe0'} + self.s.context_cfg['nodes']['tg__0'] = { + 'interfaces': { + 'xe0': {'local_ip': '192.168.1.15', 'netmask': 30} + } + } + result = self.s._get_ip_flow_range(node_data) + self.assertEqual('192.168.1.15', result) - def test__get_ip_flow_range_no_nodes(self): - expected = '0.0.0.0' - result = self.s._get_ip_flow_range({}) - self.assertEqual(result, expected) + def test__get_ip_flow_range_ipv6(self): + node_data = {'tg__0': 'xe0'} + self.s.context_cfg['nodes']['tg__0'] = { + 'interfaces': { + 'xe0': {'local_ip': '2001::11', 'netmask': 64} + } + } + result = self.s._get_ip_flow_range(node_data) + self.assertEqual('2001::2-2001::ffff:ffff:ffff:fffe', result) def test___get_traffic_flow(self): self.scenario_cfg["traffic_options"]["flow"] = \ -- cgit 1.2.3-korg From abd5b952f42f429f6f1b59f3f7822cc92da0f6f6 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Mon, 23 Jul 2018 17:00:52 +0100 Subject: Add IP mask to IxNetwork configuration Assign the IP mask to IxNetwork configuration, depending on the IP range provided by the user in the traffic profile. In case of single IP, a default mask will be provided: - IP_VERSION_4_MASK = 24 - IP_VERSION_6_MASK = 64 JIRA: YARDSTICK-1351 Change-Id: I029473ab8b9966a76cf559ffef53b34ca11462ad Signed-off-by: Rodolfo Alonso Hernandez --- yardstick/common/utils.py | 8 ++++ .../libs/ixia_libs/ixnet/ixnet_api.py | 14 ++++--- .../traffic_profile/ixia_rfc2544.py | 24 ++++++++--- yardstick/tests/unit/common/test_utils.py | 14 +++++++ .../libs/ixia_libs/test_ixnet_api.py | 47 +++++----------------- .../traffic_profile/test_ixia_rfc2544.py | 16 ++++++++ 6 files changed, 75 insertions(+), 48 deletions(-) diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py index 85cecc714..83ddbd470 100644 --- a/yardstick/common/utils.py +++ b/yardstick/common/utils.py @@ -335,6 +335,14 @@ def ip_to_hex(ip_addr, separator=''): return separator.join('{:02x}'.format(octet) for octet in address.packed) +def get_mask_from_ip_range(ip_low, ip_high): + _ip_low = ipaddress.ip_address(ip_low) + _ip_high = ipaddress.ip_address(ip_high) + _ip_low_int = int(_ip_low) + _ip_high_int = int(_ip_high) + return _ip_high.max_prefixlen - (_ip_high_int ^ _ip_low_int).bit_length() + + def try_int(s, *args): """Convert to integer if possible.""" try: diff --git a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py index cee768dba..9058fa78c 100644 --- a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py +++ b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py @@ -33,8 +33,8 @@ PROTO_UDP = 'udp' PROTO_TCP = 'tcp' PROTO_VLAN = 'vlan' -IP_VERSION_4_MASK = '0.0.0.255' -IP_VERSION_6_MASK = '0:0:0:0:0:0:0:ff' +IP_VERSION_4_MASK = 24 +IP_VERSION_6_MASK = 64 TRAFFIC_STATUS_STARTED = 'started' TRAFFIC_STATUS_STOPPED = 'stopped' @@ -424,15 +424,17 @@ class IxNextgen(object): # pragma: no cover raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id) count = traffic_param['outer_l3']['count'] - srcip4 = str(traffic_param['outer_l3']['srcip4']) - dstip4 = str(traffic_param['outer_l3']['dstip4']) + srcip = str(traffic_param['outer_l3']['srcip']) + dstip = str(traffic_param['outer_l3']['dstip']) + srcmask = traffic_param['outer_l3']['srcmask'] or IP_VERSION_4_MASK + dstmask = traffic_param['outer_l3']['dstmask'] or IP_VERSION_4_MASK self._update_ipv4_address( self._get_stack_item(fg_id, PROTO_IPV4)[0], - 'srcIp', srcip4, 1, IP_VERSION_4_MASK, count) + 'srcIp', srcip, 1, srcmask, count) self._update_ipv4_address( self._get_stack_item(fg_id, PROTO_IPV4)[0], - 'dstIp', dstip4, 1, IP_VERSION_4_MASK, count) + 'dstIp', dstip, 1, dstmask, count) def _build_stats_map(self, view_obj, name_map): return {data_yardstick: self.ixnet.execute( diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py index 49bac27e4..c32e9d8c9 100644 --- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py +++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py @@ -14,6 +14,7 @@ import logging +from yardstick.common import utils from yardstick.network_services.traffic_profile import base as tp_base from yardstick.network_services.traffic_profile import trex_traffic_profile @@ -33,6 +34,14 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): self.rate = self.config.frame_rate self.rate_unit = self.config.rate_unit + def _get_ip_and_mask(self, ip_range): + _ip_range = ip_range.split('-') + if len(_ip_range) == 1: + return _ip_range[0], None + + mask = utils.get_mask_from_ip_range(_ip_range[0], _ip_range[1]) + return _ip_range[0], mask + def _get_ixia_traffic_profile(self, profile_data, mac=None): mac = {} if mac is None else mac result = {} @@ -50,14 +59,17 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): port_id = value.get('id', 1) port_index = port_id - 1 - try: - ip = value['outer_l3v6'] - except KeyError: + + if value.get('outer_l3v4'): ip = value['outer_l3v4'] src_key, dst_key = 'srcip4', 'dstip4' else: + ip = value['outer_l3v6'] src_key, dst_key = 'srcip6', 'dstip6' + srcip, srcmask = self._get_ip_and_mask(ip[src_key]) + dstip, dstmask = self._get_ip_and_mask(ip[dst_key]) + result[traffickey] = { 'bidir': False, 'id': port_id, @@ -73,8 +85,10 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): 'count': ip['count'], 'dscp': ip['dscp'], 'ttl': ip['ttl'], - src_key: ip[src_key].split("-")[0], - dst_key: ip[dst_key].split("-")[0], + 'srcip': srcip, + 'dstip': dstip, + 'srcmask': srcmask, + 'dstmask': dstmask, 'type': key, 'proto': ip['proto'], }, diff --git a/yardstick/tests/unit/common/test_utils.py b/yardstick/tests/unit/common/test_utils.py index 446afdd38..bf0b5181a 100644 --- a/yardstick/tests/unit/common/test_utils.py +++ b/yardstick/tests/unit/common/test_utils.py @@ -1196,6 +1196,20 @@ class TestUtilsIpAddrMethods(ut_base.BaseUnitTestCase): for value in chain(value_iter, self.INVALID_IP_ADDRESS_STR_LIST): self.assertEqual(utils.ip_to_hex(value), value) + def test_get_mask_from_ip_range_ipv4(self): + ip_str = '1.1.1.1' + for mask in range(8, 30): + ip = ipaddress.ip_network(ip_str + '/' + str(mask), strict=False) + result = utils.get_mask_from_ip_range(ip[2], ip[-2]) + self.assertEqual(mask, result) + + def test_get_mask_from_ip_range_ipv6(self): + ip_str = '2001::1' + for mask in range(8, 120): + ip = ipaddress.ip_network(ip_str + '/' + str(mask), strict=False) + result = utils.get_mask_from_ip_range(ip[2], ip[-2]) + self.assertEqual(mask, result) + class SafeDecodeUtf8TestCase(ut_base.BaseUnitTestCase): diff --git a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py index afa4cc3dc..458ea0f12 100644 --- a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py +++ b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py @@ -36,25 +36,12 @@ TRAFFIC_PARAMETERS = { 'outer_l3': { 'count': 512, 'dscp': 0, - 'dstip4': '152.16.40.20', 'proto': 'udp', - 'srcip4': '152.16.100.20', - 'ttl': 32 - }, - 'outer_l3v4': { - 'dscp': 0, - 'dstip4': '152.16.40.20', - 'proto': 'udp', - 'srcip4': '152.16.100.20', - 'ttl': 32 - }, - 'outer_l3v6': { - 'count': 1024, - 'dscp': 0, - 'dstip4': '152.16.100.20', - 'proto': 'udp', - 'srcip4': '152.16.40.20', - 'ttl': 32 + 'ttl': 32, + 'dstip': '152.16.40.20', + 'srcip': '152.16.100.20', + 'dstmask': 24, + 'srcmask': 24 }, 'outer_l4': { 'dstport': '2001', @@ -74,26 +61,12 @@ TRAFFIC_PARAMETERS = { 'outer_l3': { 'count': 1024, 'dscp': 0, - 'dstip4': '152.16.100.20', - 'proto': 'udp', - 'srcip4': '152.16.40.20', - 'ttl': 32 - }, - 'outer_l3v4': { - 'count': 1024, - 'dscp': 0, - 'dstip4': '152.16.100.20', - 'proto': 'udp', - 'srcip4': '152.16.40.20', - 'ttl': 32 - }, - 'outer_l3v6': { - 'count': 1024, - 'dscp': 0, - 'dstip4': '152.16.100.20', 'proto': 'udp', - 'srcip4': '152.16.40.20', - 'ttl': 32 + 'ttl': 32, + 'dstip': '2001::10', + 'srcip': '2021::10', + 'dstmask': 64, + 'srcmask': 64 }, 'outer_l4': { 'dstport': '1234', diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py index 4ea19a121..1a33304a5 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py @@ -446,6 +446,22 @@ class TestIXIARFC2544Profile(unittest.TestCase): r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile(t_profile_data) self.assertEqual(12345678, r_f_c2544_profile.rate) + def test__get_ip_and_mask_range(self): + ip_range = '1.2.0.2-1.2.255.254' + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) + ip, mask = r_f_c2544_profile._get_ip_and_mask(ip_range) + self.assertEqual('1.2.0.2', ip) + self.assertEqual(16, mask) + + def test__get_ip_and_mask_single(self): + ip_range = '192.168.1.10' + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) + ip, mask = r_f_c2544_profile._get_ip_and_mask(ip_range) + self.assertEqual('192.168.1.10', ip) + self.assertIsNone(mask) + def test__get_ixia_traffic_profile_default_args(self): r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( self.TRAFFIC_PROFILE) -- cgit 1.2.3-korg