test: consolidate the multiple versions of send_and_*
[vpp.git] / test / test_dvr.py
1 #!/usr/bin/env python
2 import random
3 import socket
4 import unittest
5
6 from framework import VppTestCase, VppTestRunner
7 from vpp_sub_interface import VppSubInterface, VppDot1QSubint
8 from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto, VppIpMRoute, \
9     VppMRoutePath, MRouteEntryFlags, MRouteItfFlags
10 from vpp_papi_provider import L2_VTR_OP
11
12 from scapy.packet import Raw
13 from scapy.layers.l2 import Ether, Dot1Q, ARP
14 from scapy.layers.inet import IP, UDP
15 from util import ppp
16
17
18 class TestDVR(VppTestCase):
19     """ Distributed Virtual Router """
20
21     def setUp(self):
22         super(TestDVR, self).setUp()
23
24         self.create_pg_interfaces(range(4))
25         self.create_loopback_interfaces(range(1))
26
27         for i in self.pg_interfaces:
28             i.admin_up()
29
30         self.loop0.config_ip4()
31
32     def tearDown(self):
33         for i in self.pg_interfaces:
34             i.admin_down()
35         self.loop0.unconfig_ip4()
36
37         super(TestDVR, self).tearDown()
38
39     def assert_same_mac_addr(self, tx, rx):
40         t_eth = tx[Ether]
41         for p in rx:
42             r_eth = p[Ether]
43             self.assertEqual(t_eth.src, r_eth.src)
44             self.assertEqual(t_eth.dst, r_eth.dst)
45
46     def assert_has_vlan_tag(self, tag, rx):
47         for p in rx:
48             r_1q = p[Dot1Q]
49             self.assertEqual(tag, r_1q.vlan)
50
51     def assert_has_no_tag(self, rx):
52         for p in rx:
53             self.assertFalse(p.haslayer(Dot1Q))
54
55     def test_dvr(self):
56         """ Distributed Virtual Router """
57
58         #
59         # A packet destined to an IP address that is L2 bridged via
60         # a non-tag interface
61         #
62         ip_non_tag_bridged = "10.10.10.10"
63         ip_tag_bridged = "10.10.10.11"
64         any_src_addr = "1.1.1.1"
65
66         pkt_no_tag = (Ether(src=self.pg0.remote_mac,
67                             dst=self.loop0.local_mac) /
68                       IP(src=any_src_addr,
69                          dst=ip_non_tag_bridged) /
70                       UDP(sport=1234, dport=1234) /
71                       Raw('\xa5' * 100))
72         pkt_tag = (Ether(src=self.pg0.remote_mac,
73                          dst=self.loop0.local_mac) /
74                    IP(src=any_src_addr,
75                       dst=ip_tag_bridged) /
76                    UDP(sport=1234, dport=1234) /
77                    Raw('\xa5' * 100))
78
79         #
80         # Two sub-interfaces so we can test VLAN tag push/pop
81         #
82         sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92)
83         sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93)
84         sub_if_on_pg2.admin_up()
85         sub_if_on_pg3.admin_up()
86
87         #
88         # Put all the interfaces into a new bridge domain
89         #
90         self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1)
91         self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1)
92         self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index, 1)
93         self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index, 1)
94         self.vapi.sw_interface_set_l2_bridge(self.loop0.sw_if_index, 1, bvi=1)
95
96         self.vapi.sw_interface_set_l2_tag_rewrite(sub_if_on_pg2.sw_if_index,
97                                                   L2_VTR_OP.L2_POP_1,
98                                                   92)
99         self.vapi.sw_interface_set_l2_tag_rewrite(sub_if_on_pg3.sw_if_index,
100                                                   L2_VTR_OP.L2_POP_1,
101                                                   93)
102
103         #
104         # Add routes to bridge the traffic via a tagged an nontagged interface
105         #
106         route_no_tag = VppIpRoute(
107             self, ip_non_tag_bridged, 32,
108             [VppRoutePath("0.0.0.0",
109                           self.pg1.sw_if_index,
110                           proto=DpoProto.DPO_PROTO_ETHERNET)])
111         route_no_tag.add_vpp_config()
112
113         #
114         # Inject the packet that arrives and leaves on a non-tagged interface
115         # Since it's 'bridged' expect that the MAC headed is unchanged.
116         #
117         self.pg0.add_stream(pkt_no_tag)
118
119         self.pg_enable_capture(self.pg_interfaces)
120         self.pg_start()
121
122         rx = self.pg1.get_capture(1)
123
124         self.assertEqual(rx[0][Ether].dst, pkt_no_tag[Ether].dst)
125         self.assertEqual(rx[0][Ether].src, pkt_no_tag[Ether].src)
126
127         #
128         # Add routes to bridge the traffic via a tagged interface
129         #
130         route_with_tag = VppIpRoute(
131             self, ip_tag_bridged, 32,
132             [VppRoutePath("0.0.0.0",
133                           sub_if_on_pg3.sw_if_index,
134                           proto=DpoProto.DPO_PROTO_ETHERNET)])
135         route_with_tag.add_vpp_config()
136
137         #
138         # Inject the packet that arrives and leaves on a non-tagged interface
139         # Since it's 'bridged' expect that the MAC headed is unchanged.
140         #
141         rx = self.send_and_expect(self.pg0, pkt_tag * 65, self.pg3)
142         self.assert_same_mac_addr(pkt_tag, rx)
143         self.assert_has_vlan_tag(93, rx)
144
145         #
146         # Tag to tag
147         #
148         pkt_tag_to_tag = (Ether(src=self.pg2.remote_mac,
149                                 dst=self.loop0.local_mac) /
150                           Dot1Q(vlan=92) /
151                           IP(src=any_src_addr,
152                              dst=ip_tag_bridged) /
153                           UDP(sport=1234, dport=1234) /
154                           Raw('\xa5' * 100))
155
156         rx = self.send_and_expect(self.pg2, pkt_tag_to_tag * 65, self.pg3)
157         self.assert_same_mac_addr(pkt_tag_to_tag, rx)
158         self.assert_has_vlan_tag(93, rx)
159
160         #
161         # Tag to non-Tag
162         #
163         pkt_tag_to_non_tag = (Ether(src=self.pg2.remote_mac,
164                                     dst=self.loop0.local_mac) /
165                               Dot1Q(vlan=92) /
166                               IP(src=any_src_addr,
167                                  dst=ip_non_tag_bridged) /
168                               UDP(sport=1234, dport=1234) /
169                               Raw('\xa5' * 100))
170
171         rx = self.send_and_expect(self.pg2, pkt_tag_to_non_tag * 65, self.pg1)
172         self.assert_same_mac_addr(pkt_tag_to_tag, rx)
173         self.assert_has_no_tag(rx)
174
175         #
176         # cleanup
177         #
178         self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1,
179                                              enable=0)
180         self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1,
181                                              enable=0)
182         self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index,
183                                              1, enable=0)
184         self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index,
185                                              1, enable=0)
186         self.vapi.sw_interface_set_l2_bridge(self.loop0.sw_if_index,
187                                              1, bvi=1, enable=0)
188
189         #
190         # the explicit route delete is require so it happens before
191         # the sbu-interface delete. subinterface delete is required
192         # because that object type does not use the object registry
193         #
194         route_no_tag.remove_vpp_config()
195         route_with_tag.remove_vpp_config()
196         sub_if_on_pg3.remove_vpp_config()
197         sub_if_on_pg2.remove_vpp_config()
198
199     def test_l2_emulation(self):
200         """ L2 Emulation """
201
202         #
203         # non distinct L3 packets, in the tag/non-tag combos
204         #
205         pkt_no_tag = (Ether(src=self.pg0.remote_mac,
206                             dst=self.pg1.remote_mac) /
207                       IP(src="2.2.2.2",
208                          dst="1.1.1.1") /
209                       UDP(sport=1234, dport=1234) /
210                       Raw('\xa5' * 100))
211         pkt_to_tag = (Ether(src=self.pg0.remote_mac,
212                             dst=self.pg2.remote_mac) /
213                       IP(src="2.2.2.2",
214                          dst="1.1.1.2") /
215                       UDP(sport=1234, dport=1234) /
216                       Raw('\xa5' * 100))
217         pkt_from_tag = (Ether(src=self.pg3.remote_mac,
218                               dst=self.pg2.remote_mac) /
219                         Dot1Q(vlan=93) /
220                         IP(src="2.2.2.2",
221                            dst="1.1.1.1") /
222                         UDP(sport=1234, dport=1234) /
223                         Raw('\xa5' * 100))
224         pkt_from_to_tag = (Ether(src=self.pg3.remote_mac,
225                                  dst=self.pg2.remote_mac) /
226                            Dot1Q(vlan=93) /
227                            IP(src="2.2.2.2",
228                               dst="1.1.1.2") /
229                            UDP(sport=1234, dport=1234) /
230                            Raw('\xa5' * 100))
231         pkt_bcast = (Ether(src=self.pg0.remote_mac,
232                            dst="ff:ff:ff:ff:ff:ff") /
233                      IP(src="2.2.2.2",
234                         dst="255.255.255.255") /
235                      UDP(sport=1234, dport=1234) /
236                      Raw('\xa5' * 100))
237
238         #
239         # A couple of sub-interfaces for tags
240         #
241         sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92)
242         sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93)
243         sub_if_on_pg2.admin_up()
244         sub_if_on_pg3.admin_up()
245
246         #
247         # Put all the interfaces into a new bridge domain
248         #
249         self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1)
250         self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1)
251         self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index, 1)
252         self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index, 1)
253         self.vapi.sw_interface_set_l2_tag_rewrite(sub_if_on_pg2.sw_if_index,
254                                                   L2_VTR_OP.L2_POP_1,
255                                                   92)
256         self.vapi.sw_interface_set_l2_tag_rewrite(sub_if_on_pg3.sw_if_index,
257                                                   L2_VTR_OP.L2_POP_1,
258                                                   93)
259
260         #
261         # Disable UU flooding, learning and ARM terminaation. makes this test
262         # easier as unicast packets are dropped if not extracted.
263         #
264         self.vapi.bridge_flags(1, 0, (1 << 0) | (1 << 3) | (1 << 4))
265
266         #
267         # Add a DVR route to steer traffic at L3
268         #
269         route_1 = VppIpRoute(self, "1.1.1.1", 32,
270                              [VppRoutePath("0.0.0.0",
271                                            self.pg1.sw_if_index,
272                                            proto=DpoProto.DPO_PROTO_ETHERNET)])
273         route_2 = VppIpRoute(self, "1.1.1.2", 32,
274                              [VppRoutePath("0.0.0.0",
275                                            sub_if_on_pg2.sw_if_index,
276                                            proto=DpoProto.DPO_PROTO_ETHERNET)])
277         route_1.add_vpp_config()
278         route_2.add_vpp_config()
279
280         #
281         # packets are dropped because bridge does not flood unkown unicast
282         #
283         self.send_and_assert_no_replies(self.pg0, pkt_no_tag)
284
285         #
286         # Enable L3 extraction on pgs
287         #
288         self.vapi.sw_interface_set_l2_emulation(self.pg0.sw_if_index)
289         self.vapi.sw_interface_set_l2_emulation(self.pg1.sw_if_index)
290         self.vapi.sw_interface_set_l2_emulation(sub_if_on_pg2.sw_if_index)
291         self.vapi.sw_interface_set_l2_emulation(sub_if_on_pg3.sw_if_index)
292
293         #
294         # now we expect the packet forward according to the DVR route
295         #
296         rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1)
297         self.assert_same_mac_addr(pkt_no_tag, rx)
298         self.assert_has_no_tag(rx)
299
300         rx = self.send_and_expect(self.pg0, pkt_to_tag * 65, self.pg2)
301         self.assert_same_mac_addr(pkt_to_tag, rx)
302         self.assert_has_vlan_tag(92, rx)
303
304         rx = self.send_and_expect(self.pg3, pkt_from_tag * 65, self.pg1)
305         self.assert_same_mac_addr(pkt_from_tag, rx)
306         self.assert_has_no_tag(rx)
307
308         rx = self.send_and_expect(self.pg3, pkt_from_to_tag * 65, self.pg2)
309         self.assert_same_mac_addr(pkt_from_tag, rx)
310         self.assert_has_vlan_tag(92, rx)
311
312         #
313         # but broadcast packets are still flooded
314         #
315         self.send_and_expect(self.pg0, pkt_bcast * 33, self.pg2)
316
317         #
318         # cleanup
319         #
320         self.vapi.sw_interface_set_l2_emulation(self.pg0.sw_if_index,
321                                                 enable=0)
322         self.vapi.sw_interface_set_l2_emulation(self.pg1.sw_if_index,
323                                                 enable=0)
324         self.vapi.sw_interface_set_l2_emulation(sub_if_on_pg2.sw_if_index,
325                                                 enable=0)
326         self.vapi.sw_interface_set_l2_emulation(sub_if_on_pg3.sw_if_index,
327                                                 enable=0)
328
329         self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index,
330                                              1, enable=0)
331         self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
332                                              1, enable=0)
333         self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index,
334                                              1, enable=0)
335         self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index,
336                                              1, enable=0)
337
338         route_1.remove_vpp_config()
339         route_2.remove_vpp_config()
340         sub_if_on_pg3.remove_vpp_config()
341         sub_if_on_pg2.remove_vpp_config()
342
343
344 if __name__ == '__main__':
345     unittest.main(testRunner=VppTestRunner)