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(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()
99 Clear trace and packet infos before running each test.
101 super(TestL2bd, self).setUp()
102 self.packet_infos = {}
106 Show various debug prints after each test.
108 super(TestL2bd, self).tearDown()
109 if not self.vpp_dead:
110 self.logger.info(self.vapi.ppcli("show l2fib verbose"))
111 self.logger.info(self.vapi.ppcli("show bridge-domain %s detail" %
115 def create_hosts_and_learn(cls, count):
117 Create required number of host MAC addresses and distribute them among
118 interfaces. Create host IPv4 address for every host MAC address. Create
119 L2 MAC packet stream with host MAC addresses per interface to let
120 the bridge domain learn these MAC addresses.
122 :param count: Integer number of hosts to create MAC/IPv4 addresses for.
124 n_int = len(cls.pg_interfaces)
125 macs_per_if = count / n_int
127 for pg_if in cls.pg_interfaces:
129 start_nr = macs_per_if * i
130 end_nr = count if i == (n_int - 1) else macs_per_if * (i + 1)
131 cls.hosts_by_pg_idx[pg_if.sw_if_index] = []
132 hosts = cls.hosts_by_pg_idx[pg_if.sw_if_index]
134 for j in range(start_nr, end_nr):
136 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
137 "172.17.1%02x.%u" % (pg_if.sw_if_index, j))
138 packet = (Ether(dst="ff:ff:ff:ff:ff:ff", src=host.mac))
140 if hasattr(pg_if, 'sub_if'):
141 packet = pg_if.sub_if.add_dot1_layer(packet)
142 packets.append(packet)
143 pg_if.add_stream(packets)
144 cls.logger.info("Sending broadcast eth frames for MAC learning")
147 def create_stream(self, src_if, packet_sizes, packets_per_burst):
149 Create input packet stream for defined interface.
151 :param object src_if: Interface to create packet stream for.
152 :param list packet_sizes: List of required packet sizes.
153 :param int packets_per_burst: Number of packets in burst.
154 :return: Stream of packets.
157 for i in range(0, packets_per_burst):
158 dst_if = self.flows[src_if][i % 2]
159 dst_host = random.choice(self.hosts_by_pg_idx[dst_if.sw_if_index])
160 src_host = random.choice(self.hosts_by_pg_idx[src_if.sw_if_index])
161 pkt_info = self.create_packet_info(
162 src_if.sw_if_index, dst_if.sw_if_index)
163 payload = self.info_to_payload(pkt_info)
164 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
165 IP(src=src_host.ip4, dst=dst_host.ip4) /
166 UDP(sport=1234, dport=1234) /
168 pkt_info.data = p.copy()
169 if hasattr(src_if, 'sub_if'):
170 p = src_if.sub_if.add_dot1_layer(p)
171 size = random.choice(packet_sizes)
172 self.extend_packet(p, size)
176 def verify_capture(self, pg_if, capture):
178 Verify captured input packet stream for defined interface.
180 :param object pg_if: Interface to verify captured packet stream for.
181 :param list capture: Captured packet stream.
184 for i in self.pg_interfaces:
185 last_info[i.sw_if_index] = None
186 dst_sw_if_index = pg_if.sw_if_index
187 for packet in capture:
188 payload_info = self.payload_to_info(str(packet[Raw]))
189 src_sw_if_index = payload_info.src
191 for ifc in self.pg_interfaces:
193 if ifc.sw_if_index == src_sw_if_index:
196 if hasattr(src_if, 'sub_if'):
197 # Check VLAN tags and Ethernet header
198 packet = src_if.sub_if.remove_dot1_layer(packet)
199 self.assertTrue(Dot1Q not in packet)
203 packet_index = payload_info.index
204 self.assertEqual(payload_info.dst, dst_sw_if_index)
205 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
206 (pg_if.name, payload_info.src, packet_index))
207 next_info = self.get_next_packet_info_for_interface2(
208 payload_info.src, dst_sw_if_index,
209 last_info[payload_info.src])
210 last_info[payload_info.src] = next_info
211 self.assertTrue(next_info is not None)
212 self.assertEqual(packet_index, next_info.index)
213 saved_packet = next_info.data
214 # Check standard fields
215 self.assertEqual(ip.src, saved_packet[IP].src)
216 self.assertEqual(ip.dst, saved_packet[IP].dst)
217 self.assertEqual(udp.sport, saved_packet[UDP].sport)
218 self.assertEqual(udp.dport, saved_packet[UDP].dport)
220 self.logger.error(ppp("Unexpected or invalid packet:", packet))
222 for i in self.pg_interfaces:
223 remaining_packet = self.get_next_packet_info_for_interface2(
224 i, dst_sw_if_index, last_info[i.sw_if_index])
226 remaining_packet is None,
227 "Port %u: Packet expected from source %u didn't arrive" %
228 (dst_sw_if_index, i.sw_if_index))
230 def run_l2bd_test(self, pkts_per_burst):
231 """ L2BD MAC learning test """
233 # Create incoming packet streams for packet-generator interfaces
234 for i in self.pg_interfaces:
235 packet_sizes = self.sub_if_packet_sizes if hasattr(i, 'sub_if') \
236 else self.pg_if_packet_sizes
237 pkts = self.create_stream(i, packet_sizes, pkts_per_burst)
240 # Enable packet capture and start packet sending
241 self.pg_enable_capture(self.pg_interfaces)
244 # Verify outgoing packet streams per packet-generator interface
245 for i in self.pg_interfaces:
246 capture = i.get_capture()
247 self.logger.info("Verifying capture on interface %s" % i.name)
248 self.verify_capture(i, capture)
250 def test_l2bd_sl(self):
251 """ L2BD MAC learning single-loop test
257 3 interfaces: untagged, dot1q, dot1ad (dot1q used instead of
258 dot1ad in the first version)
260 2.sending l2 eth pkts between 3 interface
261 64B, 512B, 1518B, 9200B (ether_size)
262 burst of 2 pkts per interface
265 self.run_l2bd_test(self.sl_pkts_per_burst)
267 def test_l2bd_dl(self):
268 """ L2BD MAC learning dual-loop test
274 3 interfaces: untagged, dot1q, dot1ad (dot1q used instead of
275 dot1ad in the first version)
277 2.sending l2 eth pkts between 3 interface
278 64B, 512B, 1518B, 9200B (ether_size)
279 burst of 257 pkts per interface
282 self.run_l2bd_test(self.dl_pkts_per_burst)
285 if __name__ == '__main__':
286 unittest.main(testRunner=VppTestRunner)