ptf/saiwred.py (299 lines of code) (raw):
# Copyright 2021-present Intel Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Thrift SAI interface Weighted random early detection (WRED) tests
"""
from sai_thrift.sai_headers import *
from sai_base_test import *
@group("draft")
class WredBaseTest(PlatformSaiHelper):
"""
WRED base test
"""
def setUp(self):
"""
Configure WredTest:
1. Call SaiHelper setUp()
2. Configure routing.
- route traffic destined for 172.20.20.11 into port 11
- route traffic destined for 172.20.20.12 into port 12
- route traffic destined for 4000::2 into port 13
3. Get queues so that they can be used within tests
- self.queues10 of port 10
- self.queues11 of port 11
- self.queues12 of port 12
- self.queues13 of port 13
4. Create wred profiles. they will be assigned to queues
in separate tests
- self.wred_ecn - "mark all" profile
- self.wred_drop - "drop all" profile
"""
super(WredBaseTest, self).setUp()
##########################
# Configure routes
##########################
print("Configure routing...")
self.nexthops = []
self.neighbors = []
self.routes = []
##########################
# 172.20.20.11 -> port 11
# 4000::1 -> port 11
##########################
# NextHop
nexthop = sai_thrift_create_next_hop(
self.client,
ip=sai_ipaddress("172.20.10.11"),
router_interface_id=self.port11_rif,
type=SAI_NEXT_HOP_TYPE_IP)
self.nexthops.append(nexthop)
# Neighbor entry
neighbor_entry = sai_thrift_neighbor_entry_t(
rif_id=self.port11_rif, ip_address=sai_ipaddress("172.20.10.11"))
sai_thrift_create_neighbor_entry(
self.client, neighbor_entry, dst_mac_address="00:11:22:33:44:55")
self.neighbors.append(neighbor_entry)
# Route entry
route = sai_thrift_route_entry_t(
vr_id=self.default_vrf,
destination=sai_ipprefix("172.20.10.11/32"))
sai_thrift_create_route_entry(self.client, route, next_hop_id=nexthop)
self.routes.append(route)
# Route entry (IPv6)
route = sai_thrift_route_entry_t(
vr_id=self.default_vrf, destination=sai_ipprefix("4000::1/128"))
sai_thrift_create_route_entry(self.client, route, next_hop_id=nexthop)
self.routes.append(route)
##########################
# 172.20.20.12 -> port 12
# 4000::2 -> port 12
##########################
# NextHop
nexthop = sai_thrift_create_next_hop(
self.client,
ip=sai_ipaddress("172.20.10.12"),
router_interface_id=self.port12_rif,
type=SAI_NEXT_HOP_TYPE_IP)
self.nexthops.append(nexthop)
# Neighbor entry
neighbor_entry = sai_thrift_neighbor_entry_t(
rif_id=self.port12_rif, ip_address=sai_ipaddress("172.20.10.12"))
sai_thrift_create_neighbor_entry(
self.client, neighbor_entry, dst_mac_address="00:11:22:33:44:55")
self.neighbors.append(neighbor_entry)
# Route entry
route = sai_thrift_route_entry_t(
vr_id=self.default_vrf,
destination=sai_ipprefix("172.20.10.12/32"))
sai_thrift_create_route_entry(self.client, route, next_hop_id=nexthop)
self.routes.append(route)
# Route entry (IPv6)
route = sai_thrift_route_entry_t(
vr_id=self.default_vrf, destination=sai_ipprefix("4000::2/128"))
sai_thrift_create_route_entry(self.client, route, next_hop_id=nexthop)
self.routes.append(route)
##########################
# 172.20.20.13 -> port 13
# 4000::3 -> port 13
##########################
# NextHop
nexthop = sai_thrift_create_next_hop(
self.client,
ip=sai_ipaddress("172.20.10.13"),
router_interface_id=self.port13_rif,
type=SAI_NEXT_HOP_TYPE_IP)
self.nexthops.append(nexthop)
# Neighbor entry
neighbor_entry = sai_thrift_neighbor_entry_t(
rif_id=self.port13_rif, ip_address=sai_ipaddress("172.20.10.13"))
sai_thrift_create_neighbor_entry(
self.client, neighbor_entry, dst_mac_address="00:11:22:33:44:55")
self.neighbors.append(neighbor_entry)
# Route entry
route = sai_thrift_route_entry_t(
vr_id=self.default_vrf,
destination=sai_ipprefix("172.20.10.13/32"))
sai_thrift_create_route_entry(self.client, route, next_hop_id=nexthop)
self.routes.append(route)
# Route entry (IPv6)
route = sai_thrift_route_entry_t(
vr_id=self.default_vrf, destination=sai_ipprefix("4000::3/128"))
sai_thrift_create_route_entry(self.client, route, next_hop_id=nexthop)
self.routes.append(route)
##########################
# Get queues
##########################
print("Get queues...")
queue_list = sai_thrift_object_list_t(count=10)
attr = sai_thrift_get_port_attribute(
self.client, self.port10, qos_queue_list=queue_list)
self.queues10 = attr["SAI_PORT_ATTR_QOS_QUEUE_LIST"].idlist
queue_list = sai_thrift_object_list_t(count=10)
attr = sai_thrift_get_port_attribute(
self.client, self.port11, qos_queue_list=queue_list)
self.queues11 = attr["SAI_PORT_ATTR_QOS_QUEUE_LIST"].idlist
queue_list = sai_thrift_object_list_t(count=10)
attr = sai_thrift_get_port_attribute(
self.client, self.port12, qos_queue_list=queue_list)
self.queues12 = attr["SAI_PORT_ATTR_QOS_QUEUE_LIST"].idlist
queue_list = sai_thrift_object_list_t(count=10)
attr = sai_thrift_get_port_attribute(
self.client, self.port13, qos_queue_list=queue_list)
self.queues13 = attr["SAI_PORT_ATTR_QOS_QUEUE_LIST"].idlist
##########################
# Configure WRED profiles
##########################
print("Create WRED profiles...")
max_thr = 50 * 80
# Create ECN marking WRED profile (WredIPv4Test)
self.wred_ecn = sai_thrift_create_wred(
self.client,
ecn_mark_mode=True,
green_min_threshold=0,
green_max_threshold=max_thr,
green_drop_probability=100)
self.assertTrue(self.wred_ecn != 0)
# Create dropping WRED profile (WredDropIPv4Test)
self.wred_drop = sai_thrift_create_wred(
self.client,
green_enable=True,
green_min_threshold=0,
green_max_threshold=max_thr,
green_drop_probability=100)
self.assertTrue(self.wred_drop != 0)
print("-----------------------")
def tearDown(self):
"""
Deconfigure WredTest:
1. Remove wred profiles
- self.wred_ecn - "mark all" profile
- self.wred_drop - "drop all" profile
2. Deconfigure routing
- remove all created route entries
- remove all created neighbor entries
- remove all created nexthops
1. Call SaiHelper tearDown()
"""
print("\n\n-----------------------")
print("Tear down WRED tests...")
#######################
# Remove WRED profiles
#######################
print("Remove WRED profiles...")
status = sai_thrift_remove_wred(self.client, self.wred_ecn)
self.assertEqual(status, SAI_STATUS_SUCCESS)
status = sai_thrift_remove_wred(self.client, self.wred_drop)
self.assertEqual(status, SAI_STATUS_SUCCESS)
################
# Remove routes
################
print("Deconfigure routing...")
for route in self.routes:
status = sai_thrift_remove_route_entry(self.client, route)
self.assertEqual(status, SAI_STATUS_SUCCESS)
for neighbor in self.neighbors:
status = sai_thrift_remove_neighbor_entry(self.client, neighbor)
self.assertEqual(status, SAI_STATUS_SUCCESS)
for nexthop in self.nexthops:
status = sai_thrift_remove_next_hop(self.client, nexthop)
self.assertEqual(status, SAI_STATUS_SUCCESS)
super(WredBaseTest, self).tearDown()
@staticmethod
def _statsDiff(i_stats, e_stats):
""" Returns a dict off stats that differ
Args:
i_stats(dict): i stats
e_stats(dict): e stats
Returns:
dect: diff
"""
return {stat: e_stats[stat] - i_stats[stat]
for stat in e_stats
if e_stats[stat] - i_stats[stat]}
@staticmethod
def _printStats(*stats):
for (name, i_stats, e_stats) in stats:
print("\t", name, "stats:", WredBaseTest._statsDiff(i_stats,
e_stats))
def _verifyStat(self, i_stats, e_stats, stat, delta):
self.assertEqual(e_stats[stat]-i_stats[stat], delta)
def _verifyStats(self, i_stats, e_stats, *stats):
print("Verify stats:")
for (name, delta) in stats:
print("|", name, "=>", delta)
self._verifyStat(i_stats, e_stats, name, delta)
@group("draft")
class WredTestHelper(WredBaseTest):
"""
Test WRED interface, also with traffic not affected by WRED
"""
def setUp(self):
print("\n==========")
print("WRED tests")
print("==========\n")
super(WredTestHelper, self).setUp()
def tearDown(self):
super(WredTestHelper, self).tearDown()
class _WredBindProfileTest(WredTestHelper):
"""
wred.1 - Verify wred profile bind to a queue with no prior WRED profile
1. Add the WRED profile to all queues of a single port.
Cleanup:
1. Detach all WRED profiles
"""
def setUp(self):
super(_WredBindProfileTest, self).setUp()
def runTest(self):
print("\n\n_WredBindProfileTest()")
print("----------------------")
try:
# Assign WRED profile to all queues
print("Attach the WRED profile to queues.")
for queue in self.queues11:
status = sai_thrift_set_queue_attribute(
self.client, queue, wred_profile_id=self.wred_ecn)
self.assertEqual(status, SAI_STATUS_SUCCESS)
finally:
for queue in self.queues11:
status = sai_thrift_set_queue_attribute(self.client,
queue,
wred_profile_id=0)
self.assertEqual(status, SAI_STATUS_SUCCESS)
def tearDown(self):
super(_WredBindProfileTest, self).tearDown()
class _WredReplaceProfileTest(WredTestHelper):
"""
wred.2 - Verify WRED profile bind to a queue with an existing
WRED profile
1. Add the WRED profile to all queues of a single port.
2. Add the another WRED profile to all off them.
Cleanup:
1. Detach all WRED profiles
"""
def setUp(self):
super(_WredReplaceProfileTest, self).setUp()
def runTest(self):
print("\n\n_WredReplaceProfileTest()")
print("-------------------------")
try:
# Assign WRED profile to all queues
print("Attach the WRED profile to queues.")
for queue in self.queues12:
status = sai_thrift_set_queue_attribute(
self.client, queue, wred_profile_id=self.wred_ecn)
self.assertEqual(status, SAI_STATUS_SUCCESS)
# Assign WRED profile to all queues
print("Attach the another WRED profile to the same queues.")
for queue in self.queues12:
status = sai_thrift_set_queue_attribute(
self.client, queue, wred_profile_id=self.wred_drop)
self.assertEqual(status, SAI_STATUS_SUCCESS)
finally:
# Clean up all queues
for queue in self.queues12:
status = sai_thrift_set_queue_attribute(
self.client, queue, wred_profile_id=0)
self.assertEqual(status, SAI_STATUS_SUCCESS)
def tearDown(self):
super(_WredReplaceProfileTest, self).tearDown()
class _WredBindProfileMultipleQueuesTest(WredTestHelper):
"""
wred.3 - Verify WRED profile can be bound to multiple queues
1. Add the WRED profile to all queues of a single port.
2. Add the same WRED profile to all queues of a another port.
3. Add the same WRED profile to all queues of a another port.
Cleanup:
1. Detach all WRED profiles (of all three ports)
"""
def setUp(self):
super(_WredBindProfileMultipleQueuesTest, self).setUp()
def runTest(self):
print("\n\n_WredBindProfileMultipleQueuesTest()")
print("------------------------------------")
try:
# Assign WRED profile to all queues (port11)
print("Attach the WRED profile to queues.")
for queue in self.queues11:
status = sai_thrift_set_queue_attribute(
self.client, queue, wred_profile_id=self.wred_ecn)
self.assertEqual(status, SAI_STATUS_SUCCESS)
# Assign WRED profile to all queues (port12)
print("Attach the WRED profile to another port queues.")
for queue in self.queues12:
status = sai_thrift_set_queue_attribute(
self.client, queue, wred_profile_id=self.wred_ecn)
self.assertEqual(status, SAI_STATUS_SUCCESS)
# Assign WRED profile to all queues (port13)
print("Attach the WRED profile to yet another port queues.")
for queue in self.queues13:
status = sai_thrift_set_queue_attribute(
self.client, queue, wred_profile_id=self.wred_ecn)
self.assertEqual(status, SAI_STATUS_SUCCESS)
finally:
# Clean up all queues
for queue in self.queues11:
status = sai_thrift_set_queue_attribute(self.client,
queue,
wred_profile_id=0)
self.assertEqual(status, SAI_STATUS_SUCCESS)
for queue in self.queues12:
status = sai_thrift_set_queue_attribute(self.client,
queue,
wred_profile_id=0)
self.assertEqual(status, SAI_STATUS_SUCCESS)
for queue in self.queues13:
status = sai_thrift_set_queue_attribute(self.client,
queue,
wred_profile_id=0)
self.assertEqual(status, SAI_STATUS_SUCCESS)
def tearDown(self):
super(_WredBindProfileMultipleQueuesTest, self).tearDown()
class _WredIPv4NonECNTest(WredTestHelper):
"""
wred.4 - Verify non-ECN traffic is unaffected by WRED profile
on a queue
1. Add the WRED (ECN) profile to the queue of a single port.
2. Send a non-ECN packet. Verify, that the packet was not affected
by ECN profile
Cleanup:
1. Detach the WRED profile
"""
def setUp(self):
super(_WredIPv4NonECNTest, self).setUp()
def runTest(self):
print("\n\n_WredIPv4NonECNTest()")
print("---------------------")
i_port_stats = query_counter(
self, sai_thrift_get_port_stats,
self.port11)
i_queue_stats = query_counter(
self, sai_thrift_get_queue_stats,
self.queues11[0])
try:
pkt1 = simple_tcp_packet(
eth_dst='00:77:66:55:44:00',
eth_src='00:22:22:22:22:22',
ip_dst='172.20.10.11',
ip_src='192.168.0.1',
ip_id=105,
ip_ttl=64)
# ECN unaffected packet
exp_pkt1 = simple_tcp_packet(
eth_dst='00:11:22:33:44:55',
eth_src='00:77:66:55:44:00',
ip_dst='172.20.10.11',
ip_src='192.168.0.1',
ip_id=105,
ip_ttl=63)
# Assign WRED profile to the queue
status = sai_thrift_set_queue_attribute(
self.client, self.queues11[0], wred_profile_id=self.wred_ecn)
self.assertEqual(status, SAI_STATUS_SUCCESS)
print("ECT is NOT set.")
print("Send and receive a packet.")
send_packet(self, self.dev_port10, pkt1)
verify_packet(self, exp_pkt1, self.dev_port11)
time.sleep(2)
e_port_stats = query_counter(
self, sai_thrift_get_port_stats,
self.port11)
e_queue_stats = query_counter(
self, sai_thrift_get_queue_stats,
self.queues11[0])
# Verify stats
self._verifyStats(
i_port_stats, e_port_stats,
('SAI_PORT_STAT_ECN_MARKED_PACKETS', 0))
self._verifyStats(
i_queue_stats, e_queue_stats,
('SAI_QUEUE_STAT_PACKETS', 1))
finally:
status = sai_thrift_set_queue_attribute(self.client,
self.queues11[0],
wred_profile_id=0)
self.assertEqual(status, SAI_STATUS_SUCCESS)
def tearDown(self):
super(_WredIPv4NonECNTest, self).tearDown()
class _WredAttributeCheckTest(WredTestHelper):
def setUp(self):
super(_WredAttributeCheckTest, self).setUp()
def runTest(self):
# Check weight attribute
wred_attr = sai_thrift_get_wred_attribute(
self.client,
self.wred_ecn,
weight=True)
wred_weight = wred_attr['weight']
self.assertTrue(wred_weight == 0)
def tearDown(self):
super(_WredAttributeCheckTest, self).tearDown()