# License for the specific language governing permissions and limitations
# under the License.
#
+from mock import patch
+import pytest
-from attrdict import AttrDict
+from .mock_trex import no_op
+
+import json
import logging
+import sys
+from attrdict import AttrDict
from nfvbench.config import config_loads
-from nfvbench.connection import SSH
from nfvbench.credentials import Credentials
from nfvbench.fluentd import FluentLogHandler
import nfvbench.log
-from nfvbench.network import Interface
-from nfvbench.network import Network
-from nfvbench.specs import Encaps
+import nfvbench.nfvbench
+from nfvbench.traffic_client import Device
+from nfvbench.traffic_client import GeneratorConfig
+from nfvbench.traffic_client import IpBlock
+from nfvbench.traffic_client import TrafficClient
+from nfvbench.traffic_client import TrafficClientException
import nfvbench.traffic_gen.traffic_utils as traffic_utils
-import os
-import pytest
-
-__location__ = os.path.realpath(os.path.join(os.getcwd(),
- os.path.dirname(__file__)))
-
-
-@pytest.fixture
-def ssh(monkeypatch):
- def mock_init(self, ssh_access, *args, **kwargs):
- self.ssh_access = ssh_access
- if ssh_access.private_key:
- self.pkey = self._get_pkey(ssh_access.private_key)
- else:
- self.pkey = None
- self._client = False
- self.connect_timeout = 2
- self.connect_retry_count = 1
- self.connect_retry_wait_sec = 1
- super(SSH, self).__init__()
-
- monkeypatch.setattr(SSH, '__init__', mock_init)
-
-
-@pytest.fixture
-def openstack_vxlan_spec():
- return AttrDict(
- {
- 'openstack': AttrDict({
- 'vswitch': "VTS",
- 'encaps': Encaps.VxLAN}
- ),
- 'run_spec': AttrDict({
- 'use_vpp': True
- })
- }
- )
-
-# =========================================================================
-# PVP Chain tests
-# =========================================================================
-
-def test_chain_interface():
- iface = Interface('testname', 'vpp', tx_packets=1234, rx_packets=4321)
- assert iface.name == 'testname'
- assert iface.device == 'vpp'
- assert iface.get_packet_count('tx') == 1234
- assert iface.get_packet_count('rx') == 4321
- assert iface.get_packet_count('wrong_key') == 0
-
-
-@pytest.fixture(scope='session')
-def iface1():
- return Interface('iface1', 'trex', tx_packets=10000, rx_packets=1234)
-
-
-@pytest.fixture(scope='session')
-def iface2():
- return Interface('iface2', 'n9k', tx_packets=1234, rx_packets=9901)
-
-
-@pytest.fixture(scope='session')
-def iface3():
- return Interface('iface3', 'n9k', tx_packets=9900, rx_packets=1234)
-
-
-@pytest.fixture(scope='session')
-def iface4():
- return Interface('iface4', 'vpp', tx_packets=1234, rx_packets=9801)
-
-
-@pytest.fixture(scope='session')
-def net1(iface1, iface2, iface3, iface4):
- return Network([iface1, iface2, iface3, iface4], reverse=False)
-
-
-@pytest.fixture(scope='session')
-def net2(iface1, iface2, iface3):
- return Network([iface1, iface2, iface3], reverse=True)
-
-
-def test_chain_network(net1, net2, iface1, iface2, iface3, iface4):
- assert [iface1, iface2, iface3, iface4] == net1.get_interfaces()
- assert [iface3, iface2, iface1] == net2.get_interfaces()
- net2.add_interface(iface4)
- assert [iface4, iface3, iface2, iface1] == net2.get_interfaces()
-
-
-"""
-def test_chain_analysis(net1, monkeypatch, openstack_vxlan_spec):
- def mock_empty(self, *args, **kwargs):
- pass
-
- monkeypatch.setattr(ServiceChain, '_setup', mock_empty)
-
- f = ServiceChain(AttrDict({'service_chain': 'DUMMY'}), [], {'tor': {}}, openstack_vxlan_spec,
- lambda x, y, z: None)
- result = f.get_analysis([net1])
- assert result[1]['packet_drop_count'] == 99
- assert result[1]['packet_drop_percentage'] == 0.99
- assert result[2]['packet_drop_count'] == 1
- assert result[2]['packet_drop_percentage'] == 0.01
- assert result[3]['packet_drop_count'] == 99
- assert result[3]['packet_drop_percentage'] == 0.99
-
- net1.reverse = True
- result = f.get_analysis([net1])
- assert result[1]['packet_drop_count'] == 0
- assert result[1]['packet_drop_percentage'] == 0.0
- assert result[2]['packet_drop_count'] == 0
- assert result[2]['packet_drop_percentage'] == 0.0
- assert result[3]['packet_drop_count'] == 0
- assert result[3]['packet_drop_percentage'] == 0.0
-
-
-@pytest.fixture
-def pvp_chain(monkeypatch, openstack_vxlan_spec):
- tor_vni1 = Interface('vni-4097', 'n9k', 50, 77)
- vsw_vni1 = Interface('vxlan_tunnel0', 'vpp', 77, 48)
- vsw_vif1 = Interface('VirtualEthernet0/0/2', 'vpp', 48, 77)
- vsw_vif2 = Interface('VirtualEthernet0/0/3', 'vpp', 77, 47)
- vsw_vni2 = Interface('vxlan_tunnel1', 'vpp', 43, 77)
- tor_vni2 = Interface('vni-4098', 'n9k', 77, 40)
-
- def mock_init(self, *args, **kwargs):
- self.vni_ports = [4097, 4098]
- self.specs = openstack_vxlan_spec
- self.clients = {
- 'vpp': AttrDict({
- 'set_interface_counters': lambda: None,
- })
- }
- self.worker = AttrDict({
- 'run': lambda: None,
- })
-
- def mock_empty(self, *args, **kwargs):
- pass
-
- def mock_get_network(self, traffic_port, vni_id, reverse=False):
- if vni_id == 0:
- return Network([tor_vni1, vsw_vni1, vsw_vif1], reverse)
- else:
- return Network([tor_vni2, vsw_vni2, vsw_vif2], reverse)
-
- def mock_get_data(self):
- return {}
-
- monkeypatch.setattr(PVPChain, '_get_network', mock_get_network)
- monkeypatch.setattr(PVPChain, '_get_data', mock_get_data)
- monkeypatch.setattr(PVPChain, '_setup', mock_empty)
- monkeypatch.setattr(VxLANWorker, '_clear_interfaces', mock_empty)
- monkeypatch.setattr(PVPChain, '_generate_traffic', mock_empty)
- monkeypatch.setattr(PVPChain, '__init__', mock_init)
- return PVPChain(None, None, {'vm': None, 'vpp': None, 'tor': None, 'traffic': None}, None)
-
-
-def test_pvp_chain_run(pvp_chain):
- result = pvp_chain.run()
- expected_result = {
- 'raw_data': {},
- 'stats': None,
- 'packet_analysis': {
- 'direction-forward': [
- OrderedDict([
- ('interface', 'vni-4097'),
- ('device', 'n9k'),
- ('packet_count', 50)
- ]),
- OrderedDict([
- ('interface', 'vxlan_tunnel0'),
- ('device', 'vpp'),
- ('packet_count', 48),
- ('packet_drop_count', 2),
- ('packet_drop_percentage', 4.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/2'),
- ('device', 'vpp'),
- ('packet_count', 48),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/3'),
- ('device', 'vpp'),
- ('packet_count', 47),
- ('packet_drop_count', 1),
- ('packet_drop_percentage', 2.0)
- ]),
- OrderedDict([
- ('interface', 'vxlan_tunnel1'),
- ('device', 'vpp'),
- ('packet_count', 43),
- ('packet_drop_count', 4),
- ('packet_drop_percentage', 8.0)
- ]),
- OrderedDict([
- ('interface', 'vni-4098'),
- ('device', 'n9k'),
- ('packet_count', 40),
- ('packet_drop_count', 3),
- ('packet_drop_percentage', 6.0)
- ])
- ],
- 'direction-reverse': [
- OrderedDict([
- ('interface', 'vni-4098'),
- ('device', 'n9k'),
- ('packet_count', 77)
- ]),
- OrderedDict([
- ('interface', 'vxlan_tunnel1'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/3'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/2'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'vxlan_tunnel0'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'vni-4097'),
- ('device', 'n9k'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ])
- ]
- }
- }
- assert result == expected_result
-"""
-
-
-# =========================================================================
-# PVVP Chain tests
-# =========================================================================
-
-"""
-@pytest.fixture
-def pvvp_chain(monkeypatch, openstack_vxlan_spec):
- tor_vni1 = Interface('vni-4097', 'n9k', 50, 77)
- vsw_vni1 = Interface('vxlan_tunnel0', 'vpp', 77, 48)
- vsw_vif1 = Interface('VirtualEthernet0/0/2', 'vpp', 48, 77)
- vsw_vif3 = Interface('VirtualEthernet0/0/0', 'vpp', 77, 47)
- vsw_vif4 = Interface('VirtualEthernet0/0/1', 'vpp', 45, 77)
- vsw_vif2 = Interface('VirtualEthernet0/0/3', 'vpp', 77, 44)
- vsw_vni2 = Interface('vxlan_tunnel1', 'vpp', 43, 77)
- tor_vni2 = Interface('vni-4098', 'n9k', 77, 40)
-
- def mock_init(self, *args, **kwargs):
- self.vni_ports = [4099, 4100]
- self.v2vnet = V2VNetwork()
- self.specs = openstack_vxlan_spec
- self.clients = {
- 'vpp': AttrDict({
- 'get_v2v_network': lambda reverse=None: Network([vsw_vif3, vsw_vif4], reverse),
- 'set_interface_counters': lambda pvvp=None: None,
- 'set_v2v_counters': lambda: None,
- })
- }
- self.worker = AttrDict({
- 'run': lambda: None,
- })
+import nfvbench.utils as utils
- def mock_empty(self, *args, **kwargs):
- pass
+# just to get rid of the unused function warning
+no_op()
- def mock_get_network(self, traffic_port, vni_id, reverse=False):
- if vni_id == 0:
- return Network([tor_vni1, vsw_vni1, vsw_vif1], reverse)
- else:
- return Network([tor_vni2, vsw_vni2, vsw_vif2], reverse)
-
- def mock_get_data(self):
- return {}
-
- monkeypatch.setattr(PVVPChain, '_get_network', mock_get_network)
- monkeypatch.setattr(PVVPChain, '_get_data', mock_get_data)
- monkeypatch.setattr(PVVPChain, '_setup', mock_empty)
- monkeypatch.setattr(VxLANWorker, '_clear_interfaces', mock_empty)
- monkeypatch.setattr(PVVPChain, '_generate_traffic', mock_empty)
- monkeypatch.setattr(PVVPChain, '__init__', mock_init)
-
- return PVVPChain(None, None, {'vm': None, 'vpp': None, 'tor': None, 'traffic': None}, None)
-
-
-def test_pvvp_chain_run(pvvp_chain):
- result = pvvp_chain.run()
-
- expected_result = {
- 'raw_data': {},
- 'stats': None,
- 'packet_analysis':
- {'direction-forward': [
- OrderedDict([
- ('interface', 'vni-4097'),
- ('device', 'n9k'),
- ('packet_count', 50)
- ]),
- OrderedDict([
- ('interface', 'vxlan_tunnel0'),
- ('device', 'vpp'),
- ('packet_count', 48),
- ('packet_drop_count', 2),
- ('packet_drop_percentage', 4.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/2'),
- ('device', 'vpp'),
- ('packet_count', 48),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/0'),
- ('device', 'vpp'),
- ('packet_count', 47),
- ('packet_drop_count', 1),
- ('packet_drop_percentage', 2.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/1'),
- ('device', 'vpp'),
- ('packet_count', 45),
- ('packet_drop_count', 2),
- ('packet_drop_percentage', 4.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/3'),
- ('device', 'vpp'),
- ('packet_count', 44),
- ('packet_drop_count', 1),
- ('packet_drop_percentage', 2.0)
- ]),
- OrderedDict([
- ('interface', 'vxlan_tunnel1'),
- ('device', 'vpp'),
- ('packet_count', 43),
- ('packet_drop_count', 1),
- ('packet_drop_percentage', 2.0)
- ]),
- OrderedDict([
- ('interface', 'vni-4098'),
- ('device', 'n9k'),
- ('packet_count', 40),
- ('packet_drop_count', 3),
- ('packet_drop_percentage', 6.0)
- ])
- ],
- 'direction-reverse': [
- OrderedDict([
- ('interface', 'vni-4098'),
- ('device', 'n9k'),
- ('packet_count', 77)
- ]),
- OrderedDict([
- ('interface', 'vxlan_tunnel1'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/3'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/1'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/0'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'VirtualEthernet0/0/2'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'vxlan_tunnel0'),
- ('device', 'vpp'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ]),
- OrderedDict([
- ('interface', 'vni-4097'),
- ('device', 'n9k'),
- ('packet_count', 77),
- ('packet_drop_count', 0),
- ('packet_drop_percentage', 0.0)
- ])
- ]}
- }
- assert result == expected_result
-"""
+def setup_module(module):
+ """Enable log."""
+ nfvbench.log.setup(mute_stdout=True)
# =========================================================================
# Traffic client tests
except Exception:
return True
else:
- assert False
+ return False
+ return False
assert should_raise_error('101')
assert should_raise_error('201%')
assert should_raise_error('0pps')
assert should_raise_error('-1bps')
+
def test_rate_conversion():
assert traffic_utils.load_to_bps(50, 10000000000) == pytest.approx(5000000000.0)
assert traffic_utils.load_to_bps(37, 10000000000) == pytest.approx(3700000000.0)
assert traffic_utils.pps_to_bps(3225895.85831, 340.3) == pytest.approx(9298322222)
-"""
-@pytest.fixture
-def traffic_client(monkeypatch):
-
- def mock_init(self, *args, **kwargs):
- self.run_config = {
- 'bidirectional': False,
- 'l2frame_size': '64',
- 'duration_sec': 30,
- 'rates': [{'rate_percent': '10'}, {'rate_pps': '1'}]
- }
-
- self.config = AttrDict({
- 'generator_config': {
- 'intf_speed': 10000000000
- },
- 'ndr_run': True,
- 'pdr_run': True,
- 'single_run': False,
- 'attempts': 1,
- 'measurement': {
- 'NDR': 0.0,
- 'PDR': 0.1,
- 'load_epsilon': 0.1
- }
- })
-
- self.runner = AttrDict({
- 'time_elapsed': lambda: 30,
- 'stop': lambda: None,
- 'client': AttrDict({'get_stats': lambda: None})
- })
+# pps at 10Gbps line rate for 64 byte frames
+LR_64B_PPS = 14880952
+LR_1518B_PPS = 812743
- self.current_load = None
- self.dummy_stats = {
- 50.0: 72.6433562831,
- 25.0: 45.6095059858,
- 12.5: 0.0,
- 18.75: 27.218642979,
- 15.625: 12.68585861,
- 14.0625: 2.47154392563,
- 13.28125: 0.000663797066801,
- 12.890625: 0.0,
- 13.0859375: 0.0,
- 13.18359375: 0.00359387347122,
- 13.671875: 0.307939922531,
- 13.4765625: 0.0207718516156,
- 13.57421875: 0.0661795060969
- }
-
- def mock_modify_load(self, load):
- self.run_config['rates'][0] = {'rate_percent': str(load)}
- self.current_load = load
-
- def mock_run_traffic(self):
- yield {
- 'overall': {
- 'drop_rate_percent': self.dummy_stats[self.current_load],
- 'rx': {
- 'total_pkts': 1,
- 'avg_delay_usec': 0.0,
- 'max_delay_usec': 0.0,
- 'min_delay_usec': 0.0
- }
- }
- }
-
- monkeypatch.setattr(TrafficClient, '__init__', mock_init)
- monkeypatch.setattr(TrafficClient, 'modify_load', mock_modify_load)
- monkeypatch.setattr(TrafficClient, 'run_traffic', mock_run_traffic)
-
- return TrafficClient()
-
-
-def test_ndr_pdr_search(traffic_client):
- expected_results = {
- 'pdr': {
- 'l2frame_size': '64',
- 'initial_rate_type': 'rate_percent',
- 'stats': {
- 'overall': {
- 'drop_rate_percent': 0.0661795060969,
- 'min_delay_usec': 0.0,
- 'avg_delay_usec': 0.0,
- 'max_delay_usec': 0.0
- }
- },
- 'load_percent_per_direction': 13.57421875,
- 'rate_percent': 13.57422547,
- 'rate_bps': 1357422547.0,
- 'rate_pps': 2019974.0282738095,
- 'duration_sec': 30
- },
- 'ndr': {
- 'l2frame_size': '64',
- 'initial_rate_type': 'rate_percent',
- 'stats': {
- 'overall': {
- 'drop_rate_percent': 0.0,
- 'min_delay_usec': 0.0,
- 'avg_delay_usec': 0.0,
- 'max_delay_usec': 0.0
- }
- },
- 'load_percent_per_direction': 13.0859375,
- 'rate_percent': 13.08594422,
- 'rate_bps': 1308594422.0,
- 'rate_pps': 1947313.1279761905,
- 'duration_sec': 30
- }
- }
+def assert_equivalence(reference, value, allowance_pct=1):
+ """Assert if a value is equivalent to a reference value with given margin.
- results = traffic_client.get_ndr_and_pdr()
- assert len(results) == 2
- for result in results.values():
- result.pop('timestamp_sec')
- result.pop('time_taken_sec')
- assert results == expected_results
-"""
+ :param float reference: reference value to compare to
+ :param float value: value to compare to reference
+ :param float allowance_pct: max allowed percentage of margin
+ 0 : requires exact match
+ 1 : must be equal within 1% of the reference value
+ ...
+ 100: always true
+ """
+ if reference == 0:
+ assert value == 0
+ else:
+ assert abs(value - reference) * 100 / reference <= allowance_pct
+
+def test_load_from_rate():
+ assert traffic_utils.get_load_from_rate('100%') == 100
+ assert_equivalence(100, traffic_utils.get_load_from_rate(str(LR_64B_PPS) + 'pps'))
+ assert_equivalence(50, traffic_utils.get_load_from_rate(str(LR_64B_PPS / 2) + 'pps'))
+ assert_equivalence(100, traffic_utils.get_load_from_rate('10Gbps'))
+ assert_equivalence(50, traffic_utils.get_load_from_rate('5000Mbps'))
+ assert_equivalence(1, traffic_utils.get_load_from_rate('100Mbps'))
+ assert_equivalence(100, traffic_utils.get_load_from_rate(str(LR_1518B_PPS) + 'pps',
+ avg_frame_size=1518))
+ assert_equivalence(100, traffic_utils.get_load_from_rate(str(LR_1518B_PPS * 2) + 'pps',
+ avg_frame_size=1518,
+ line_rate='20Gbps'))
# =========================================================================
# Other tests
# =========================================================================
-def setup_module(module):
- nfvbench.log.setup(mute_stdout=True)
-
def test_no_credentials():
cred = Credentials('/completely/wrong/path/openrc', None, False)
if cred.rc_auth_url:
else:
assert True
+def test_ip_block():
+ ipb = IpBlock('10.0.0.0', '0.0.0.1', 256)
+ assert ipb.get_ip() == '10.0.0.0'
+ assert ipb.get_ip(255) == '10.0.0.255'
+ with pytest.raises(IndexError):
+ ipb.get_ip(256)
+ ipb = IpBlock('10.0.0.0', '0.0.0.1', 1)
+ assert ipb.get_ip() == '10.0.0.0'
+ with pytest.raises(IndexError):
+ ipb.get_ip(1)
+
+ ipb = IpBlock('10.0.0.0', '0.0.0.2', 256)
+ assert ipb.get_ip() == '10.0.0.0'
+ assert ipb.get_ip(1) == '10.0.0.2'
+ assert ipb.get_ip(127) == '10.0.0.254'
+ assert ipb.get_ip(128) == '10.0.1.0'
+ with pytest.raises(IndexError):
+ ipb.get_ip(256)
+
+ # verify with step larger than 1
+ ipb = IpBlock('10.0.0.0', '0.0.0.2', 256)
+ assert ipb.get_ip() == '10.0.0.0'
+ assert ipb.get_ip(1) == '10.0.0.2'
+ assert ipb.get_ip(128) == '10.0.1.0'
+ assert ipb.get_ip(255) == '10.0.1.254'
+ with pytest.raises(IndexError):
+ ipb.get_ip(256)
+
+ ipb = IpBlock('10.0.0.0', '0.0.0.2', 128)
+ assert ipb.get_ip() == '10.0.0.0'
+ assert ipb.get_ip(1) == '10.0.0.2'
+ assert ipb.get_ip(127) == '10.0.0.254'
+ with pytest.raises(IndexError):
+ ipb.get_ip(128)
+
+ ipb = IpBlock('10.0.0.0', '0.0.0.4', 64)
+ assert ipb.get_ip() == '10.0.0.0'
+ assert ipb.get_ip(1) == '10.0.0.4'
+ assert ipb.get_ip(63) == '10.0.0.252'
+ with pytest.raises(IndexError):
+ ipb.get_ip(64)
+
+ ipb = IpBlock('10.0.0.0', '0.0.0.10', 1)
+ assert ipb.get_ip() == '10.0.0.0'
+ with pytest.raises(IndexError):
+ ipb.get_ip(1)
+
+
+def test_lcm():
+ assert utils.lcm(10, 2) == 10
+ assert utils.lcm(1, 256) == 256
+ assert utils.lcm(10, 256) == 1280
+ assert utils.lcm(utils.lcm(10, 2), utils.lcm(1, 256))
+ with pytest.raises(TypeError):
+ utils.lcm(0, 0)
+
+
+def test_flow_count_limit():
+ # lcm ip src and dst /32
+ lcm_ip = utils.lcm(1, 1) == 1
+ # port udp src = 1 port udp dst [1,29]
+ src_min = 1
+ src_max = 1
+ dst_min = 1
+ dst_max = 29
+ udp_step = 3
+ udp_src_size = Device.check_range_size(int(src_max) - int(src_min) + 1,
+ udp_step)
+ udp_dst_size = Device.check_range_size(int(dst_max) - int(dst_min) + 1,
+ udp_step)
+ lcm_port = utils.lcm(udp_src_size, udp_dst_size)
+ assert utils.lcm(lcm_ip, lcm_port) < 29
+
+
+def test_check_range_size():
+ assert Device.check_range_size(256, 1) == 256
+ assert Device.check_range_size(256, 3) == 86
+ assert Device.check_range_size(256, 4) == 64
+ assert Device.check_range_size(16, 10) == 2
+ assert Device.check_range_size(1, 10) == 1
+ with pytest.raises(ZeroDivisionError):
+ Device.check_range_size(256, 0)
+
+
+def test_reserve_ip_range():
+ ipb = IpBlock('10.0.0.0', '0.0.0.1', 256)
+ src_ip_first, src_ip_last = ipb.reserve_ip_range(256)
+ assert src_ip_first == "10.0.0.0"
+ assert src_ip_last == "10.0.0.255"
+ ipb = IpBlock('20.0.0.0', '0.0.0.1', 2)
+ src_ip_first, src_ip_last = ipb.reserve_ip_range(2)
+ assert src_ip_first == "20.0.0.0"
+ assert src_ip_last == "20.0.0.1"
+ ipb = IpBlock('30.0.0.0', '0.0.0.1', 2)
+ with pytest.raises(IndexError):
+ ipb.reserve_ip_range(256)
+
+
+def check_stream_configs(gen_config):
+ """Verify that the range for each chain have adjacent IP ranges without holes between chains."""
+ config = gen_config.config
+ tgc = config['traffic_generator']
+ step = Device.ip_to_int(tgc['ip_addrs_step'])
+ cfc = 0
+ sip = Device.ip_to_int(tgc['ip_addrs'][0].split('/')[0])
+ dip = Device.ip_to_int(tgc['ip_addrs'][1].split('/')[0])
+ stream_configs = gen_config.devices[0].get_stream_configs()
+ for index in range(config['service_chain_count']):
+ stream_cfg = stream_configs[index]
+ # ip_src_static == True
+ assert stream_cfg['ip_src_count'] == 1
+ if index == 0:
+ assert stream_cfg['ip_dst_count'] == 4999
+ else:
+ assert stream_cfg['ip_dst_count'] == 5000
+ assert stream_cfg['ip_src_addr'] == Device.int_to_ip(sip)
+ assert Device.ip_to_int(stream_cfg['ip_src_addr']) == sip
+ assert Device.ip_to_int(stream_cfg['ip_dst_addr']) == dip
+ count = stream_cfg['ip_dst_count']
+ cfc += count
+ sip += step
+ dip += count * step
+ assert cfc == int(config['flow_count'] / 2)
+
+def _check_device_flow_config(step_ip):
+ config = _get_dummy_tg_config('PVP', '1Mpps', scc=10, fc=99999, step_ip=step_ip)
+ gen_config = GeneratorConfig(config)
+ check_stream_configs(gen_config)
+
+def test_device_flow_config():
+ _check_device_flow_config('0.0.0.1')
+ _check_device_flow_config('0.0.0.2')
+
+
+def check_udp_stream_configs(gen_config, expected_cfg):
+ """Verify that the range for each chain have adjacent UDP ports without holes between chains."""
+ config = gen_config.config
+ stream_configs = gen_config.devices[0].get_stream_configs()
+ for index in range(config['service_chain_count']):
+ stream_cfg = stream_configs[index]
+ expected = expected_cfg[index]
+ assert stream_cfg['ip_src_addr'] == expected['ip_src_addr']
+ assert stream_cfg['ip_src_addr_max'] == expected['ip_src_addr_max']
+ assert stream_cfg['ip_src_count'] == expected['ip_src_count']
+
+ assert stream_cfg['ip_dst_addr'] == expected['ip_dst_addr']
+ assert stream_cfg['ip_dst_addr_max'] == expected['ip_dst_addr_max']
+ assert stream_cfg['ip_dst_count'] == expected['ip_dst_count']
+
+ assert stream_cfg['udp_src_port'] == expected['udp_src_port']
+ assert stream_cfg['udp_src_port_max'] == expected['udp_src_port_max']
+ assert stream_cfg['udp_src_count'] == expected['udp_src_count']
+
+ assert stream_cfg['udp_dst_port'] == expected['udp_dst_port']
+ assert stream_cfg['udp_dst_port_max'] == expected['udp_dst_port_max']
+ assert stream_cfg['udp_dst_count'] == expected['udp_dst_count']
+
+ lcm_ip = utils.lcm(stream_cfg['ip_src_count'], stream_cfg['ip_dst_count'])
+ udp_src_size = int(stream_cfg['udp_src_port_max']) - int(stream_cfg['udp_src_port']) + 1
+ udp_dst_size = int(stream_cfg['udp_dst_port_max']) - int(stream_cfg['udp_dst_port']) + 1
+ lcm_udp = utils.lcm(udp_src_size, udp_dst_size)
+ assert utils.lcm(lcm_ip, lcm_udp) >= stream_cfg['count']
+
+
+def _check_device_udp_flow_config(param, expected_cfg):
+ config = _get_dummy_tg_config('PVP', '1Mpps',
+ scc=param['scc'],
+ ip_src_static=param['ip_src_static'],
+ fc=param['flow_count'],
+ ip0=param['ip_src_addr'],
+ ip1=param['ip_dst_addr'],
+ step_ip=param['ip_addrs_step'],
+ src_udp=param['udp_src_port'],
+ dst_udp=param['udp_dst_port'],
+ step_udp=param['udp_port_step'])
+ gen_config = GeneratorConfig(config)
+ check_udp_stream_configs(gen_config, expected_cfg)
+
+
+def __get_udp_params():
+ param = {'ip_src_static': True,
+ 'ip_src_addr': '110.0.0.0/32',
+ 'ip_dst_addr': '120.0.0.0/32',
+ 'ip_addrs_step': '0.0.0.1',
+ 'udp_src_port': 53,
+ 'udp_dst_port': 53,
+ 'flow_count': 2,
+ 'scc': 1,
+ 'udp_port_step': '1'}
+ return param
+
+
+def __get_udp_expected_list():
+ expected = {'ip_src_addr': '110.0.0.0',
+ 'ip_src_addr_max': '110.0.0.0',
+ 'ip_src_count': 1,
+ 'ip_dst_addr': '120.0.0.0',
+ 'ip_dst_addr_max': '120.0.0.0',
+ 'ip_dst_count': 1,
+ 'udp_src_port': 53,
+ 'udp_src_port_max': 53,
+ 'udp_src_count': 1,
+ 'udp_dst_port': 53,
+ 'udp_dst_port_max': 53,
+ 'udp_dst_count': 1}
+ return expected
+
+
+def test_device_udp_flow_config_single_ip_single_port():
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+ _check_device_udp_flow_config(param, [expected])
+
+
+def test_device_udp_flow_config_single_ip_multiple_src_ports():
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+ # Overwrite the udp_src_port value to define a large range of ports
+ # instead of a single port, in order to check if the imposed
+ # flow count is respected. Notice that udp range >> flow count.
+ param['udp_src_port'] = [53, 1024]
+ param['flow_count'] = 10
+ expected['udp_src_port_max'] = 57
+ expected['udp_src_count'] = 5
+ _check_device_udp_flow_config(param, [expected])
+
+
+def test_device_udp_flow_config_multiple_ip_src_single_port():
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+ # Re affect the default udp_src_port values and
+ # overwrite the ip_dst_addr value to define a large range of addresses
+ # instead of a single one, in order to check if the imposed
+ # flow count is respected. Notice that the netmask allows a very larger
+ # range of possible addresses than the flow count value.
+ param['udp_src_port'] = 53
+ param['flow_count'] = 10
+ param['ip_src_static'] = False
+ param['ip_dst_addr'] = '120.0.0.0/24'
+
+ expected['udp_src_port_max'] = 53
+ expected['udp_src_count'] = 1
+ expected['ip_dst_addr'] = '120.0.0.0'
+ expected['ip_dst_addr_max'] = '120.0.0.4'
+ expected['ip_dst_count'] = 5
+ _check_device_udp_flow_config(param, [expected])
+
+
+def test_device_udp_flow_config_multiple_ip_src_dst_multiple_src_dst_ports():
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ param['udp_src_port'] = [49000, 49031]
+ param['udp_dst_port'] = [50000, 50033]
+ param['ip_src_static'] = False
+ param['flow_count'] = 1000
+ param['ip_src_addr'] = '110.0.0.0/16'
+ param['ip_dst_addr'] = '120.0.0.0/16'
+
+ expected['udp_src_port'] = 49000
+ expected['udp_src_port_max'] = 49024
+ expected['udp_dst_port'] = 50000
+ expected['udp_dst_port_max'] = 50024
+ expected['udp_src_count'] = 25
+ expected['udp_dst_count'] = 25
+ expected['ip_src_addr_max'] = '110.0.1.243'
+ expected['ip_src_count'] = 500
+ expected['ip_dst_addr'] = '120.0.0.0'
+ expected['ip_dst_addr_max'] = '120.0.1.243'
+ expected['ip_dst_count'] = 500
+ _check_device_udp_flow_config(param, [expected])
+
+
+
+
+def test_device_udp_flow_config_random_multiple_ip_src_dst_multiple_src_dst_ports():
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ param['udp_src_port'] = [1025, 65000]
+ param['udp_dst_port'] = [1024, 65000]
+ param['ip_src_static'] = False
+ param['ip_addrs_step'] = 'random'
+ param['udp_port_step'] = 'random'
+ param['flow_count'] = 1000000
+ param['ip_src_addr'] = '110.0.0.0/16'
+ param['ip_dst_addr'] = '120.0.0.0/16'
+
+ expected['udp_src_port'] = 1025
+ expected['udp_src_port_max'] = 65000
+ expected['udp_dst_port'] = 1024
+ expected['udp_dst_port_max'] = 65000
+ expected['udp_src_count'] = 62500
+ expected['udp_dst_count'] = 62500
+ expected['ip_src_addr_max'] = '110.0.0.31'
+ expected['ip_src_count'] = 32
+ expected['ip_dst_addr'] = '120.0.0.0'
+ expected['ip_dst_addr_max'] = '120.0.0.31'
+ expected['ip_dst_count'] = 32
+ _check_device_udp_flow_config(param, [expected])
+
+def test_device_udp_flow_config_random_multiple_ip_srcstatic_dst_multiple_src_dst_ports():
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ param['udp_src_port'] = [1025, 65000]
+ param['udp_dst_port'] = [1024, 65000]
+ param['ip_src_static'] = True
+ param['ip_addrs_step'] = 'random'
+ param['udp_port_step'] = 'random'
+ param['flow_count'] = 1000000
+ param['ip_src_addr'] = '110.0.0.0/16'
+ param['ip_dst_addr'] = '120.0.0.0/16'
+
+ expected['udp_src_port'] = 1025
+ expected['udp_src_port_max'] = 65000
+ expected['udp_dst_port'] = 1024
+ expected['udp_dst_port_max'] = 65000
+ expected['udp_src_count'] = 1
+ expected['udp_dst_count'] = 62500
+ expected['ip_src_addr_max'] = '110.0.0.0'
+ expected['ip_src_count'] = 1
+ expected['ip_dst_addr'] = '120.0.0.0'
+ expected['ip_dst_addr_max'] = '120.0.0.31'
+ expected['ip_dst_count'] = 32
+ _check_device_udp_flow_config(param, [expected])
+
+
+
+def test_device_udp_flow_config_single_ip_src_dst_multiple_src_dst_ports():
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ param['udp_src_port'] = [49152, 49154]
+ param['udp_dst_port'] = [50001, 50005]
+ param['ip_src_static'] = False
+ param['flow_count'] = 10
+ param['ip_src_addr'] = '110.0.0.0/32'
+ param['ip_dst_addr'] = '120.0.0.0/32'
+
+ expected['udp_src_port'] = 49152
+ expected['udp_src_port_max'] = 49152
+ expected['udp_dst_port'] = 50001
+ expected['udp_dst_port_max'] = 50005
+ expected['udp_src_count'] = 1
+ expected['udp_dst_count'] = 5
+ expected['ip_src_addr_max'] = '110.0.0.0'
+ expected['ip_src_count'] = 1
+ expected['ip_dst_addr'] = '120.0.0.0'
+ expected['ip_dst_addr_max'] = '120.0.0.0'
+ expected['ip_dst_count'] = 1
+ _check_device_udp_flow_config(param, [expected])
+
+
+def test_device_udp_flow_config_single_ip_src_dst_single_src_multiple_dst_ports():
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ param['udp_src_port'] = 49152
+ param['udp_dst_port'] = [50001, 50029]
+ param['udp_port_step'] = '3'
+ param['flow_count'] = 58
+ param['ip_src_addr'] = '110.0.0.0/32'
+ param['ip_dst_addr'] = '120.0.0.0/32'
+
+ expected['udp_src_port'] = 49152
+ expected['udp_src_port_max'] = 49152
+ expected['udp_dst_port'] = 50001
+ expected['udp_dst_port_max'] = 50029
+ expected['udp_src_count'] = 1
+ expected['udp_dst_count'] = 29
+ expected['ip_src_addr_max'] = '110.0.0.0'
+ expected['ip_src_count'] = 1
+ expected['ip_dst_addr'] = '120.0.0.0'
+ expected['ip_dst_addr_max'] = '120.0.0.0'
+ expected['ip_dst_count'] = 1
+ with pytest.raises(TrafficClientException):
+ _check_device_udp_flow_config(param, [expected])
+
+
+def test_device_udp_flow_config_scc3():
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ param['scc'] = 3
+ param['udp_src_port'] = [49000, 49031]
+ param['udp_dst_port'] = [50000, 50033]
+ param['ip_src_static'] = False
+ param['flow_count'] = 10000
+ param['ip_src_addr'] = '110.0.0.0/16'
+ param['ip_dst_addr'] = '120.0.0.0/16'
+
+ expected_cfg = []
+ # chain 0
+ expected_scc0 = dict(expected)
+ expected_scc0['udp_src_port'] = 49000
+ expected_scc0['udp_src_port_max'] = 49016
+ expected_scc0['udp_dst_port'] = 50000
+ expected_scc0['udp_dst_port_max'] = 50033
+ expected_scc0['udp_src_count'] = 17
+ expected_scc0['udp_dst_count'] = 34
+ expected_scc0['ip_src_addr_max'] = '110.0.6.129'
+ expected_scc0['ip_src_count'] = 1666
+ expected_scc0['ip_dst_addr'] = '120.0.0.0'
+ expected_scc0['ip_dst_addr_max'] = '120.0.6.129'
+ expected_scc0['ip_dst_count'] = 1666
+ expected_cfg.append(expected_scc0)
+
+ # chain 1
+ expected_scc1 = dict(expected)
+ expected_scc1['udp_src_port'] = 49000
+ expected_scc1['udp_src_port_max'] = 49000
+ expected_scc1['udp_dst_port'] = 50000
+ expected_scc1['udp_dst_port_max'] = 50000
+ expected_scc1['udp_src_count'] = 1
+ expected_scc1['udp_dst_count'] = 1
+ expected_scc1['ip_src_addr'] = '110.0.6.130'
+ expected_scc1['ip_src_addr_max'] = '110.0.13.4'
+ expected_scc1['ip_src_count'] = 1667
+ expected_scc1['ip_dst_addr'] = '120.0.6.130'
+ expected_scc1['ip_dst_addr_max'] = '120.0.13.4'
+ expected_scc1['ip_dst_count'] = 1667
+ expected_cfg.append(expected_scc1)
+
+ # chain 2
+ expected_scc2 = dict(expected)
+ expected_scc2['udp_src_port'] = 49000
+ expected_scc2['udp_src_port_max'] = 49000
+ expected_scc2['udp_dst_port'] = 50000
+ expected_scc2['udp_dst_port_max'] = 50000
+ expected_scc2['udp_src_count'] = 1
+ expected_scc2['udp_dst_count'] = 1
+ expected_scc2['ip_src_addr'] = '110.0.13.5'
+ expected_scc2['ip_src_addr_max'] = '110.0.19.135'
+ expected_scc2['ip_src_count'] = 1667
+ expected_scc2['ip_dst_addr'] = '120.0.13.5'
+ expected_scc2['ip_dst_addr_max'] = '120.0.19.135'
+ expected_scc2['ip_dst_count'] = 1667
+ expected_cfg.append(expected_scc2)
+
+ _check_device_udp_flow_config(param, expected_cfg)
+
+
+def test_device_udp_flow_config_doc_example1(caplog):
+ caplog.clear()
+ caplog.set_level(logging.INFO)
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ # Multiflow unitary test corresponding to first example in documentation
+ param['scc'] = 3
+ param['udp_src_port'] = 53
+ param['udp_dst_port'] = 53
+ param['ip_src_static'] = True
+ param['flow_count'] = 100
+ param['ip_src_addr'] = '110.0.0.0/8'
+ param['ip_dst_addr'] = '120.0.0.0/8'
+
+ expected_cfg = []
+ # chain 0
+ expected_scc0 = dict(expected)
+ expected_scc0['udp_src_port'] = 53
+ expected_scc0['udp_src_port_max'] = 53
+ expected_scc0['udp_dst_port'] = 53
+ expected_scc0['udp_dst_port_max'] = 53
+ expected_scc0['udp_src_count'] = 1
+ expected_scc0['udp_dst_count'] = 1
+ expected_scc0['ip_src_addr'] = '110.0.0.0'
+ expected_scc0['ip_src_addr_max'] = '110.0.0.0'
+ expected_scc0['ip_src_count'] = 1
+ expected_scc0['ip_dst_addr'] = '120.0.0.0'
+ expected_scc0['ip_dst_addr_max'] = '120.0.0.15'
+ expected_scc0['ip_dst_count'] = 16
+ expected_cfg.append(expected_scc0)
+
+ # chain 1
+ expected_scc1 = dict(expected)
+ expected_scc1['udp_src_port'] = 53
+ expected_scc1['udp_src_port_max'] = 53
+ expected_scc1['udp_dst_port'] = 53
+ expected_scc1['udp_dst_port_max'] = 53
+ expected_scc1['udp_src_count'] = 1
+ expected_scc1['udp_dst_count'] = 1
+ expected_scc1['ip_src_addr'] = '110.0.0.1'
+ expected_scc1['ip_src_addr_max'] = '110.0.0.1'
+ expected_scc1['ip_src_count'] = 1
+ expected_scc1['ip_dst_addr'] = '120.0.0.16'
+ expected_scc1['ip_dst_addr_max'] = '120.0.0.32'
+ expected_scc1['ip_dst_count'] = 17
+ expected_cfg.append(expected_scc1)
+
+ # chain 2
+ expected_scc2 = dict(expected)
+ expected_scc2['udp_src_port'] = 53
+ expected_scc2['udp_src_port_max'] = 53
+ expected_scc2['udp_dst_port'] = 53
+ expected_scc2['udp_dst_port_max'] = 53
+ expected_scc2['udp_src_count'] = 1
+ expected_scc2['udp_dst_count'] = 1
+ expected_scc2['ip_src_addr'] = '110.0.0.2'
+ expected_scc2['ip_src_addr_max'] = '110.0.0.2'
+ expected_scc2['ip_src_count'] = 1
+ expected_scc2['ip_dst_addr'] = '120.0.0.33'
+ expected_scc2['ip_dst_addr_max'] = '120.0.0.49'
+ expected_scc2['ip_dst_count'] = 17
+ expected_cfg.append(expected_scc2)
+
+ _check_device_udp_flow_config(param, expected_cfg)
+ assert "Current values of ip_addrs_step and/or udp_port_step properties" not in caplog.text
+
+
+def test_device_udp_flow_config_doc_example2(caplog):
+ caplog.clear()
+ caplog.set_level(logging.INFO)
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ # Multiflow unitary test corresponding to second example in documentation
+ param['scc'] = 3
+ param['udp_src_port'] = 53
+ param['udp_dst_port'] = 53
+ param['ip_src_static'] = True
+ param['ip_addrs_step'] = 'random'
+ param['flow_count'] = 100
+ param['ip_src_addr'] = '110.0.0.0/8'
+ param['ip_dst_addr'] = '120.0.0.0/8'
+
+ expected_cfg = []
+ # chain 0
+ expected_scc0 = dict(expected)
+ expected_scc0['udp_src_port'] = 53
+ expected_scc0['udp_src_port_max'] = 53
+ expected_scc0['udp_dst_port'] = 53
+ expected_scc0['udp_dst_port_max'] = 53
+ expected_scc0['udp_src_count'] = 1
+ expected_scc0['udp_dst_count'] = 1
+ expected_scc0['ip_src_addr'] = '110.0.0.0'
+ expected_scc0['ip_src_addr_max'] = '110.0.0.0'
+ expected_scc0['ip_src_count'] = 1
+ expected_scc0['ip_dst_addr'] = '120.0.0.0'
+ expected_scc0['ip_dst_addr_max'] = '120.0.0.15'
+ expected_scc0['ip_dst_count'] = 16
+ expected_cfg.append(expected_scc0)
+
+ # chain 1
+ expected_scc1 = dict(expected)
+ expected_scc1['udp_src_port'] = 53
+ expected_scc1['udp_src_port_max'] = 53
+ expected_scc1['udp_dst_port'] = 53
+ expected_scc1['udp_dst_port_max'] = 53
+ expected_scc1['udp_src_count'] = 1
+ expected_scc1['udp_dst_count'] = 1
+ expected_scc1['ip_src_addr'] = '110.0.0.1'
+ expected_scc1['ip_src_addr_max'] = '110.0.0.1'
+ expected_scc1['ip_src_count'] = 1
+ expected_scc1['ip_dst_addr'] = '120.0.0.16'
+ expected_scc1['ip_dst_addr_max'] = '120.0.0.32'
+ expected_scc1['ip_dst_count'] = 17
+ expected_cfg.append(expected_scc1)
+
+ # chain 2
+ expected_scc2 = dict(expected)
+ expected_scc2['udp_src_port'] = 53
+ expected_scc2['udp_src_port_max'] = 53
+ expected_scc2['udp_dst_port'] = 53
+ expected_scc2['udp_dst_port_max'] = 53
+ expected_scc2['udp_src_count'] = 1
+ expected_scc2['udp_dst_count'] = 1
+ expected_scc2['ip_src_addr'] = '110.0.0.2'
+ expected_scc2['ip_src_addr_max'] = '110.0.0.2'
+ expected_scc2['ip_src_count'] = 1
+ expected_scc2['ip_dst_addr'] = '120.0.0.33'
+ expected_scc2['ip_dst_addr_max'] = '120.0.0.49'
+ expected_scc2['ip_dst_count'] = 17
+ expected_cfg.append(expected_scc2)
+
+ _check_device_udp_flow_config(param, expected_cfg)
+ assert "Current values of ip_addrs_step and/or udp_port_step properties" not in caplog.text
+
+
+def test_device_udp_flow_config_doc_example3(caplog):
+ caplog.clear()
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ # Multiflow unitary test corresponding to third example in documentation
+ param['scc'] = 3
+ param['udp_src_port'] = 53
+ param['udp_dst_port'] = 53
+ param['ip_src_static'] = True
+ param['ip_addrs_step'] = '0.0.0.5'
+ param['flow_count'] = 100
+ param['ip_src_addr'] = '110.0.0.0/8'
+ param['ip_dst_addr'] = '120.0.0.0/8'
+
+ expected_cfg = []
+ # chain 0
+ expected_scc0 = dict(expected)
+ expected_scc0['udp_src_port'] = 53
+ expected_scc0['udp_src_port_max'] = 53
+ expected_scc0['udp_dst_port'] = 53
+ expected_scc0['udp_dst_port_max'] = 53
+ expected_scc0['udp_src_count'] = 1
+ expected_scc0['udp_dst_count'] = 1
+ expected_scc0['ip_src_addr'] = '110.0.0.0'
+ expected_scc0['ip_src_addr_max'] = '110.0.0.0'
+ expected_scc0['ip_src_count'] = 1
+ expected_scc0['ip_dst_addr'] = '120.0.0.0'
+ expected_scc0['ip_dst_addr_max'] = '120.0.0.75'
+ expected_scc0['ip_dst_count'] = 16
+ expected_cfg.append(expected_scc0)
+
+ # chain 1
+ expected_scc1 = dict(expected)
+ expected_scc1['udp_src_port'] = 53
+ expected_scc1['udp_src_port_max'] = 53
+ expected_scc1['udp_dst_port'] = 53
+ expected_scc1['udp_dst_port_max'] = 53
+ expected_scc1['udp_src_count'] = 1
+ expected_scc1['udp_dst_count'] = 1
+ expected_scc1['ip_src_addr'] = '110.0.0.5'
+ expected_scc1['ip_src_addr_max'] = '110.0.0.5'
+ expected_scc1['ip_src_count'] = 1
+ expected_scc1['ip_dst_addr'] = '120.0.0.80'
+ expected_scc1['ip_dst_addr_max'] = '120.0.0.160'
+ expected_scc1['ip_dst_count'] = 17
+ expected_cfg.append(expected_scc1)
+
+ # chain 2
+ expected_scc2 = dict(expected)
+ expected_scc2['udp_src_port'] = 53
+ expected_scc2['udp_src_port_max'] = 53
+ expected_scc2['udp_dst_port'] = 53
+ expected_scc2['udp_dst_port_max'] = 53
+ expected_scc2['udp_src_count'] = 1
+ expected_scc2['udp_dst_count'] = 1
+ expected_scc2['ip_src_addr'] = '110.0.0.10'
+ expected_scc2['ip_src_addr_max'] = '110.0.0.10'
+ expected_scc2['ip_src_count'] = 1
+ expected_scc2['ip_dst_addr'] = '120.0.0.165'
+ expected_scc2['ip_dst_addr_max'] = '120.0.0.245'
+ expected_scc2['ip_dst_count'] = 17
+ expected_cfg.append(expected_scc2)
+
+ caplog.set_level(logging.INFO)
+ _check_device_udp_flow_config(param, expected_cfg)
+ assert "Current values of ip_addrs_step and/or udp_port_step properties" not in caplog.text
+
+
+def test_device_udp_flow_config_doc_example4(caplog):
+ caplog.clear()
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ # Multiflow unitary test corresponding to fourth example in documentation
+ param['scc'] = 3
+ param['udp_src_port'] = [10, 14]
+ param['udp_dst_port'] = [20, 25]
+ param['ip_src_static'] = True
+ param['ip_addrs_step'] = '0.0.0.1'
+ param['udp_port_step'] = 'random'
+ param['flow_count'] = 100
+ param['ip_src_addr'] = '110.0.0.0/29'
+ param['ip_dst_addr'] = '120.0.0.0/30'
+
+ expected_cfg = []
+ # chain 0
+ expected_scc0 = dict(expected)
+ expected_scc0['udp_src_port'] = 10
+ expected_scc0['udp_src_port_max'] = 14
+ expected_scc0['udp_dst_port'] = 20
+ expected_scc0['udp_dst_port_max'] = 25
+ expected_scc0['udp_src_count'] = 5
+ expected_scc0['udp_dst_count'] = 6
+ expected_scc0['ip_src_addr'] = '110.0.0.0'
+ expected_scc0['ip_src_addr_max'] = '110.0.0.0'
+ expected_scc0['ip_src_count'] = 1
+ expected_scc0['ip_dst_addr'] = '120.0.0.0'
+ expected_scc0['ip_dst_addr_max'] = '120.0.0.0'
+ expected_scc0['ip_dst_count'] = 1
+ expected_cfg.append(expected_scc0)
+
+ # chain 1
+ expected_scc1 = dict(expected)
+ expected_scc1['udp_src_port'] = 10
+ expected_scc1['udp_src_port_max'] = 14
+ expected_scc1['udp_dst_port'] = 20
+ expected_scc1['udp_dst_port_max'] = 25
+ expected_scc1['udp_src_count'] = 5
+ expected_scc1['udp_dst_count'] = 6
+ expected_scc1['ip_src_addr'] = '110.0.0.1'
+ expected_scc1['ip_src_addr_max'] = '110.0.0.1'
+ expected_scc1['ip_src_count'] = 1
+ expected_scc1['ip_dst_addr'] = '120.0.0.1'
+ expected_scc1['ip_dst_addr_max'] = '120.0.0.1'
+ expected_scc1['ip_dst_count'] = 1
+ expected_cfg.append(expected_scc1)
+
+ # chain 2
+ expected_scc2 = dict(expected)
+ expected_scc2['udp_src_port'] = 10
+ expected_scc2['udp_src_port_max'] = 14
+ expected_scc2['udp_dst_port'] = 20
+ expected_scc2['udp_dst_port_max'] = 25
+ expected_scc2['udp_src_count'] = 5
+ expected_scc2['udp_dst_count'] = 6
+ expected_scc2['ip_src_addr'] = '110.0.0.2'
+ expected_scc2['ip_src_addr_max'] = '110.0.0.2'
+ expected_scc2['ip_src_count'] = 1
+ expected_scc2['ip_dst_addr'] = '120.0.0.2'
+ expected_scc2['ip_dst_addr_max'] = '120.0.0.2'
+ expected_scc2['ip_dst_count'] = 1
+ expected_cfg.append(expected_scc2)
+ caplog.set_level(logging.INFO)
+ _check_device_udp_flow_config(param, expected_cfg)
+ assert "Current values of ip_addrs_step and/or udp_port_step properties" in caplog.text
+ assert "udp_port_step='1' (previous value: udp_port_step='random'" in caplog.text
+
+
+def test_device_udp_flow_config_no_random_steps_overridden(caplog):
+ caplog.clear()
+ param = __get_udp_params()
+ expected = __get_udp_expected_list()
+
+ # Multiflow unitary test corresponding to fifth example in documentation
+ param['scc'] = 3
+ param['udp_src_port'] = [10, 14]
+ param['udp_dst_port'] = [20, 25]
+ param['ip_src_static'] = True
+ param['ip_addrs_step'] = 'random'
+ param['udp_port_step'] = 'random'
+ param['flow_count'] = 100
+ param['ip_src_addr'] = '110.0.0.0/29'
+ param['ip_dst_addr'] = '120.0.0.0/30'
+
+ expected_cfg = []
+ # chain 0
+ expected_scc0 = dict(expected)
+ expected_scc0['udp_src_port'] = 10
+ expected_scc0['udp_src_port_max'] = 14
+ expected_scc0['udp_dst_port'] = 20
+ expected_scc0['udp_dst_port_max'] = 25
+ expected_scc0['udp_src_count'] = 5
+ expected_scc0['udp_dst_count'] = 6
+ expected_scc0['ip_src_addr'] = '110.0.0.0'
+ expected_scc0['ip_src_addr_max'] = '110.0.0.0'
+ expected_scc0['ip_src_count'] = 1
+ expected_scc0['ip_dst_addr'] = '120.0.0.0'
+ expected_scc0['ip_dst_addr_max'] = '120.0.0.0'
+ expected_scc0['ip_dst_count'] = 1
+ expected_cfg.append(expected_scc0)
+
+ # chain 1
+ expected_scc1 = dict(expected)
+ expected_scc1['udp_src_port'] = 10
+ expected_scc1['udp_src_port_max'] = 14
+ expected_scc1['udp_dst_port'] = 20
+ expected_scc1['udp_dst_port_max'] = 25
+ expected_scc1['udp_src_count'] = 5
+ expected_scc1['udp_dst_count'] = 6
+ expected_scc1['ip_src_addr'] = '110.0.0.1'
+ expected_scc1['ip_src_addr_max'] = '110.0.0.1'
+ expected_scc1['ip_src_count'] = 1
+ expected_scc1['ip_dst_addr'] = '120.0.0.1'
+ expected_scc1['ip_dst_addr_max'] = '120.0.0.1'
+ expected_scc1['ip_dst_count'] = 1
+ expected_cfg.append(expected_scc1)
+
+ # chain 2
+ expected_scc2 = dict(expected)
+ expected_scc2['udp_src_port'] = 10
+ expected_scc2['udp_src_port_max'] = 14
+ expected_scc2['udp_dst_port'] = 20
+ expected_scc2['udp_dst_port_max'] = 25
+ expected_scc2['udp_src_count'] = 5
+ expected_scc2['udp_dst_count'] = 6
+ expected_scc2['ip_src_addr'] = '110.0.0.2'
+ expected_scc2['ip_src_addr_max'] = '110.0.0.2'
+ expected_scc2['ip_src_count'] = 1
+ expected_scc2['ip_dst_addr'] = '120.0.0.2'
+ expected_scc2['ip_dst_addr_max'] = '120.0.0.2'
+ expected_scc2['ip_dst_count'] = 1
+ expected_cfg.append(expected_scc2)
+ caplog.set_level(logging.INFO)
+ _check_device_udp_flow_config(param, expected_cfg)
+ assert "Current values of ip_addrs_step and/or udp_port_step properties" not in caplog.text
+
+
def test_config():
refcfg = {1: 100, 2: {21: 100, 22: 200}, 3: None}
res1 = {1: 10, 2: {21: 100, 22: 200}, 3: None}
res2 = {1: 100, 2: {21: 1000, 22: 200}, 3: None}
res3 = {1: 100, 2: {21: 100, 22: 200}, 3: "abc"}
- assert(config_loads("{}", refcfg) == refcfg)
- assert(config_loads("{1: 10}", refcfg) == res1)
- assert(config_loads("{2: {21: 1000}}", refcfg) == res2)
- assert(config_loads('{3: "abc"}', refcfg) == res3)
+ assert config_loads("{}", refcfg) == refcfg
+ assert config_loads("{1: 10}", refcfg) == res1
+ assert config_loads("{2: {21: 1000}}", refcfg) == res2
+ assert config_loads('{3: "abc"}', refcfg) == res3
# correctly fails
# pairs of input string and expected subset (None if identical)
expected = fail_pair[1]
if expected is None:
expected = fail_pair[0]
- assert expected in e_info.value.message
+ assert expected in str(e_info)
+ # whitelist keys
+ flavor = {'flavor': {'vcpus': 2, 'ram': 8192, 'disk': 0,
+ 'extra_specs': {'hw:cpu_policy': 'dedicated'}}}
+ new_flavor = {'flavor': {'vcpus': 2, 'ram': 8192, 'disk': 0,
+ 'extra_specs': {'hw:cpu_policy': 'dedicated', 'hw:numa_nodes': 2}}}
+ assert config_loads("{'flavor': {'extra_specs': {'hw:numa_nodes': 2}}}", flavor,
+ whitelist_keys=['alpha', 'extra_specs']) == new_flavor
def test_fluentd():
logger = logging.getLogger('fluent-logger')
- handler = FluentLogHandler('nfvbench', fluentd_port=7081)
+
+ class FluentdConfig(dict):
+ def __getattr__(self, attr):
+ return self.get(attr)
+
+ fluentd_configs = [
+ FluentdConfig({
+ 'logging_tag': 'nfvbench',
+ 'result_tag': 'resultnfvbench',
+ 'ip': '127.0.0.1',
+ 'port': 7081
+ }),
+ FluentdConfig({
+ 'logging_tag': 'nfvbench',
+ 'result_tag': 'resultnfvbench',
+ 'ip': '127.0.0.1',
+ 'port': 24224
+ }),
+ FluentdConfig({
+ 'logging_tag': None,
+ 'result_tag': 'resultnfvbench',
+ 'ip': '127.0.0.1',
+ 'port': 7082
+ }),
+ FluentdConfig({
+ 'logging_tag': 'nfvbench',
+ 'result_tag': None,
+ 'ip': '127.0.0.1',
+ 'port': 7083
+ })
+ ]
+
+ handler = FluentLogHandler(fluentd_configs=fluentd_configs)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
logger.info('test')
logger.warning('test %d', 100)
+
try:
raise Exception("test")
except Exception:
logger.exception("got exception")
+
+def assert_ndr_pdr(stats, ndr, ndr_dr, pdr, pdr_dr):
+ assert stats['ndr']['rate_percent'] == ndr
+ assert stats['ndr']['stats']['overall']['drop_percentage'] == ndr_dr
+ assert_equivalence(pdr, stats['pdr']['rate_percent'])
+ assert_equivalence(pdr_dr, stats['pdr']['stats']['overall']['drop_percentage'])
+
+def _get_dummy_tg_config(chain_type, rate, scc=1, fc=10, step_ip='0.0.0.1',
+ ip0='10.0.0.0/8', ip1='20.0.0.0/8',
+ step_udp='1', src_udp=None, dst_udp=None, ip_src_static=True):
+ return AttrDict({
+ 'traffic_generator': {'host_name': 'nfvbench_tg',
+ 'default_profile': 'dummy',
+ 'generator_profile': [{'name': 'dummy',
+ 'tool': 'dummy',
+ 'ip': '127.0.0.1',
+ 'intf_speed': '10Gbps',
+ 'interfaces': [{'port': 0, 'pci': '0.0'},
+ {'port': 1, 'pci': '0.0'}]}],
+ 'ip_addrs_step': step_ip,
+ 'ip_addrs': [ip0, ip1],
+ 'ip_src_static': ip_src_static,
+ 'tg_gateway_ip_addrs': ['1.1.0.100', '2.2.0.100'],
+ 'tg_gateway_ip_addrs_step': step_ip,
+ 'gateway_ip_addrs': ['1.1.0.2', '2.2.0.2'],
+ 'gateway_ip_addrs_step': step_ip,
+ 'mac_addrs_left': None,
+ 'mac_addrs_right': None,
+ 'udp_src_port': src_udp,
+ 'udp_dst_port': dst_udp,
+ 'udp_port_step': step_udp},
+ 'traffic': {'profile': 'profile_64',
+ 'bidirectional': True},
+ 'traffic_profile': [{'name': 'profile_64', 'l2frame_size': ['64']}],
+ 'generator_profile': None,
+ 'service_chain': chain_type,
+ 'service_chain_count': scc,
+ 'flow_count': fc,
+ 'vlan_tagging': True,
+ 'no_arp': False,
+ 'duration_sec': 1,
+ 'interval_sec': 1,
+ 'pause_sec': 1,
+ 'rate': rate,
+ 'check_traffic_time_sec': 200,
+ 'generic_poll_sec': 2,
+ 'measurement': {'NDR': 0.001, 'PDR': 0.1, 'load_epsilon': 0.1},
+ 'l2_loopback': False,
+ 'cores': None,
+ 'mbuf_factor': None,
+ 'disable_hdrh': None,
+ 'mbuf_64': None,
+ 'service_mode': False,
+ 'no_flow_stats': False,
+ 'no_latency_stats': False,
+ 'no_latency_streams': False,
+ 'intf_speed': '10Gbps',
+ 'periodic_gratuitous_arp': False,
+ 'gratuitous_arp_pps': 1
+ })
+
+def _get_traffic_client(user_info=None):
+ config = _get_dummy_tg_config('PVP', 'ndr_pdr')
+ config['vxlan'] = False
+ config['mpls'] = False
+ config['ndr_run'] = True
+ config['pdr_run'] = True
+ config['generator_profile'] = 'dummy'
+ config['single_run'] = False
+ if user_info:
+ config['user_info'] = user_info
+ traffic_client = TrafficClient(config)
+ traffic_client.start_traffic_generator()
+ traffic_client.set_traffic('64', True)
+ return traffic_client
+
+@patch.object(TrafficClient, 'skip_sleep', lambda x: True)
+def test_ndr_at_lr():
+ """Test NDR at line rate."""
+ traffic_client = _get_traffic_client()
+ tg = traffic_client.gen
+ # this is a perfect sut with no loss at LR
+ tg.set_response_curve(lr_dr=0, ndr=100, max_actual_tx=100, max_11_tx=100)
+ # tx packets should be line rate for 64B and no drops...
+ assert tg.get_tx_pps_dropped_pps(100) == (LR_64B_PPS, 0)
+ # NDR and PDR should be at 100%
+ # traffic_client.ensure_end_to_end()
+ results = traffic_client.get_ndr_and_pdr()
+ assert_ndr_pdr(results, 200.0, 0.0, 200.0, 0.0)
+
+@patch.object(TrafficClient, 'skip_sleep', lambda x: True)
+def test_ndr_at_50():
+ """Test NDR at 50% line rate.
+
+ This is a sut with an NDR of 50% and linear drop rate after NDR up to 20% drops at LR
+ (meaning that if you send 100% TX, you will only receive 80% RX)
+ the tg requested TX/actual TX ratio is up to 50%, after 50%
+ is linear up 80% actuak TX when requesting 100%
+ """
+ traffic_client = _get_traffic_client()
+ tg = traffic_client.gen
+
+ tg.set_response_curve(lr_dr=20, ndr=50, max_actual_tx=80, max_11_tx=50)
+ # tx packets should be half line rate for 64B and no drops...
+ assert tg.get_tx_pps_dropped_pps(50) == (LR_64B_PPS / 2, 0)
+ # at 100% TX requested, actual TX is 80% where the drop rate is 3/5 of 20% of the actual TX
+ assert tg.get_tx_pps_dropped_pps(100) == (int(LR_64B_PPS * 0.8),
+ int(LR_64B_PPS * 0.8 * 0.6 * 0.2))
+ results = traffic_client.get_ndr_and_pdr()
+ assert_ndr_pdr(results, 100.0, 0.0, 100.781, 0.09374)
+
+@patch.object(TrafficClient, 'skip_sleep', lambda x: True)
+def test_ndr_pdr_low_cpu():
+ """Test NDR and PDR with too low cpu.
+
+ This test is for the case where the TG is underpowered and cannot send fast enough for the NDR
+ true NDR=40%, actual TX at 50% = 30%, actual measured DR is 0%
+ The ndr/pdr should bail out with a warning and a best effort measured NDR of 30%
+ """
+ traffic_client = _get_traffic_client()
+ tg = traffic_client.gen
+ tg.set_response_curve(lr_dr=50, ndr=40, max_actual_tx=60, max_11_tx=0)
+ # tx packets should be 30% at requested half line rate for 64B and no drops...
+ assert tg.get_tx_pps_dropped_pps(50) == (int(LR_64B_PPS * 0.3), 0)
+ results = traffic_client.get_ndr_and_pdr()
+ assert results
+ # import pprint
+ # pp = pprint.PrettyPrinter(indent=4)
+ # pp.pprint(results)
+
+@patch.object(TrafficClient, 'skip_sleep', lambda x: True)
+def test_ndr_at_lr_sdn_gw_encapsulation():
+ """Test NDR at line rate with traffic gen outside SUT and connected via SDN GW."""
+ user_info = {'extra_encapsulation_bytes': 28}
+ traffic_client = _get_traffic_client(user_info)
+ tg = traffic_client.gen
+ # this is a perfect sut with no loss at LR
+ tg.set_response_curve(lr_dr=0, ndr=100, max_actual_tx=100, max_11_tx=100)
+ # tx packets should be line rate for 64B and no drops...
+ assert tg.get_tx_pps_dropped_pps(100) == (LR_64B_PPS, 0)
+ # NDR and PDR should be at 100%
+ # traffic_client.ensure_end_to_end()
+ results = traffic_client.get_ndr_and_pdr()
+ assert results['ndr']['stats']['theoretical_tx_rate_bps'] == 15000000000.0
+ assert_ndr_pdr(results, 200.0, 0.0, 200.0, 0.0)
+
+@patch.object(TrafficClient, 'skip_sleep', lambda x: True)
+def test_no_openstack():
+ """Test nfvbench using main."""
+ config = _get_dummy_tg_config('EXT', '1000pps')
+ config.openrc_file = None
+ config.vlans = [[100], [200]]
+ config['traffic_generator']['mac_addrs_left'] = ['00:00:00:00:00:00']
+ config['traffic_generator']['mac_addrs_right'] = ['00:00:00:00:01:00']
+ del config['generator_profile']
+ old_argv = sys.argv
+ sys.argv = [old_argv[0], '-c', json.dumps(config)]
+ nfvbench.nfvbench.main()
+ sys.argv = old_argv