2 """L2 FIB Test Case HLD:
5 - add 4 pg-l2 interfaces
6 - configure them into l2bd
7 - configure 100 MAC entries in L2 fib - 25 MACs per interface
8 - L2 MAC learning and unknown unicast flooding disabled in l2bd
9 - configure 100 MAC entries in L2 fib - 25 MACs per interface
12 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 100 MAC \
16 - all packets received correctly
19 - delete 12 MAC entries - 3 MACs per interface
22 - send L2 MAC frames between all 4 pg-l2 interfaces for non-deleted MAC \
26 - all packets received correctly
29 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 12 deleted \
33 - no packet received on all 4 pg-l2 interfaces
36 - configure new 100 MAC entries in L2 fib - 25 MACs per interface
39 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 188 MAC \
43 - all packets received correctly
46 - delete 160 MAC entries, 40 MACs per interface
49 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 28 \
50 non-deleted MAC entries
53 - all packets received correctly
56 - try send L2 MAC frames between all 4 pg-l2 interfaces for all of 172 \
60 - no packet received on all 4 pg-l2 interfaces
66 from scapy.packet import Raw
67 from scapy.layers.l2 import Ether
68 from scapy.layers.inet import IP, UDP
70 from framework import VppTestCase, VppTestRunner
74 class TestL2fib(VppTestCase):
75 """ L2 FIB Test Case """
80 Perform standard class setup (defined by class method setUpClass in
81 class VppTestCase) before running the test case, set test case related
82 variables and configure VPP.
84 :var int bd_id: Bridge domain ID.
85 :var int mac_entries_count: Number of MAC entries for bridge-domain.
87 super(TestL2fib, cls).setUpClass()
91 cls.mac_entries_count = 200
94 # Create 4 pg interfaces
95 cls.create_pg_interfaces(range(4))
97 # Packet flows mapping pg0 -> pg1, pg2, pg3 etc.
99 cls.flows[cls.pg0] = [cls.pg1, cls.pg2, cls.pg3]
100 cls.flows[cls.pg1] = [cls.pg0, cls.pg2, cls.pg3]
101 cls.flows[cls.pg2] = [cls.pg0, cls.pg1, cls.pg3]
102 cls.flows[cls.pg3] = [cls.pg0, cls.pg1, cls.pg2]
105 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
107 # Create BD with MAC learning and unknown unicast flooding disabled
108 # and put interfaces to this BD
109 cls.vapi.bridge_domain_add_del(bd_id=cls.bd_id, uu_flood=0, learn=0)
110 for pg_if in cls.pg_interfaces:
111 cls.vapi.sw_interface_set_l2_bridge(pg_if.sw_if_index,
114 # Set up all interfaces
115 for i in cls.pg_interfaces:
118 # Mapping between packet-generator index and lists of test hosts
119 cls.hosts_by_pg_idx = dict()
120 for pg_if in cls.pg_interfaces:
121 cls.hosts_by_pg_idx[pg_if.sw_if_index] = []
123 # Create list of deleted hosts
124 cls.deleted_hosts_by_pg_idx = dict()
125 for pg_if in cls.pg_interfaces:
126 cls.deleted_hosts_by_pg_idx[pg_if.sw_if_index] = []
129 super(TestL2fib, cls).tearDownClass()
134 Clear trace and packet infos before running each test.
136 super(TestL2fib, self).setUp()
137 self.packet_infos = {}
141 Show various debug prints after each test.
143 super(TestL2fib, self).tearDown()
144 if not self.vpp_dead:
145 self.logger.info(self.vapi.ppcli("show l2fib verbose"))
146 self.logger.info(self.vapi.ppcli("show bridge-domain %s detail"
149 def create_hosts(self, count, start=0):
151 Create required number of host MAC addresses and distribute them among
152 interfaces. Create host IPv4 address for every host MAC address.
154 :param int count: Number of hosts to create MAC/IPv4 addresses for.
155 :param int start: Number to start numbering from.
157 n_int = len(self.pg_interfaces)
158 macs_per_if = count / n_int
160 for pg_if in self.pg_interfaces:
162 start_nr = macs_per_if * i + start
163 end_nr = count + start if i == (n_int - 1) \
164 else macs_per_if * (i + 1) + start
165 hosts = self.hosts_by_pg_idx[pg_if.sw_if_index]
166 for j in range(start_nr, end_nr):
168 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
169 "172.17.1%02x.%u" % (pg_if.sw_if_index, j))
172 def config_l2_fib_entries(self, count, start=0):
174 Create required number of L2 FIB entries.
176 :param int count: Number of L2 FIB entries to be created.
177 :param int start: Starting index of the host list. (Default value = 0)
179 n_int = len(self.pg_interfaces)
182 for pg_if in self.pg_interfaces:
183 end_nr = start + count / n_int
184 for j in range(start, end_nr):
185 host = self.hosts_by_pg_idx[pg_if.sw_if_index][j]
186 self.vapi.l2fib_add_del(host.mac, self.bd_id, pg_if.sw_if_index,
189 percentage = counter / count * 100
190 if percentage > percent:
191 self.logger.info("Configure %d L2 FIB entries .. %d%% done"
192 % (count, percentage))
194 self.logger.info(self.vapi.ppcli("show l2fib"))
196 def delete_l2_fib_entry(self, count):
198 Delete required number of L2 FIB entries.
200 :param int count: Number of L2 FIB entries to be created.
202 n_int = len(self.pg_interfaces)
205 for pg_if in self.pg_interfaces:
206 for j in range(count / n_int):
207 host = self.hosts_by_pg_idx[pg_if.sw_if_index][0]
208 self.vapi.l2fib_add_del(host.mac, self.bd_id, pg_if.sw_if_index,
210 self.deleted_hosts_by_pg_idx[pg_if.sw_if_index].append(host)
211 del self.hosts_by_pg_idx[pg_if.sw_if_index][0]
213 percentage = counter / count * 100
214 if percentage > percent:
215 self.logger.info("Delete %d L2 FIB entries .. %d%% done"
216 % (count, percentage))
218 self.logger.info(self.vapi.ppcli("show l2fib"))
220 def create_stream(self, src_if, packet_sizes, deleted=False):
222 Create input packet stream for defined interface using hosts or
225 :param object src_if: Interface to create packet stream for.
226 :param list packet_sizes: List of required packet sizes.
227 :param boolean deleted: Set to True if deleted_hosts list required.
228 :return: Stream of packets.
231 src_hosts = self.hosts_by_pg_idx[src_if.sw_if_index]
232 for dst_if in self.flows[src_if]:
233 dst_hosts = self.deleted_hosts_by_pg_idx[dst_if.sw_if_index]\
234 if deleted else self.hosts_by_pg_idx[dst_if.sw_if_index]
235 n_int = len(dst_hosts)
236 for i in range(0, n_int):
237 dst_host = dst_hosts[i]
238 src_host = random.choice(src_hosts)
239 pkt_info = self.create_packet_info(
240 src_if.sw_if_index, dst_if.sw_if_index)
241 payload = self.info_to_payload(pkt_info)
242 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
243 IP(src=src_host.ip4, dst=dst_host.ip4) /
244 UDP(sport=1234, dport=1234) /
246 pkt_info.data = p.copy()
247 size = random.choice(packet_sizes)
248 self.extend_packet(p, size)
252 def verify_capture(self, pg_if, capture):
254 Verify captured input packet stream for defined interface.
256 :param object pg_if: Interface to verify captured packet stream for.
257 :param list capture: Captured packet stream.
260 for i in self.pg_interfaces:
261 last_info[i.sw_if_index] = None
262 dst_sw_if_index = pg_if.sw_if_index
263 for packet in capture:
264 payload_info = self.payload_to_info(str(packet[Raw]))
268 packet_index = payload_info.index
269 self.assertEqual(payload_info.dst, dst_sw_if_index)
270 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
271 (pg_if.name, payload_info.src, packet_index))
272 next_info = self.get_next_packet_info_for_interface2(
273 payload_info.src, dst_sw_if_index,
274 last_info[payload_info.src])
275 last_info[payload_info.src] = next_info
276 self.assertTrue(next_info is not None)
277 self.assertEqual(packet_index, next_info.index)
278 saved_packet = next_info.data
279 # Check standard fields
280 self.assertEqual(ip.src, saved_packet[IP].src)
281 self.assertEqual(ip.dst, saved_packet[IP].dst)
282 self.assertEqual(udp.sport, saved_packet[UDP].sport)
283 self.assertEqual(udp.dport, saved_packet[UDP].dport)
285 self.logger.error("Unexpected or invalid packet:")
286 self.logger.error(packet.show())
288 for i in self.pg_interfaces:
289 remaining_packet = self.get_next_packet_info_for_interface2(
290 i, dst_sw_if_index, last_info[i.sw_if_index])
292 remaining_packet is None,
293 "Port %u: Packet expected from source %u didn't arrive" %
294 (dst_sw_if_index, i.sw_if_index))
296 def run_verify_test(self):
298 # Create incoming packet streams for packet-generator interfaces
299 for i in self.pg_interfaces:
300 pkts = self.create_stream(i, self.pg_if_packet_sizes)
303 # Enable packet capture and start packet sending
304 self.pg_enable_capture(self.pg_interfaces)
308 # Verify outgoing packet streams per packet-generator interface
309 for i in self.pg_interfaces:
310 capture = i.get_capture()
311 self.logger.info("Verifying capture on interface %s" % i.name)
312 self.verify_capture(i, capture)
314 def run_verify_negat_test(self):
316 # Create incoming packet streams for packet-generator interfaces for
317 # deleted MAC addresses
318 self.packet_infos = {}
319 for i in self.pg_interfaces:
320 pkts = self.create_stream(i, self.pg_if_packet_sizes, deleted=True)
323 # Enable packet capture and start packet sending
324 self.pg_enable_capture(self.pg_interfaces)
328 # Verify outgoing packet streams per packet-generator interface
329 for i in self.pg_interfaces:
330 capture = i.get_capture()
331 self.logger.info("Verifying capture on interface %s" % i.name)
333 self.assertEqual(len(capture), 0)
334 except AssertionError:
335 self.logger.error("The capture on interface %s is not empty!"
337 raise AssertionError("%d != 0" % len(capture))
339 def test_l2_fib_01(self):
340 """ L2 FIB test 1 - program 100 MAC addresses
343 # Create test host entries
344 self.create_hosts(100)
346 # Add first 100 MAC entries to L2 FIB
347 self.config_l2_fib_entries(100)
350 self.run_verify_test()
352 def test_l2_fib_02(self):
353 """ L2 FIB test 2 - delete 12 MAC entries
356 # Delete 12 MAC entries (3 per interface) from L2 FIB
357 self.delete_l2_fib_entry(12)
360 self.run_verify_test()
363 self.run_verify_negat_test()
365 def test_l2_fib_03(self):
366 """ L2 FIB test 3 - program new 100 MAC addresses
369 # Create new test host entries
370 self.create_hosts(100, start=100)
372 # Add new 100 MAC entries to L2 FIB
373 self.config_l2_fib_entries(100, start=22)
376 self.run_verify_test()
378 def test_l2_fib_04(self):
379 """ L2 FIB test 4 - delete 160 MAC entries
382 # Delete 160 MAC entries (40 per interface) from L2 FIB
383 self.delete_l2_fib_entry(160)
386 self.run_verify_negat_test()
389 if __name__ == '__main__':
390 unittest.main(testRunner=VppTestRunner)