blob: 270f8c9a09876392a6f38f4eda99e350dcc06f83 [file] [log] [blame]
Brian Russell6e6920d2021-02-17 15:54:52 +00001#!/usr/bin/env python3
2# Copyright (c) 2021 Graphiant, Inc.
3
4import unittest
Brian Russell6e6920d2021-02-17 15:54:52 +00005from scapy.layers.inet import IP, UDP
6from scapy.layers.l2 import Ether
7from scapy.packet import Raw
Dave Wallace8800f732023-08-31 00:47:44 -04008from framework import VppTestCase
9from asfframework import VppTestRunner
Brian Russell6e6920d2021-02-17 15:54:52 +000010from vpp_papi import VppEnum
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +020011from vpp_policer import VppPolicer, PolicerAction, Dir
Brian Russell6e6920d2021-02-17 15:54:52 +000012
13NUM_PKTS = 67
14
15
16class TestPolicerInput(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020017 """Policer on an interface"""
18
Klement Sekera8d815022021-03-15 16:58:10 +010019 vpp_worker_count = 2
Brian Russell6e6920d2021-02-17 15:54:52 +000020
21 def setUp(self):
22 super(TestPolicerInput, self).setUp()
23
24 self.create_pg_interfaces(range(2))
25 for i in self.pg_interfaces:
26 i.admin_up()
27 i.config_ip4()
28 i.resolve_arp()
29
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020030 self.pkt = (
31 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
32 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
33 / UDP(sport=1234, dport=1234)
34 / Raw(b"\xa5" * 100)
35 )
Brian Russell6e6920d2021-02-17 15:54:52 +000036
37 def tearDown(self):
38 for i in self.pg_interfaces:
39 i.unconfig_ip4()
40 i.admin_down()
41 super(TestPolicerInput, self).tearDown()
42
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +020043 def policer_interface_test(self, dir: Dir):
Brian Russell26bcbc12021-02-18 11:02:29 +000044 pkts = self.pkt * NUM_PKTS
45
Brian Russell6e6920d2021-02-17 15:54:52 +000046 action_tx = PolicerAction(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020047 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
48 )
49 policer = VppPolicer(
50 self,
51 "pol1",
52 80,
53 0,
54 1000,
55 0,
56 conform_action=action_tx,
57 exceed_action=action_tx,
58 violate_action=action_tx,
59 )
Brian Russell6e6920d2021-02-17 15:54:52 +000060 policer.add_vpp_config()
61
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020062 sw_if_index = self.pg0.sw_if_index if dir == Dir.RX else self.pg1.sw_if_index
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +020063
Brian Russell6e6920d2021-02-17 15:54:52 +000064 # Start policing on pg0
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +020065 policer.apply_vpp_config(sw_if_index, dir, True)
Brian Russell6e6920d2021-02-17 15:54:52 +000066
Brian Russell26bcbc12021-02-18 11:02:29 +000067 rx = self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
Brian Russell6e6920d2021-02-17 15:54:52 +000068 stats = policer.get_stats()
69
70 # Single rate, 2 colour policer - expect conform, violate but no exceed
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020071 self.assertGreater(stats["conform_packets"], 0)
72 self.assertEqual(stats["exceed_packets"], 0)
73 self.assertGreater(stats["violate_packets"], 0)
Brian Russell6e6920d2021-02-17 15:54:52 +000074
75 # Stop policing on pg0
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +020076 policer.apply_vpp_config(sw_if_index, dir, False)
Brian Russell6e6920d2021-02-17 15:54:52 +000077
Brian Russell26bcbc12021-02-18 11:02:29 +000078 rx = self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
79
Brian Russell6e6920d2021-02-17 15:54:52 +000080 statsnew = policer.get_stats()
81
82 # No new packets counted
83 self.assertEqual(stats, statsnew)
84
85 policer.remove_vpp_config()
86
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +020087 def test_policer_input(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020088 """Input Policing"""
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +020089 self.policer_interface_test(Dir.RX)
90
91 def test_policer_output(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020092 """Output Policing"""
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +020093 self.policer_interface_test(Dir.TX)
94
Maxime Peim2d1a62b2023-01-06 11:57:38 +000095 def test_policer_reset(self):
96 """Policer reset bucket"""
97 pkts = self.pkt * NUM_PKTS
98
99 action_tx = PolicerAction(
100 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
101 )
102 policer = VppPolicer(
103 self,
104 "pol1",
105 1,
106 0,
107 10000,
108 0,
109 conform_action=action_tx,
110 exceed_action=action_tx,
111 violate_action=action_tx,
112 )
113 policer.add_vpp_config()
114
115 # Start policing on pg0
116 policer.apply_vpp_config(self.pg0.sw_if_index, Dir.RX, True)
117
118 self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
119 details = policer.get_details()
120
121 self.assertGreater(details.current_limit, details.current_bucket)
122
123 self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
124 self.vapi.policer_reset(policer_index=policer.policer_index)
125 details = policer.get_details()
126
127 self.assertEqual(details.current_limit, details.current_bucket)
128
129 policer.apply_vpp_config(self.pg0.sw_if_index, Dir.RX, False)
130
131 policer.remove_vpp_config()
132
133 def test_policer_update(self):
134 """Policer update"""
135 pkts = self.pkt * NUM_PKTS
136
137 action_tx = PolicerAction(
138 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
139 )
140 policer = VppPolicer(
141 self,
142 "pol1",
143 1,
144 0,
145 10000,
146 0,
147 conform_action=action_tx,
148 exceed_action=action_tx,
149 violate_action=action_tx,
150 )
151 policer.add_vpp_config()
152
153 # Start policing on pg0
154 policer.apply_vpp_config(self.pg0.sw_if_index, Dir.RX, True)
155
156 self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
157 details_before = policer.get_details()
158
159 self.assertGreater(details_before.current_limit, details_before.current_bucket)
160
161 policer.cir = 8000
162 policer.commited_burst = 100000
163 policer.update()
164
165 details_after = policer.get_details()
166
167 self.assertGreater(details_after.cir, details_before.cir)
168 self.assertGreater(details_after.cb, details_before.cb)
169
170 policer.apply_vpp_config(self.pg0.sw_if_index, Dir.RX, False)
171
172 policer.remove_vpp_config()
173
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +0200174 def policer_handoff_test(self, dir: Dir):
Brian Russell26bcbc12021-02-18 11:02:29 +0000175 pkts = self.pkt * NUM_PKTS
176
177 action_tx = PolicerAction(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200178 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
179 )
180 policer = VppPolicer(
181 self,
182 "pol2",
183 80,
184 0,
185 1000,
186 0,
187 conform_action=action_tx,
188 exceed_action=action_tx,
189 violate_action=action_tx,
190 )
Brian Russell26bcbc12021-02-18 11:02:29 +0000191 policer.add_vpp_config()
192
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200193 sw_if_index = self.pg0.sw_if_index if dir == Dir.RX else self.pg1.sw_if_index
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +0200194
Brian Russell26bcbc12021-02-18 11:02:29 +0000195 # Bind the policer to worker 1
196 policer.bind_vpp_config(1, True)
197
198 # Start policing on pg0
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +0200199 policer.apply_vpp_config(sw_if_index, dir, True)
Brian Russell26bcbc12021-02-18 11:02:29 +0000200
201 for worker in [0, 1]:
202 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
203 self.logger.debug(self.vapi.cli("show trace max 100"))
204
205 stats = policer.get_stats()
206 stats0 = policer.get_stats(worker=0)
207 stats1 = policer.get_stats(worker=1)
208
209 # Worker 1, should have done all the policing
210 self.assertEqual(stats, stats1)
211
212 # Worker 0, should have handed everything off
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200213 self.assertEqual(stats0["conform_packets"], 0)
214 self.assertEqual(stats0["exceed_packets"], 0)
215 self.assertEqual(stats0["violate_packets"], 0)
Brian Russell26bcbc12021-02-18 11:02:29 +0000216
217 # Unbind the policer from worker 1 and repeat
218 policer.bind_vpp_config(1, False)
219 for worker in [0, 1]:
220 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
221 self.logger.debug(self.vapi.cli("show trace max 100"))
222
223 # The policer should auto-bind to worker 0 when packets arrive
224 stats = policer.get_stats()
225
226 # The 2 workers should now have policed the same amount
227 stats = policer.get_stats()
228 stats0 = policer.get_stats(worker=0)
229 stats1 = policer.get_stats(worker=1)
230
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200231 self.assertGreater(stats0["conform_packets"], 0)
232 self.assertEqual(stats0["exceed_packets"], 0)
233 self.assertGreater(stats0["violate_packets"], 0)
Brian Russell26bcbc12021-02-18 11:02:29 +0000234
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200235 self.assertGreater(stats1["conform_packets"], 0)
236 self.assertEqual(stats1["exceed_packets"], 0)
237 self.assertGreater(stats1["violate_packets"], 0)
Brian Russell26bcbc12021-02-18 11:02:29 +0000238
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200239 self.assertEqual(
240 stats0["conform_packets"] + stats1["conform_packets"],
241 stats["conform_packets"],
242 )
Brian Russell26bcbc12021-02-18 11:02:29 +0000243
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200244 self.assertEqual(
245 stats0["violate_packets"] + stats1["violate_packets"],
246 stats["violate_packets"],
247 )
Brian Russell26bcbc12021-02-18 11:02:29 +0000248
249 # Stop policing on pg0
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +0200250 policer.apply_vpp_config(sw_if_index, dir, False)
Brian Russell26bcbc12021-02-18 11:02:29 +0000251
252 policer.remove_vpp_config()
Brian Russell6e6920d2021-02-17 15:54:52 +0000253
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +0200254 def test_policer_handoff_input(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200255 """Worker thread handoff policer input"""
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +0200256 self.policer_handoff_test(Dir.RX)
257
258 def test_policer_handoff_output(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200259 """Worker thread handoff policer output"""
Stanislav Zaikine5a3ae02022-04-05 19:23:12 +0200260 self.policer_handoff_test(Dir.TX)
261
262
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200263if __name__ == "__main__":
Brian Russell6e6920d2021-02-17 15:54:52 +0000264 unittest.main(testRunner=VppTestRunner)