6 from scapy.packet import Raw
7 from scapy.layers.l2 import Ether, Dot1Q
8 from scapy.layers.inet import IP, UDP
10 from framework import VppTestCase, VppTestRunner
11 from util import Host, ppp
12 from vpp_sub_interface import VppDot1QSubint, VppDot1ADSubint
15 class TestL2bd(VppTestCase):
16 """ L2BD Test Case """
21 Perform standard class setup (defined by class method setUpClass in
22 class VppTestCase) before running the test case, set test case related
23 variables and configure VPP.
25 :var int bd_id: Bridge domain ID.
26 :var int mac_entries_count: Number of MAC entries for bridge-domain to
28 :var int dot1q_tag: VLAN tag for dot1q sub-interface.
29 :var int dot1ad_sub_id: SubID of dot1ad sub-interface.
30 :var int dot1ad_outer_tag: VLAN S-tag for dot1ad sub-interface.
31 :var int dot1ad_inner_tag: VLAN C-tag for dot1ad sub-interface.
32 :var int sl_pkts_per_burst: Number of packets in burst for single-loop
34 :var int dl_pkts_per_burst: Number of packets in burst for dual-loop
37 super(TestL2bd, cls).setUpClass()
41 cls.mac_entries_count = 100
42 # cls.dot1q_sub_id = 100
44 cls.dot1ad_sub_id = 20
45 cls.dot1ad_outer_tag = 200
46 cls.dot1ad_inner_tag = 300
47 cls.sl_pkts_per_burst = 2
48 cls.dl_pkts_per_burst = 257
51 # create 3 pg interfaces
52 cls.create_pg_interfaces(range(3))
54 # create 2 sub-interfaces for pg1 and pg2
55 cls.sub_interfaces = [
56 VppDot1QSubint(cls, cls.pg1, cls.dot1q_tag),
57 VppDot1ADSubint(cls, cls.pg2, cls.dot1ad_sub_id,
58 cls.dot1ad_outer_tag, cls.dot1ad_inner_tag)]
60 # packet flows mapping pg0 -> pg1, pg2, etc.
62 cls.flows[cls.pg0] = [cls.pg1, cls.pg2]
63 cls.flows[cls.pg1] = [cls.pg0, cls.pg2]
64 cls.flows[cls.pg2] = [cls.pg0, cls.pg1]
67 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
68 cls.sub_if_packet_sizes = [64, 512, 1518 + 4, 9018 + 4]
70 cls.interfaces = list(cls.pg_interfaces)
71 cls.interfaces.extend(cls.sub_interfaces)
73 # Create BD with MAC learning enabled and put interfaces and
74 # sub-interfaces to this BD
75 for pg_if in cls.pg_interfaces:
76 sw_if_index = pg_if.sub_if.sw_if_index \
77 if hasattr(pg_if, 'sub_if') else pg_if.sw_if_index
78 cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=sw_if_index,
81 # setup all interfaces
82 for i in cls.interfaces:
85 # mapping between packet-generator index and lists of test hosts
86 cls.hosts_by_pg_idx = dict()
88 # create test host entries and inject packets to learn MAC entries
89 # in the bridge-domain
90 cls.create_hosts_and_learn(cls.mac_entries_count)
91 cls.logger.info(cls.vapi.ppcli("show l2fib"))
94 super(TestL2bd, cls).tearDownClass()
98 def tearDownClass(cls):
99 super(TestL2bd, cls).tearDownClass()
103 Clear trace and packet infos before running each test.
105 super(TestL2bd, self).setUp()
106 self.reset_packet_infos()
110 Show various debug prints after each test.
112 super(TestL2bd, self).tearDown()
113 if not self.vpp_dead:
114 self.logger.info(self.vapi.ppcli("show l2fib verbose"))
115 self.logger.info(self.vapi.ppcli("show bridge-domain %s detail" %
119 def create_hosts_and_learn(cls, count):
121 Create required number of host MAC addresses and distribute them among
122 interfaces. Create host IPv4 address for every host MAC address. Create
123 L2 MAC packet stream with host MAC addresses per interface to let
124 the bridge domain learn these MAC addresses.
126 :param count: Integer number of hosts to create MAC/IPv4 addresses for.
128 n_int = len(cls.pg_interfaces)
129 macs_per_if = count // n_int
131 for pg_if in cls.pg_interfaces:
133 start_nr = macs_per_if * i
134 end_nr = count if i == (n_int - 1) else macs_per_if * (i + 1)
135 cls.hosts_by_pg_idx[pg_if.sw_if_index] = []
136 hosts = cls.hosts_by_pg_idx[pg_if.sw_if_index]
138 for j in range(start_nr, end_nr):
140 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
141 "172.17.1%02x.%u" % (pg_if.sw_if_index, j))
142 packet = (Ether(dst="ff:ff:ff:ff:ff:ff", src=host.mac))
144 if hasattr(pg_if, 'sub_if'):
145 packet = pg_if.sub_if.add_dot1_layer(packet)
146 packets.append(packet)
147 pg_if.add_stream(packets)
148 cls.logger.info("Sending broadcast eth frames for MAC learning")
151 def create_stream(self, src_if, packet_sizes, packets_per_burst):
153 Create input packet stream for defined interface.
155 :param object src_if: Interface to create packet stream for.
156 :param list packet_sizes: List of required packet sizes.
157 :param int packets_per_burst: Number of packets in burst.
158 :return: Stream of packets.
161 for i in range(0, packets_per_burst):
162 dst_if = self.flows[src_if][i % 2]
163 dst_host = random.choice(self.hosts_by_pg_idx[dst_if.sw_if_index])
164 src_host = random.choice(self.hosts_by_pg_idx[src_if.sw_if_index])
165 pkt_info = self.create_packet_info(src_if, dst_if)
166 payload = self.info_to_payload(pkt_info)
167 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
168 IP(src=src_host.ip4, dst=dst_host.ip4) /
169 UDP(sport=1234, dport=1234) /
171 pkt_info.data = p.copy()
172 if hasattr(src_if, 'sub_if'):
173 p = src_if.sub_if.add_dot1_layer(p)
174 size = random.choice(packet_sizes)
175 self.extend_packet(p, size)
179 def verify_capture(self, pg_if, capture):
181 Verify captured input packet stream for defined interface.
183 :param object pg_if: Interface to verify captured packet stream for.
184 :param list capture: Captured packet stream.
187 for i in self.pg_interfaces:
188 last_info[i.sw_if_index] = None
189 dst_sw_if_index = pg_if.sw_if_index
190 for packet in capture:
191 payload_info = self.payload_to_info(packet[Raw])
192 src_sw_if_index = payload_info.src
194 for ifc in self.pg_interfaces:
196 if ifc.sw_if_index == src_sw_if_index:
199 if hasattr(src_if, 'sub_if'):
200 # Check VLAN tags and Ethernet header
201 packet = src_if.sub_if.remove_dot1_layer(packet)
202 self.assertTrue(Dot1Q not in packet)
206 packet_index = payload_info.index
207 self.assertEqual(payload_info.dst, dst_sw_if_index)
208 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
209 (pg_if.name, payload_info.src, packet_index))
210 next_info = self.get_next_packet_info_for_interface2(
211 payload_info.src, dst_sw_if_index,
212 last_info[payload_info.src])
213 last_info[payload_info.src] = next_info
214 self.assertTrue(next_info is not None)
215 self.assertEqual(packet_index, next_info.index)
216 saved_packet = next_info.data
217 # Check standard fields
218 self.assertEqual(ip.src, saved_packet[IP].src)
219 self.assertEqual(ip.dst, saved_packet[IP].dst)
220 self.assertEqual(udp.sport, saved_packet[UDP].sport)
221 self.assertEqual(udp.dport, saved_packet[UDP].dport)
223 self.logger.error(ppp("Unexpected or invalid packet:", packet))
225 for i in self.pg_interfaces:
226 remaining_packet = self.get_next_packet_info_for_interface2(
227 i, dst_sw_if_index, last_info[i.sw_if_index])
229 remaining_packet is None,
230 "Port %u: Packet expected from source %u didn't arrive" %
231 (dst_sw_if_index, i.sw_if_index))
233 def run_l2bd_test(self, pkts_per_burst):
234 """ L2BD MAC learning test """
236 # Create incoming packet streams for packet-generator interfaces
237 for i in self.pg_interfaces:
238 packet_sizes = self.sub_if_packet_sizes if hasattr(i, 'sub_if') \
239 else self.pg_if_packet_sizes
240 pkts = self.create_stream(i, packet_sizes, pkts_per_burst)
243 # Enable packet capture and start packet sending
244 self.pg_enable_capture(self.pg_interfaces)
247 # Verify outgoing packet streams per packet-generator interface
248 for i in self.pg_interfaces:
249 capture = i.get_capture()
250 self.logger.info("Verifying capture on interface %s" % i.name)
251 self.verify_capture(i, capture)
253 def test_l2bd_sl(self):
254 """ L2BD MAC learning single-loop test
259 learn 100 MAC entries
260 3 interfaces: untagged, dot1q, dot1ad (dot1q used instead of
261 dot1ad in the first version)
263 2.sending l2 eth pkts between 3 interface
264 64B, 512B, 1518B, 9200B (ether_size)
265 burst of 2 pkts per interface
268 self.run_l2bd_test(self.sl_pkts_per_burst)
270 def test_l2bd_dl(self):
271 """ L2BD MAC learning dual-loop test
276 learn 100 MAC entries
277 3 interfaces: untagged, dot1q, dot1ad (dot1q used instead of
278 dot1ad in the first version)
280 2.sending l2 eth pkts between 3 interface
281 64B, 512B, 1518B, 9200B (ether_size)
282 burst of 257 pkts per interface
285 self.run_l2bd_test(self.dl_pkts_per_burst)
288 if __name__ == '__main__':
289 unittest.main(testRunner=VppTestRunner)