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
71 from util import Host, ppp
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()
133 super(TestL2fib, self).setUp()
134 self.reset_packet_infos()
138 Show various debug prints after each test.
140 super(TestL2fib, self).tearDown()
141 if not self.vpp_dead:
142 self.logger.info(self.vapi.ppcli("show l2fib verbose"))
143 self.logger.info(self.vapi.ppcli("show bridge-domain %s detail"
146 def create_hosts(self, count, start=0):
148 Create required number of host MAC addresses and distribute them among
149 interfaces. Create host IPv4 address for every host MAC address.
151 :param int count: Number of hosts to create MAC/IPv4 addresses for.
152 :param int start: Number to start numbering from.
154 n_int = len(self.pg_interfaces)
155 macs_per_if = count / n_int
157 for pg_if in self.pg_interfaces:
159 start_nr = macs_per_if * i + start
160 end_nr = count + start if i == (n_int - 1) \
161 else macs_per_if * (i + 1) + start
162 hosts = self.hosts_by_pg_idx[pg_if.sw_if_index]
163 for j in range(start_nr, end_nr):
165 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
166 "172.17.1%02x.%u" % (pg_if.sw_if_index, j))
169 def config_l2_fib_entries(self, count, start=0):
171 Create required number of L2 FIB entries.
173 :param int count: Number of L2 FIB entries to be created.
174 :param int start: Starting index of the host list. (Default value = 0)
176 n_int = len(self.pg_interfaces)
179 for pg_if in self.pg_interfaces:
180 end_nr = start + count / n_int
181 for j in range(start, end_nr):
182 host = self.hosts_by_pg_idx[pg_if.sw_if_index][j]
183 self.vapi.l2fib_add_del(host.mac, self.bd_id, pg_if.sw_if_index,
186 percentage = counter / count * 100
187 if percentage > percent:
188 self.logger.info("Configure %d L2 FIB entries .. %d%% done"
189 % (count, percentage))
191 self.logger.info(self.vapi.ppcli("show l2fib"))
193 def delete_l2_fib_entry(self, count):
195 Delete required number of L2 FIB entries.
197 :param int count: Number of L2 FIB entries to be created.
199 n_int = len(self.pg_interfaces)
202 for pg_if in self.pg_interfaces:
203 for j in range(count / n_int):
204 host = self.hosts_by_pg_idx[pg_if.sw_if_index][0]
205 self.vapi.l2fib_add_del(host.mac, self.bd_id, pg_if.sw_if_index,
207 self.deleted_hosts_by_pg_idx[pg_if.sw_if_index].append(host)
208 del self.hosts_by_pg_idx[pg_if.sw_if_index][0]
210 percentage = counter / count * 100
211 if percentage > percent:
212 self.logger.info("Delete %d L2 FIB entries .. %d%% done"
213 % (count, percentage))
215 self.logger.info(self.vapi.ppcli("show l2fib"))
217 def create_stream(self, src_if, packet_sizes, deleted=False):
219 Create input packet stream for defined interface using hosts or
222 :param object src_if: Interface to create packet stream for.
223 :param list packet_sizes: List of required packet sizes.
224 :param boolean deleted: Set to True if deleted_hosts list required.
225 :return: Stream of packets.
228 src_hosts = self.hosts_by_pg_idx[src_if.sw_if_index]
229 for dst_if in self.flows[src_if]:
230 dst_hosts = self.deleted_hosts_by_pg_idx[dst_if.sw_if_index]\
231 if deleted else self.hosts_by_pg_idx[dst_if.sw_if_index]
232 n_int = len(dst_hosts)
233 for i in range(0, n_int):
234 dst_host = dst_hosts[i]
235 src_host = random.choice(src_hosts)
236 pkt_info = self.create_packet_info(src_if, dst_if)
237 payload = self.info_to_payload(pkt_info)
238 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
239 IP(src=src_host.ip4, dst=dst_host.ip4) /
240 UDP(sport=1234, dport=1234) /
242 pkt_info.data = p.copy()
243 size = random.choice(packet_sizes)
244 self.extend_packet(p, size)
248 def verify_capture(self, pg_if, capture):
250 Verify captured input packet stream for defined interface.
252 :param object pg_if: Interface to verify captured packet stream for.
253 :param list capture: Captured packet stream.
256 for i in self.pg_interfaces:
257 last_info[i.sw_if_index] = None
258 dst_sw_if_index = pg_if.sw_if_index
259 for packet in capture:
260 payload_info = self.payload_to_info(str(packet[Raw]))
264 packet_index = payload_info.index
265 self.assertEqual(payload_info.dst, dst_sw_if_index)
266 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
267 (pg_if.name, payload_info.src, packet_index))
268 next_info = self.get_next_packet_info_for_interface2(
269 payload_info.src, dst_sw_if_index,
270 last_info[payload_info.src])
271 last_info[payload_info.src] = next_info
272 self.assertTrue(next_info is not None)
273 self.assertEqual(packet_index, next_info.index)
274 saved_packet = next_info.data
275 # Check standard fields
276 self.assertEqual(ip.src, saved_packet[IP].src)
277 self.assertEqual(ip.dst, saved_packet[IP].dst)
278 self.assertEqual(udp.sport, saved_packet[UDP].sport)
279 self.assertEqual(udp.dport, saved_packet[UDP].dport)
281 self.logger.error(ppp("Unexpected or invalid packet:", packet))
283 for i in self.pg_interfaces:
284 remaining_packet = self.get_next_packet_info_for_interface2(
285 i, dst_sw_if_index, last_info[i.sw_if_index])
287 remaining_packet is None,
288 "Port %u: Packet expected from source %u didn't arrive" %
289 (dst_sw_if_index, i.sw_if_index))
291 def run_verify_test(self):
293 # Create incoming packet streams for packet-generator interfaces
294 for i in self.pg_interfaces:
295 pkts = self.create_stream(i, self.pg_if_packet_sizes)
298 # Enable packet capture and start packet sending
299 self.pg_enable_capture(self.pg_interfaces)
303 # Verify outgoing packet streams per packet-generator interface
304 for i in self.pg_interfaces:
305 capture = i.get_capture()
306 self.logger.info("Verifying capture on interface %s" % i.name)
307 self.verify_capture(i, capture)
309 def run_verify_negat_test(self):
311 # Create incoming packet streams for packet-generator interfaces for
312 # deleted MAC addresses
313 self.reset_packet_infos()
314 for i in self.pg_interfaces:
315 pkts = self.create_stream(i, self.pg_if_packet_sizes, deleted=True)
318 # Enable packet capture and start packet sending
319 self.pg_enable_capture(self.pg_interfaces)
323 # Verify outgoing packet streams per packet-generator interface
324 for i in self.pg_interfaces:
325 i.assert_nothing_captured(remark="outgoing interface")
327 def test_l2_fib_01(self):
328 """ L2 FIB test 1 - program 100 MAC addresses
331 # Create test host entries
332 self.create_hosts(100)
334 # Add first 100 MAC entries to L2 FIB
335 self.config_l2_fib_entries(100)
338 self.run_verify_test()
340 def test_l2_fib_02(self):
341 """ L2 FIB test 2 - delete 12 MAC entries
344 # Delete 12 MAC entries (3 per interface) from L2 FIB
345 self.delete_l2_fib_entry(12)
348 self.run_verify_test()
351 self.run_verify_negat_test()
353 def test_l2_fib_03(self):
354 """ L2 FIB test 3 - program new 100 MAC addresses
357 # Create new test host entries
358 self.create_hosts(100, start=100)
360 # Add new 100 MAC entries to L2 FIB
361 self.config_l2_fib_entries(100, start=22)
364 self.run_verify_test()
366 def test_l2_fib_04(self):
367 """ L2 FIB test 4 - delete 160 MAC entries
370 # Delete 160 MAC entries (40 per interface) from L2 FIB
371 self.delete_l2_fib_entry(160)
374 self.run_verify_negat_test()
377 if __name__ == '__main__':
378 unittest.main(testRunner=VppTestRunner)