diff --git a/snappi_ixnetwork/protocolmetrics.py b/snappi_ixnetwork/protocolmetrics.py index 1274d546b..226aec7ae 100644 --- a/snappi_ixnetwork/protocolmetrics.py +++ b/snappi_ixnetwork/protocolmetrics.py @@ -25,7 +25,7 @@ class ProtocolMetrics(object): # TODO session_flap_count can't be added now # it needs to be added by creating new view. # currently facing an issue in protocol view creation. - ("session_flap_count", "Session Flap Count", int, _SKIP), + ("session_flap_count", "Session Flap Count", int), ("routes_advertised", "Routes Advertised", int), ("routes_received", "Routes Rx", int), ("route_withdraws_sent", "Routes Withdrawn", int), @@ -43,7 +43,7 @@ class ProtocolMetrics(object): ("name", "Device Group", str), ("session_state", "Status", str), # TODO session_flap_count can't be added now - ("session_flap_count", "Session Flap Count", int, _SKIP), + ("session_flap_count", "Session Flap Count", int), ("routes_advertised", "Routes Advertised", int), ("routes_received", "Routes Rx", int), ("route_withdraws_sent", "Routes Withdrawn", int), diff --git a/tests/bgp/test_bgpv4_stats.py b/tests/bgp/test_bgpv4_stats.py new file mode 100644 index 000000000..607746046 --- /dev/null +++ b/tests/bgp/test_bgpv4_stats.py @@ -0,0 +1,128 @@ +import pytest + + +# @pytest.mark.skip(reason="Revisit CI/CD fail") +def test_bgpv4_stats(api, b2b_raw_config, utils): + """ + Test for the bgpv4 metrics + """ + api.set_config(api.config()) + b2b_raw_config.flows.clear() + + p1, p2 = b2b_raw_config.ports + d1, d2 = b2b_raw_config.devices.device(name="tx_bgp").device(name="rx_bgp") + + eth1, eth2 = d1.ethernets.add(), d2.ethernets.add() + eth1.connection.port_name, eth2.connection.port_name = p1.name, p2.name + eth1.mac, eth2.mac = "00:00:00:00:00:11", "00:00:00:00:00:22" + ip1, ip2 = eth1.ipv4_addresses.add(), eth2.ipv4_addresses.add() + bgp1, bgp2 = d1.bgp, d2.bgp + + eth1.name, eth2.name = "eth1", "eth2" + ip1.name, ip2.name = "ip1", "ip2" + bgp1.router_id, bgp2.router_id = "192.0.0.1", "192.0.0.2" + bgp1_int, bgp2_int = bgp1.ipv4_interfaces.add(), bgp2.ipv4_interfaces.add() + bgp1_int.ipv4_name, bgp2_int.ipv4_name = ip1.name, ip2.name + bgp1_peer, bgp2_peer = bgp1_int.peers.add(), bgp2_int.peers.add() + bgp1_peer.name, bgp2_peer.name = "bgp1", "bpg2" + ip1.address = "10.1.1.1" + ip1.gateway = "10.1.1.2" + ip1.prefix = 24 + + ip2.address = "10.1.1.2" + ip2.gateway = "10.1.1.1" + ip2.prefix = 24 + + bgp1_peer.peer_address = "10.1.1.2" + bgp1_peer.as_type = "ibgp" + bgp1_peer.as_number = 10 + + bgp2_peer.peer_address = "10.1.1.1" + bgp2_peer.as_type = "ibgp" + bgp2_peer.as_number = 10 + + utils.start_traffic(api, b2b_raw_config) + utils.wait_for( + lambda: results_ok(api), "stats to be as expected", timeout_seconds=20 + ) + enums = [ + "session_state", + "routes_advertised", + "routes_received", + "route_withdraws_sent", + "route_withdraws_received", + "updates_sent", + "updates_received", + "opens_sent", + "opens_received", + "keepalives_sent", + "keepalives_received", + "notifications_sent", + "notifications_received", + ] + expected_results = { + "tx_bgp": ["up", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "rx_bgp": ["up", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + } + req = api.metrics_request() + req.bgpv4.peer_names = [] + req.bgpv4.column_names = enums[:3] + results = api.get_metrics(req) + assert len(results.bgpv4_metrics) == 2 + for bgp_res in results.bgpv4_metrics: + for i, enum in enumerate(enums[:3]): + val = expected_results[bgp_res.name][i] + if "session_state" in enum: + assert getattr(bgp_res, enum) == val + else: + assert getattr(bgp_res, enum) >= val + + req = api.metrics_request() + req.bgpv4.peer_names = [] + req.bgpv4.column_names = [] + results = api.get_metrics(req) + + assert len(results.bgpv4_metrics) == 2 + for bgp_res in results.bgpv4_metrics: + for i, enum in enumerate(enums): + val = expected_results[bgp_res.name][i] + if "session_state" in enum: + assert getattr(bgp_res, enum) == val + else: + assert getattr(bgp_res, enum) >= val + + # req = api.metrics_request() + # req.bgpv4.peer_names = ["rx_bgp"] + # results = api.get_metrics(req) + + # assert len(results.bgpv4_metrics) == 1 + # assert results.bgpv4_metrics[0].name == "rx_bgp" + # for bgp_res in results.bgpv4_metrics: + # for i, enum in enumerate(enums): + # val = expected_results[bgp_res.name][i] + # if "session_state" in enum: + # assert getattr(bgp_res, enum) == val + # else: + # assert getattr(bgp_res, enum) >= val + + req = api.metrics_request() + req.bgpv4.column_names = ["session_state"] + results = api.get_metrics(req) + assert len(results.bgpv4_metrics) == 2 + assert results.bgpv4_metrics[0].session_state == "up" + assert results.bgpv4_metrics[1].session_state == "up" + utils.stop_traffic(api, b2b_raw_config) + + +def results_ok(api): + req = api.metrics_request() + req.bgpv4.column_names = ["session_state"] + results = api.get_metrics(req) + ok = [] + for r in results.bgpv4_metrics: + ok.append(r.session_state == "up") + return all(ok) + + +if __name__ == "__main__": + pytest.main(["-vv", "-s", __file__]) diff --git a/tests/traffic/test_device_bgp_ep.py b/tests/traffic/test_device_bgp_ep.py new file mode 100644 index 000000000..0540c9b2e --- /dev/null +++ b/tests/traffic/test_device_bgp_ep.py @@ -0,0 +1,128 @@ +import pytest + + +# @pytest.mark.skip(reason="will be updating the test with new snappi version") +def test_bgpv6_routes(api, b2b_raw_config, utils): + """ + Test for the bgpv6 routes + """ + size = 1500 + packets = 1000 + api.set_config(api.config()) + b2b_raw_config.flows.clear() + + p1, p2 = b2b_raw_config.ports + d1, d2 = b2b_raw_config.devices.device(name="tx_bgp").device(name="rx_bgp") + eth1, eth2 = d1.ethernets.add(), d2.ethernets.add() + eth1.connection.port_name, eth2.connection.port_name = p1.name, p2.name + eth1.mac, eth2.mac = "00:00:00:00:00:11", "00:00:00:00:00:22" + ip1, ip2 = eth1.ipv6_addresses.add(), eth2.ipv6_addresses.add() + bgp1, bgp2 = d1.bgp, d2.bgp + + eth1.name, eth2.name = "eth1", "eth2" + ip1.name, ip2.name = "ip1", "ip2" + + ip1.address = "2000::1" + ip1.gateway = "3000::1" + ip1.prefix = 64 + + ip2.address = "3000::1" + ip2.gateway = "2000::1" + ip2.prefix = 64 + + bgp1.router_id, bgp2.router_id = "192.0.0.1", "192.0.0.2" + bgp1_int, bgp2_int = bgp1.ipv6_interfaces.add(), bgp2.ipv6_interfaces.add() + bgp1_int.ipv6_name, bgp2_int.ipv6_name = ip1.name, ip2.name + bgp1_peer, bgp2_peer = bgp1_int.peers.add(), bgp2_int.peers.add() + bgp1_peer.name, bgp2_peer.name = "bgp1", "bpg2" + + bgp1_peer.peer_address = "3000::1" + bgp1_peer.as_type = "ibgp" + bgp1_peer.as_number = 10 + + bgp2_peer.peer_address = "2000::1" + bgp2_peer.as_type = "ibgp" + bgp2_peer.as_number = 10 + + bgp1_rr1 = bgp1_peer.v6_routes.add(name="bgp1_rr1") + bgp1_rr2 = bgp1_peer.v6_routes.add(name="bgp1_rr2") + bgp2_rr1 = bgp2_peer.v6_routes.add(name="bgp2_rr1") + bgp2_rr2 = bgp2_peer.v6_routes.add(name="bgp2_rr2") + + bgp1_rr1.addresses.add(address="4000::1", prefix=64) + bgp1_rr2.addresses.add(address="5000::1", prefix=64) + + bgp2_rr1.addresses.add(address="4000::1", prefix=64) + bgp2_rr2.addresses.add(address="5000::1", prefix=64) + + flow_bgp = b2b_raw_config.flows.flow(name="flow_bgp")[-1] + + flow_bgp.rate.percentage = 1 + flow_bgp.duration.fixed_packets.packets = packets + flow_bgp.size.fixed = size + flow_bgp.tx_rx.device.tx_names = [ + bgp1_rr1.name, + bgp1_rr2.name, + ] + flow_bgp.tx_rx.device.rx_names = [ + bgp2_rr1.name, + bgp2_rr2.name, + ] + flow_bgp.metrics.enable = True + flow_bgp.metrics.loss = True + utils.start_traffic(api, b2b_raw_config, start_capture=False) + + req = api.metrics_request() + req.bgpv6.peer_names = [] + results = api.get_metrics(req) + enums = [ + "session_state", + "routes_advertised", + "route_withdraws_sent", + ] + expected_results = { + "tx_bgp": ["up", 0, 0], + "rx_bgp": ["up", 0, 0], + } + + assert len(results.bgpv6_metrics) == 2 + for bgp_res in results.bgpv6_metrics: + for i, enum in enumerate(enums): + val = expected_results[bgp_res.name][i] + assert getattr(bgp_res, enum) == val + + req = api.metrics_request() + req.bgpv6.peer_names = ["rx_bgp"] + results = api.get_metrics(req) + + # assert len(results.bgpv6_metrics) == 1 + # assert results.bgpv6_metrics[0].name == "rx_bgp" + # for bgp_res in results.bgpv6_metrics: + # for i, enum in enumerate(enums): + # val = expected_results[bgp_res.name][i] + # assert getattr(bgp_res, enum) == val + + req = api.metrics_request() + req.bgpv6.column_names = ["session_state"] + results = api.get_metrics(req) + assert len(results.bgpv6_metrics) == 2 + assert results.bgpv6_metrics[0].session_state == "up" + assert results.bgpv6_metrics[1].session_state == "up" + + utils.wait_for( + lambda: results_ok(api, ["flow_bgp"], packets), + "stats to be as expected", + timeout_seconds=10, + ) + utils.stop_traffic(api, b2b_raw_config) + + +def results_ok(api, flow_names, expected): + """ + Returns True if there is no traffic loss else False + """ + request = api.metrics_request() + request.flow.flow_names = flow_names + flow_results = api.get_metrics(request).flow_metrics + flow_rx = sum([f.frames_rx for f in flow_results]) + return flow_rx == expected diff --git a/tests/traffic/test_ip_device_and_flow.py b/tests/traffic/test_ip_device_and_flow.py new file mode 100644 index 000000000..26bc329f6 --- /dev/null +++ b/tests/traffic/test_ip_device_and_flow.py @@ -0,0 +1,140 @@ +import pytest + + +@pytest.mark.e2e +def test_ip_device_and_flow(api, b2b_raw_config, utils): + """ + Configure the devices on Tx and Rx Port. + Configure the flow with devices as end points. + run the traffic + Validation, + - validate the port and flow statistics. + """ + + size = 128 + packets = 100000 + count = 10 + mac_tx = utils.mac_or_ip_addr_from_counter_pattern( + "00:10:10:20:20:10", "00:00:00:00:00:01", count, True + ) + mac_rx = utils.mac_or_ip_addr_from_counter_pattern( + "00:10:10:20:20:20", "00:00:00:00:00:01", count, False + ) + ip_tx = utils.mac_or_ip_addr_from_counter_pattern( + "10.1.1.1", "0.0.1.0", count, True, False + ) + + ip_rx = utils.mac_or_ip_addr_from_counter_pattern( + "10.1.1.2", "0.0.1.0", count, True, False + ) + + addrs = { + "mac_tx": mac_tx, + "mac_rx": mac_rx, + "ip_tx": ip_tx, + "ip_rx": ip_rx, + } + + for i in range(count * 2): + port = int(i / count) + node = "tx" if port == 0 else "rx" + if i >= count: + i = i - count + dev = b2b_raw_config.devices.device()[-1] + + dev.name = "%s_dev_%d" % (node, i + 1) + eth = dev.ethernets.add() + eth.connection.port_name = b2b_raw_config.ports[port].name + eth.name = "%s_eth_%d" % (node, i + 1) + eth.mac = addrs["mac_%s" % node][i] + + ip = eth.ipv4_addresses.add() + ip.name = "%s_ipv4_%d" % (node, i + 1) + ip.address = addrs["ip_%s" % node][i] + ip.gateway = addrs["ip_%s" % ("rx" if node == "tx" else "tx")][i] + ip.prefix = 24 + f1, f2 = b2b_raw_config.flows.flow(name="TxFlow-2") + f1.name = "TxFlow-1" + f1.tx_rx.device.tx_names = [ + b2b_raw_config.devices[i].name for i in range(count) + ] + f1.tx_rx.device.rx_names = [ + b2b_raw_config.devices[i].name for i in range(count, count * 2) + ] + f1.tx_rx.device.mode = f2.tx_rx.device.ONE_TO_ONE + f1.size.fixed = size + f1.duration.fixed_packets.packets = packets + f1.rate.percentage = 10 + f1.metrics.enable = True + + f2.tx_rx.device.tx_names = [ + b2b_raw_config.devices[i].name for i in range(count) + ] + f2.tx_rx.device.rx_names = [ + b2b_raw_config.devices[i].name for i in range(count, count * 2) + ] + f2.tx_rx.device.mode = f2.tx_rx.device.ONE_TO_ONE + f2.packet.ethernet().ipv4().tcp() + tcp = f2.packet[-1] + tcp.src_port.increment.start = 5000 + tcp.src_port.increment.step = 1 + tcp.src_port.increment.count = count + tcp.dst_port.increment.start = 2000 + tcp.dst_port.increment.step = 1 + tcp.dst_port.increment.count = count + f2.size.fixed = size * 2 + f2.duration.fixed_packets.packets = packets + f2.rate.percentage = 10 + f2.metrics.enable = True + + utils.start_traffic(api, b2b_raw_config) + + utils.wait_for( + lambda: results_ok(api, utils, size, size * 2, packets), + "stats to be as expected", + timeout_seconds=20, + ) + utils.stop_traffic(api, b2b_raw_config) + captures_ok(api, b2b_raw_config, utils, count, packets * 2) + + +def results_ok(api, utils, size1, size2, packets): + """ + Returns true if stats are as expected, false otherwise. + """ + port_results, flow_results = utils.get_all_stats(api) + frames_ok = utils.total_frames_ok(port_results, flow_results, packets * 2) + bytes_ok = utils.total_bytes_ok( + port_results, flow_results, packets * size1 + packets * size2 + ) + return frames_ok and bytes_ok + + +def captures_ok(api, cfg, utils, count, packets): + """ + Returns normally if patterns in captured packets are as expected. + """ + src_mac = [[0x00, 0x10, 0x10, 0x20, 0x20, 0x10 + i] for i in range(count)] + dst_mac = [[0x00, 0x10, 0x10, 0x20, 0x20, 0x20 - i] for i in range(count)] + + src_ip = [[0x0A, 0x01, 0x01 + i, 0x01] for i in range(count)] + dst_ip = [[0x0A, 0x01, 0x01 + i, 0x02] for i in range(count)] + + src_port = [[0x13, 0x88 + i] for i in range(count)] + dst_port = [[0x07, 0xD0 + i] for i in range(count)] + + cap_dict = utils.get_all_captures(api, cfg) + assert len(cap_dict) == 1 + sizes = [128, 256] + size_dt = {128: [0 for i in range(count)], 256: [0 for i in range(count)]} + + for b in cap_dict[list(cap_dict.keys())[0]]: + i = dst_mac.index(b[0:6]) + assert b[0:6] == dst_mac[i] and b[6:12] == src_mac[i] + assert b[26:30] == src_ip[i] and b[30:34] == dst_ip[i] + assert len(b) in sizes + size_dt[len(b)][i] += 1 + if len(b) == 256: + assert b[34:36] == src_port[i] and b[36:38] == dst_port[i] + + assert sum(size_dt[128]) + sum(size_dt[256]) == packets diff --git a/tests/traffic/test_ip_many_to_many.py b/tests/traffic/test_ip_many_to_many.py new file mode 100644 index 000000000..eb614dff5 --- /dev/null +++ b/tests/traffic/test_ip_many_to_many.py @@ -0,0 +1,138 @@ +import pytest + + +@pytest.mark.e2e +def test_ip_device_and_flow(api, b2b_raw_config, utils): + """ + Configure the devices on Tx and Rx Port. + Configure the flow with devices as end points. + run the traffic + Validation, + - validate the port and flow statistics. + """ + + size = 128 + packets = 100000 + count = 10 + mac_tx = utils.mac_or_ip_addr_from_counter_pattern( + "00:10:10:20:20:10", "00:00:00:00:00:01", count, True + ) + mac_rx = utils.mac_or_ip_addr_from_counter_pattern( + "00:10:10:20:20:20", "00:00:00:00:00:01", count, False + ) + ip_tx = utils.mac_or_ip_addr_from_counter_pattern( + "10.1.1.1", "0.0.1.0", count, True, False + ) + + ip_rx = utils.mac_or_ip_addr_from_counter_pattern( + "10.1.1.2", "0.0.1.0", count, True, False + ) + + addrs = { + "mac_tx": mac_tx, + "mac_rx": mac_rx, + "ip_tx": ip_tx, + "ip_rx": ip_rx, + } + + # import snappi + # b2b_raw_config = snappi.Api().config() + + for i in range(count * 2): + port = int(i / count) + node = "tx" if port == 0 else "rx" + if i >= count: + i = i - count + dev = b2b_raw_config.devices.device()[-1] + + dev.name = "%s_dev_%d" % (node, i + 1) + dev.container_name = b2b_raw_config.ports[port].name + + dev.ethernet.name = "%s_eth_%d" % (node, i + 1) + dev.ethernet.mac = addrs["mac_%s" % node][i] + + dev.ethernet.ipv4.name = "%s_ipv4_%d" % (node, i + 1) + dev.ethernet.ipv4.address = addrs["ip_%s" % node][i] + dev.ethernet.ipv4.gateway = addrs[ + "ip_%s" % ("rx" if node == "tx" else "tx") + ][i] + dev.ethernet.ipv4.prefix = 24 + b2b_raw_config.flows.clear() + f1, f2 = b2b_raw_config.flows.flow(name="TxFlow-1").flow(name="TxFlow-2") + f1.tx_rx.device.tx_names = [ + b2b_raw_config.devices[i].name for i in range(count) + ] + f1.tx_rx.device.rx_names = [ + b2b_raw_config.devices[i + count].name for i in range(count) + ] + f1.size.fixed = size + f1.duration.fixed_packets.packets = packets + f1.rate.percentage = "10" + + f2.tx_rx.device.tx_names = [ + b2b_raw_config.devices[i].name for i in range(count) + ] + f2.tx_rx.device.rx_names = [ + b2b_raw_config.devices[i + count].name for i in range(count) + ] + f2.packet.ethernet().ipv4().tcp() + tcp = f2.packet[-1] + tcp.src_port.increment.start = "5000" + tcp.src_port.increment.step = "1" + tcp.src_port.increment.count = "%d" % count + tcp.dst_port.increment.start = "2000" + tcp.dst_port.increment.step = "1" + tcp.dst_port.increment.count = "%d" % count + f2.size.fixed = size * 2 + f2.duration.fixed_packets.packets = packets + f2.rate.percentage = "10" + utils.start_traffic(api, b2b_raw_config) + utils.wait_for( + lambda: results_ok(api, utils, size, size * 2, packets), + "stats to be as expected", + timeout_seconds=20, + ) + utils.stop_traffic(api, b2b_raw_config) + # captures_ok(api, b2b_raw_config, utils, count, packets * 2) + + +def results_ok(api, utils, size1, size2, packets): + """ + Returns true if stats are as expected, false otherwise. + """ + port_results, flow_results = utils.get_all_stats(api) + frames_ok = utils.total_frames_ok(port_results, flow_results, packets * 2) + bytes_ok = utils.total_bytes_ok( + port_results, flow_results, packets * size1 + packets * size2 + ) + return frames_ok and bytes_ok + + +def captures_ok(api, cfg, utils, count, packets): + """ + Returns normally if patterns in captured packets are as expected. + """ + src_mac = [[0x00, 0x10, 0x10, 0x20, 0x20, 0x10 + i] for i in range(count)] + dst_mac = [[0x00, 0x10, 0x10, 0x20, 0x20, 0x20 - i] for i in range(count)] + + src_ip = [[0x0A, 0x01, 0x01 + i, 0x01] for i in range(count)] + dst_ip = [[0x0A, 0x01, 0x01 + i, 0x02] for i in range(count)] + + src_port = [[0x13, 0x88 + i] for i in range(count)] + dst_port = [[0x07, 0xD0 + i] for i in range(count)] + + cap_dict = utils.get_all_captures(api, cfg) + assert len(cap_dict) == 1 + sizes = [128, 256] + size_dt = {128: [0 for i in range(count)], 256: [0 for i in range(count)]} + + for b in cap_dict[list(cap_dict.keys())[0]]: + i = dst_mac.index(b[0:6]) + assert b[0:6] == dst_mac[i] and b[6:12] == src_mac[i] + assert b[26:30] == src_ip[i] and b[30:34] in dst_ip[i] + assert len(b) in sizes + size_dt[len(b)][i] += 1 + if len(b) == 256: + assert b[34:36] == src_port[i] and b[36:38] in dst_port[i] + + assert sum(size_dt[128]) + sum(size_dt[256]) == packets diff --git a/tests/traffic/test_ip_one_to_one.py b/tests/traffic/test_ip_one_to_one.py new file mode 100644 index 000000000..f6b95052b --- /dev/null +++ b/tests/traffic/test_ip_one_to_one.py @@ -0,0 +1,139 @@ +import pytest + + +@pytest.mark.e2e +def test_ip_device_and_flow(api, b2b_raw_config, utils): + """ + Configure the devices on Tx and Rx Port. + Configure the flow with devices as end points. + run the traffic + Validation, + - validate the port and flow statistics. + """ + + size = 128 + packets = 100000 + count = 10 + mac_tx = utils.mac_or_ip_addr_from_counter_pattern( + "00:10:10:20:20:10", "00:00:00:00:00:01", count, True + ) + mac_rx = utils.mac_or_ip_addr_from_counter_pattern( + "00:10:10:20:20:20", "00:00:00:00:00:01", count, False + ) + ip_tx = utils.mac_or_ip_addr_from_counter_pattern( + "10.1.1.1", "0.0.1.0", count, True, False + ) + + ip_rx = utils.mac_or_ip_addr_from_counter_pattern( + "10.1.1.2", "0.0.1.0", count, True, False + ) + + addrs = { + "mac_tx": mac_tx, + "mac_rx": mac_rx, + "ip_tx": ip_tx, + "ip_rx": ip_rx, + } + + # import snappi + # b2b_raw_config = snappi.Api().config() + + for i in range(count * 2): + port = int(i / count) + node = "tx" if port == 0 else "rx" + if i >= count: + i = i - count + dev = b2b_raw_config.devices.device()[-1] + + dev.name = "%s_dev_%d" % (node, i + 1) + dev.container_name = b2b_raw_config.ports[port].name + + dev.ethernet.name = "%s_eth_%d" % (node, i + 1) + dev.ethernet.mac = addrs["mac_%s" % node][i] + + dev.ethernet.ipv4.name = "%s_ipv4_%d" % (node, i + 1) + dev.ethernet.ipv4.address = addrs["ip_%s" % node][i] + dev.ethernet.ipv4.gateway = addrs[ + "ip_%s" % ("rx" if node == "tx" else "tx") + ][i] + dev.ethernet.ipv4.prefix = 24 + b2b_raw_config.flows.clear() + f1, f2 = b2b_raw_config.flows.flow(name="TxFlow-1").flow(name="TxFlow-2") + f1.tx_rx.device.tx_names = [ + b2b_raw_config.devices[i].name for i in range(count) + ] + f1.tx_rx.device.rx_names = [ + b2b_raw_config.devices[i + count].name for i in range(count) + ] + f1.tx_rx.device.mode = f1.tx_rx.device.ONE_TO_ONE + f1.size.fixed = size + f1.duration.fixed_packets.packets = packets + f1.rate.percentage = "10" + + f2.tx_rx.device.tx_names = [ + b2b_raw_config.devices[i].name for i in range(count) + ] + f2.tx_rx.device.rx_names = [ + b2b_raw_config.devices[i + count].name for i in range(count) + ] + f2.tx_rx.device.mode = f1.tx_rx.device.ONE_TO_ONE + f2.packet.ethernet().ipv4().tcp() + tcp = f2.packet[-1] + tcp.src_port.increment.start = "5000" + tcp.src_port.increment.step = "1" + tcp.src_port.increment.count = "%d" % count + tcp.dst_port.increment.start = "2000" + tcp.dst_port.increment.step = "1" + tcp.dst_port.increment.count = "%d" % count + f2.size.fixed = size * 2 + f2.duration.fixed_packets.packets = packets + f2.rate.percentage = "10" + utils.start_traffic(api, b2b_raw_config) + utils.wait_for( + lambda: results_ok(api, utils, size, size * 2, packets), + "stats to be as expected", + timeout_seconds=20, + ) + utils.stop_traffic(api, b2b_raw_config) + captures_ok(api, b2b_raw_config, utils, count, packets * 2) + + +def results_ok(api, utils, size1, size2, packets): + """ + Returns true if stats are as expected, false otherwise. + """ + port_results, flow_results = utils.get_all_stats(api) + frames_ok = utils.total_frames_ok(port_results, flow_results, packets * 2) + bytes_ok = utils.total_bytes_ok( + port_results, flow_results, packets * size1 + packets * size2 + ) + return frames_ok and bytes_ok + + +def captures_ok(api, cfg, utils, count, packets): + """ + Returns normally if patterns in captured packets are as expected. + """ + src_mac = [[0x00, 0x10, 0x10, 0x20, 0x20, 0x10 + i] for i in range(count)] + dst_mac = [[0x00, 0x10, 0x10, 0x20, 0x20, 0x20 - i] for i in range(count)] + + src_ip = [[0x0A, 0x01, 0x01 + i, 0x01] for i in range(count)] + dst_ip = [[0x0A, 0x01, 0x01 + i, 0x02] for i in range(count)] + + src_port = [[0x13, 0x88 + i] for i in range(count)] + dst_port = [[0x07, 0xD0 + i] for i in range(count)] + + cap_dict = utils.get_all_captures(api, cfg) + assert len(cap_dict) == 1 + sizes = [128, 256] + size_dt = {128: [0 for i in range(count)], 256: [0 for i in range(count)]} + for b in cap_dict[list(cap_dict.keys())[0]]: + i = dst_mac.index(b[0:6]) + assert b[0:6] == dst_mac[i] and b[6:12] == src_mac[i] + assert b[26:30] == src_ip[i] and b[30:34] == dst_ip[i] + assert len(b) in sizes + size_dt[len(b)][i] += 1 + if len(b) == 256: + assert b[34:36] == src_port[i] and b[36:38] == dst_port[i] + + assert sum(size_dt[128]) + sum(size_dt[256]) == packets diff --git a/tests/traffic/test_stats_filter_e2e.py b/tests/traffic/test_stats_filter_e2e.py new file mode 100644 index 000000000..2df0f5e3f --- /dev/null +++ b/tests/traffic/test_stats_filter_e2e.py @@ -0,0 +1,119 @@ +import pytest +import time + + +def test_stats_filter_e2e(api, b2b_raw_config, utils): + """ + configure two flows f1 and f2 + - Send continuous packets from f1 of size 74B + - Send continuous packets from f2 of size 1500B + + Validation: + 1) Get port statistics based on port name & column names and assert + each port & column has returned the values and assert + 2) Get flow statistics based on flow name & column names and assert + each flow & column has returned the values and assert + """ + api.set_config(api.config()) + f1_size = 74 + f2_size = 1500 + ports = b2b_raw_config.ports + flow1 = b2b_raw_config.flows[0] + flow2 = b2b_raw_config.flows.flow()[-1] + flow2.name = "f2" + flow2.tx_rx.port.tx_name = ports[0].name + flow2.tx_rx.port.rx_name = ports[1].name + + flow1.size.fixed = f1_size + flow1.rate.percentage = 10 + flow1.duration.continuous + flow1.metrics.enable = True + + flow2.size.fixed = f2_size + flow2.rate.percentage = 10 + flow2.duration.continuous + flow2.metrics.enable = True + + utils.start_traffic(api, b2b_raw_config, start_capture=False) + time.sleep(5) + + # Validation on Port statistics based on port names + port_names = ["raw_tx", "raw_rx"] + for port_name in port_names: + req = api.metrics_request() + req.port.port_names = [port_name] + port_results = api.get_metrics(req).port_metrics + validate_port_stats_based_on_port_name(port_results, port_name) + + # Validation on Port statistics based on column names + column_names = [ + "frames_tx_rate", + "bytes_tx_rate", + "frames_rx_rate", + "bytes_rx_rate", + ] + for column_name in column_names: + req = api.metrics_request() + req.port.column_names = ["name", column_name] + port_results = api.get_metrics(req).port_metrics + validate_port_stats_based_on_column_name(port_results, column_name) + + # Validation on Flow statistics based on flow names + flow_names = ["f1", "f2"] + for flow_name in flow_names: + req = api.metrics_request() + req.flow.flow_names = [flow_name] + req.flow.metric_names = ["name"] + flow_results = api.get_metrics(req).flow_metrics + validate_flow_stats_based_on_flow_name(flow_results, flow_name) + + # Validation on Flow statistics based on column names + # column_names = ["frames_tx_rate", "frames_rx_rate"] + # for column_name in column_names: + # req = api.metrics_request() + # req.flow.metric_names = ["name", column_name] + # flow_results = api.get_metrics(req).flow_metrics + # validate_flow_stats_based_on_column_name(flow_results, column_name) + + utils.stop_traffic(api, b2b_raw_config) + + +def validate_port_stats_based_on_port_name(port_results, port_name): + """ + Validate stats based on port_names + """ + for row in port_results: + assert row.name == port_name + + +def validate_port_stats_based_on_column_name(port_results, column_name): + """ + Validate Port stats based on column_names + """ + for row in port_results: + if row.name == "raw_tx": + if column_name == "frames_tx_rate": + assert getattr(row, column_name) > 0 + elif column_name == "bytes_tx_rate": + assert getattr(row, column_name) > 0 + elif row.name == "raw_rx": + if column_name == "frames_rx_rate": + assert getattr(row, column_name) > 0 + elif column_name == "bytes_rx_rate": + assert getattr(row, column_name) > 0 + + +def validate_flow_stats_based_on_flow_name(flow_results, flow_name): + """ + Validate Flow stats based on flow_names + """ + for row in flow_results: + assert row.name == flow_name + + +def validate_flow_stats_based_on_column_name(flow_results, column_name): + """ + Validate Flow stats based on column_names + """ + for row in flow_results: + assert round(getattr(row, column_name)) > 0 diff --git a/tests/traffic/test_tcp_flow_capture.py b/tests/traffic/test_tcp_flow_capture.py new file mode 100644 index 000000000..68d333083 --- /dev/null +++ b/tests/traffic/test_tcp_flow_capture.py @@ -0,0 +1,78 @@ +import pytest + + +@pytest.mark.e2e +def test_tcp_flow_capture(api, b2b_raw_config, utils): + """ + Configure a raw TCP flow with, + - list of 6 src ports and 3 dst ports + - 100 frames of 1518B size each + - 10% line rate + Validate, + - tx/rx frame count and bytes are as expected + - all captured frames have expected src and dst ports + """ + size = 1518 + packets = 100 + + flow = b2b_raw_config.flows[0] + eth, ip, tcp = flow.packet.ethernet().ipv4().tcp() + + eth.src.value = "00:CD:DC:CD:DC:CD" + eth.dst.value = "00:AB:BC:AB:BC:AB" + + ip.src.value = "1.1.1.2" + ip.dst.value = "1.1.1.1" + + tcp.src_port.values = [5000, 5050, 5015, 5040, 5032, 5021] + tcp.dst_port.values = [6000, 6015, 6050] + + flow.duration.fixed_packets.packets = packets + flow.size.fixed = size + flow.rate.percentage = 10 + flow.metrics.enable = True + + utils.start_traffic(api, b2b_raw_config) + utils.wait_for( + lambda: results_ok(api, utils, size, packets), + "stats to be as expected", + timeout_seconds=10, + ) + captures_ok(api, b2b_raw_config, utils, size) + + +def results_ok(api, utils, size, packets): + """ + Returns true if stats are as expected, false otherwise. + """ + port_results, flow_results = utils.get_all_stats(api) + frames_ok = utils.total_frames_ok(port_results, flow_results, packets) + bytes_ok = utils.total_bytes_ok(port_results, flow_results, packets * size) + return frames_ok and bytes_ok + + +def captures_ok(api, cfg, utils, size): + """ + Returns normally if patterns in captured packets are as expected. + """ + src = [ + [0x13, 0x88], + [0x13, 0xBA], + [0x13, 0x97], + [0x13, 0xB0], + [0x13, 0xA8], + [0x13, 0x9D], + ] + dst = [[0x17, 0x70], [0x17, 0x7F], [0x17, 0xA2]] + + cap_dict = utils.get_all_captures(api, cfg) + assert len(cap_dict) == 1 + + for k in cap_dict: + i = 0 + j = 0 + for b in cap_dict[k]: + assert b[34:36] == src[i] and b[36:38] == dst[j] + i = (i + 1) % 6 + j = (j + 1) % 3 + assert len(b) == size