blob: d2088ea2320ef2e1927a05e645a3672da8422e37 [file] [log] [blame]
Neale Ranns6f631152017-10-03 08:20:21 -07001#!/usr/bin/env python
Neale Ranns6f631152017-10-03 08:20:21 -07002import unittest
3
4from framework import VppTestCase, VppTestRunner
Klement Sekerab9ef2732018-06-24 22:49:33 +02005from vpp_sub_interface import VppDot1QSubint
6from vpp_ip_route import VppIpRoute, VppRoutePath
Neale Rannsb4743802018-09-05 09:13:57 -07007from vpp_papi_provider import L2_VTR_OP, L2_PORT_TYPE
Neale Ranns6f631152017-10-03 08:20:21 -07008
9from scapy.packet import Raw
Klement Sekerab9ef2732018-06-24 22:49:33 +020010from scapy.layers.l2 import Ether, Dot1Q
Neale Ranns6f631152017-10-03 08:20:21 -070011from scapy.layers.inet import IP, UDP
Neale Rannsf068c3e2018-01-03 04:18:48 -080012from socket import AF_INET, inet_pton
Neale Ranns6f631152017-10-03 08:20:21 -070013
14
15class TestDVR(VppTestCase):
Neale Ranns62fe07c2017-10-31 12:28:22 -070016 """ Distributed Virtual Router """
Neale Ranns6f631152017-10-03 08:20:21 -070017
18 def setUp(self):
19 super(TestDVR, self).setUp()
20
21 self.create_pg_interfaces(range(4))
Klement Sekerab9ef2732018-06-24 22:49:33 +020022 self.create_loopback_interfaces(1)
Neale Ranns6f631152017-10-03 08:20:21 -070023
24 for i in self.pg_interfaces:
25 i.admin_up()
26
27 self.loop0.config_ip4()
28
29 def tearDown(self):
30 for i in self.pg_interfaces:
31 i.admin_down()
32 self.loop0.unconfig_ip4()
33
34 super(TestDVR, self).tearDown()
35
Neale Ranns55d03782017-10-21 06:34:22 -070036 def assert_same_mac_addr(self, tx, rx):
37 t_eth = tx[Ether]
38 for p in rx:
39 r_eth = p[Ether]
40 self.assertEqual(t_eth.src, r_eth.src)
41 self.assertEqual(t_eth.dst, r_eth.dst)
42
43 def assert_has_vlan_tag(self, tag, rx):
44 for p in rx:
45 r_1q = p[Dot1Q]
46 self.assertEqual(tag, r_1q.vlan)
47
48 def assert_has_no_tag(self, rx):
49 for p in rx:
50 self.assertFalse(p.haslayer(Dot1Q))
51
Neale Ranns6f631152017-10-03 08:20:21 -070052 def test_dvr(self):
53 """ Distributed Virtual Router """
54
55 #
56 # A packet destined to an IP address that is L2 bridged via
57 # a non-tag interface
58 #
59 ip_non_tag_bridged = "10.10.10.10"
60 ip_tag_bridged = "10.10.10.11"
61 any_src_addr = "1.1.1.1"
62
63 pkt_no_tag = (Ether(src=self.pg0.remote_mac,
64 dst=self.loop0.local_mac) /
65 IP(src=any_src_addr,
66 dst=ip_non_tag_bridged) /
67 UDP(sport=1234, dport=1234) /
68 Raw('\xa5' * 100))
69 pkt_tag = (Ether(src=self.pg0.remote_mac,
70 dst=self.loop0.local_mac) /
71 IP(src=any_src_addr,
72 dst=ip_tag_bridged) /
73 UDP(sport=1234, dport=1234) /
74 Raw('\xa5' * 100))
75
76 #
77 # Two sub-interfaces so we can test VLAN tag push/pop
78 #
79 sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92)
80 sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93)
81 sub_if_on_pg2.admin_up()
82 sub_if_on_pg3.admin_up()
83
84 #
85 # Put all the interfaces into a new bridge domain
86 #
87 self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1)
88 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1)
89 self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index, 1)
90 self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index, 1)
Neale Rannsb4743802018-09-05 09:13:57 -070091 self.vapi.sw_interface_set_l2_bridge(self.loop0.sw_if_index, 1,
92 port_type=L2_PORT_TYPE.BVI)
Neale Ranns6f631152017-10-03 08:20:21 -070093
Ole Troane1ade682019-03-04 23:55:43 +010094 self.vapi.l2_interface_vlan_tag_rewrite(
95 sub_if_on_pg2.sw_if_index,
96 L2_VTR_OP.L2_POP_1,
97 92)
98 self.vapi.l2_interface_vlan_tag_rewrite(
99 sub_if_on_pg3.sw_if_index,
100 L2_VTR_OP.L2_POP_1,
101 93)
Neale Ranns6f631152017-10-03 08:20:21 -0700102
Neale Ranns6f631152017-10-03 08:20:21 -0700103 #
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,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800110 is_dvr=1)])
Neale Ranns6f631152017-10-03 08:20:21 -0700111 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 #
Neale Rannsf068c3e2018-01-03 04:18:48 -0800117 rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1)
118 self.assert_same_mac_addr(pkt_no_tag, rx)
119 self.assert_has_no_tag(rx)
Neale Ranns6f631152017-10-03 08:20:21 -0700120
121 #
122 # Add routes to bridge the traffic via a tagged interface
123 #
Neale Ranns55d03782017-10-21 06:34:22 -0700124 route_with_tag = VppIpRoute(
Neale Ranns6f631152017-10-03 08:20:21 -0700125 self, ip_tag_bridged, 32,
126 [VppRoutePath("0.0.0.0",
127 sub_if_on_pg3.sw_if_index,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800128 is_dvr=1)])
Neale Ranns55d03782017-10-21 06:34:22 -0700129 route_with_tag.add_vpp_config()
Neale Ranns6f631152017-10-03 08:20:21 -0700130
131 #
Neale Rannsf068c3e2018-01-03 04:18:48 -0800132 # Inject the packet that arrives non-tag and leaves on a tagged
133 # interface
Neale Ranns6f631152017-10-03 08:20:21 -0700134 #
Neale Ranns55d03782017-10-21 06:34:22 -0700135 rx = self.send_and_expect(self.pg0, pkt_tag * 65, self.pg3)
136 self.assert_same_mac_addr(pkt_tag, rx)
137 self.assert_has_vlan_tag(93, rx)
Neale Ranns6f631152017-10-03 08:20:21 -0700138
139 #
140 # Tag to tag
141 #
142 pkt_tag_to_tag = (Ether(src=self.pg2.remote_mac,
143 dst=self.loop0.local_mac) /
144 Dot1Q(vlan=92) /
145 IP(src=any_src_addr,
146 dst=ip_tag_bridged) /
147 UDP(sport=1234, dport=1234) /
148 Raw('\xa5' * 100))
149
Neale Ranns55d03782017-10-21 06:34:22 -0700150 rx = self.send_and_expect(self.pg2, pkt_tag_to_tag * 65, self.pg3)
151 self.assert_same_mac_addr(pkt_tag_to_tag, rx)
152 self.assert_has_vlan_tag(93, rx)
Neale Ranns6f631152017-10-03 08:20:21 -0700153
154 #
155 # Tag to non-Tag
156 #
157 pkt_tag_to_non_tag = (Ether(src=self.pg2.remote_mac,
158 dst=self.loop0.local_mac) /
159 Dot1Q(vlan=92) /
160 IP(src=any_src_addr,
161 dst=ip_non_tag_bridged) /
162 UDP(sport=1234, dport=1234) /
163 Raw('\xa5' * 100))
164
Neale Ranns55d03782017-10-21 06:34:22 -0700165 rx = self.send_and_expect(self.pg2, pkt_tag_to_non_tag * 65, self.pg1)
166 self.assert_same_mac_addr(pkt_tag_to_tag, rx)
167 self.assert_has_no_tag(rx)
Neale Ranns6f631152017-10-03 08:20:21 -0700168
Neale Ranns55d03782017-10-21 06:34:22 -0700169 #
Neale Rannsf068c3e2018-01-03 04:18:48 -0800170 # Add an output L3 ACL that will block the traffic
171 #
172 rule_1 = ({'is_permit': 0,
173 'is_ipv6': 0,
174 'proto': 17,
175 'srcport_or_icmptype_first': 1234,
176 'srcport_or_icmptype_last': 1234,
177 'src_ip_prefix_len': 32,
178 'src_ip_addr': inet_pton(AF_INET, any_src_addr),
179 'dstport_or_icmpcode_first': 1234,
180 'dstport_or_icmpcode_last': 1234,
181 'dst_ip_prefix_len': 32,
182 'dst_ip_addr': inet_pton(AF_INET, ip_non_tag_bridged)})
183 acl = self.vapi.acl_add_replace(acl_index=4294967295,
184 r=[rule_1])
185
186 #
187 # Apply the ACL on the output interface
188 #
189 self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index,
190 0,
191 [acl.acl_index])
192
193 #
194 # Send packet's that should match the ACL and be dropped
195 #
196 rx = self.send_and_assert_no_replies(self.pg2, pkt_tag_to_non_tag * 65)
197
198 #
Neale Ranns55d03782017-10-21 06:34:22 -0700199 # cleanup
200 #
Neale Rannsf068c3e2018-01-03 04:18:48 -0800201 self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index,
202 0, [])
203 self.vapi.acl_del(acl.acl_index)
204
Neale Ranns55d03782017-10-21 06:34:22 -0700205 self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1,
206 enable=0)
207 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1,
208 enable=0)
209 self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index,
210 1, enable=0)
211 self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index,
212 1, enable=0)
213 self.vapi.sw_interface_set_l2_bridge(self.loop0.sw_if_index,
Neale Rannsb4743802018-09-05 09:13:57 -0700214 1, port_type=L2_PORT_TYPE.BVI,
215 enable=0)
Neale Ranns55d03782017-10-21 06:34:22 -0700216
217 #
Neale Ranns81458422018-03-12 06:59:36 -0700218 # Do a FIB dump to make sure the paths are correctly reported as DVR
219 #
220 routes = self.vapi.ip_fib_dump()
221
222 for r in routes:
223 if (inet_pton(AF_INET, ip_tag_bridged) == r.address):
Neale Ranns81458422018-03-12 06:59:36 -0700224 self.assertEqual(r.path[0].sw_if_index,
225 sub_if_on_pg3.sw_if_index)
226 self.assertEqual(r.path[0].is_dvr, 1)
227 if (inet_pton(AF_INET, ip_non_tag_bridged) == r.address):
Neale Ranns81458422018-03-12 06:59:36 -0700228 self.assertEqual(r.path[0].sw_if_index,
229 self.pg1.sw_if_index)
230 self.assertEqual(r.path[0].is_dvr, 1)
231
232 #
Neale Ranns55d03782017-10-21 06:34:22 -0700233 # the explicit route delete is require so it happens before
234 # the sbu-interface delete. subinterface delete is required
235 # because that object type does not use the object registry
236 #
237 route_no_tag.remove_vpp_config()
238 route_with_tag.remove_vpp_config()
239 sub_if_on_pg3.remove_vpp_config()
240 sub_if_on_pg2.remove_vpp_config()
241
242 def test_l2_emulation(self):
243 """ L2 Emulation """
244
245 #
246 # non distinct L3 packets, in the tag/non-tag combos
247 #
248 pkt_no_tag = (Ether(src=self.pg0.remote_mac,
249 dst=self.pg1.remote_mac) /
250 IP(src="2.2.2.2",
251 dst="1.1.1.1") /
252 UDP(sport=1234, dport=1234) /
253 Raw('\xa5' * 100))
254 pkt_to_tag = (Ether(src=self.pg0.remote_mac,
255 dst=self.pg2.remote_mac) /
256 IP(src="2.2.2.2",
257 dst="1.1.1.2") /
258 UDP(sport=1234, dport=1234) /
259 Raw('\xa5' * 100))
260 pkt_from_tag = (Ether(src=self.pg3.remote_mac,
261 dst=self.pg2.remote_mac) /
262 Dot1Q(vlan=93) /
263 IP(src="2.2.2.2",
264 dst="1.1.1.1") /
265 UDP(sport=1234, dport=1234) /
266 Raw('\xa5' * 100))
267 pkt_from_to_tag = (Ether(src=self.pg3.remote_mac,
268 dst=self.pg2.remote_mac) /
269 Dot1Q(vlan=93) /
270 IP(src="2.2.2.2",
271 dst="1.1.1.2") /
272 UDP(sport=1234, dport=1234) /
273 Raw('\xa5' * 100))
274 pkt_bcast = (Ether(src=self.pg0.remote_mac,
275 dst="ff:ff:ff:ff:ff:ff") /
276 IP(src="2.2.2.2",
277 dst="255.255.255.255") /
278 UDP(sport=1234, dport=1234) /
279 Raw('\xa5' * 100))
280
281 #
282 # A couple of sub-interfaces for tags
283 #
284 sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92)
285 sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93)
286 sub_if_on_pg2.admin_up()
287 sub_if_on_pg3.admin_up()
288
289 #
290 # Put all the interfaces into a new bridge domain
291 #
292 self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1)
293 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1)
294 self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index, 1)
295 self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index, 1)
Ole Troane1ade682019-03-04 23:55:43 +0100296 self.vapi.l2_interface_vlan_tag_rewrite(
297 sub_if_on_pg2.sw_if_index,
298 L2_VTR_OP.L2_POP_1,
299 92)
300 self.vapi.l2_interface_vlan_tag_rewrite(
301 sub_if_on_pg3.sw_if_index,
302 L2_VTR_OP.L2_POP_1,
303 93)
Neale Ranns55d03782017-10-21 06:34:22 -0700304
305 #
Neale Rannsf068c3e2018-01-03 04:18:48 -0800306 # Disable UU flooding, learning and ARP terminaation. makes this test
Neale Ranns55d03782017-10-21 06:34:22 -0700307 # easier as unicast packets are dropped if not extracted.
308 #
309 self.vapi.bridge_flags(1, 0, (1 << 0) | (1 << 3) | (1 << 4))
310
311 #
312 # Add a DVR route to steer traffic at L3
313 #
314 route_1 = VppIpRoute(self, "1.1.1.1", 32,
315 [VppRoutePath("0.0.0.0",
316 self.pg1.sw_if_index,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800317 is_dvr=1)])
Neale Ranns55d03782017-10-21 06:34:22 -0700318 route_2 = VppIpRoute(self, "1.1.1.2", 32,
319 [VppRoutePath("0.0.0.0",
320 sub_if_on_pg2.sw_if_index,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800321 is_dvr=1)])
Neale Ranns55d03782017-10-21 06:34:22 -0700322 route_1.add_vpp_config()
323 route_2.add_vpp_config()
324
325 #
Andrey "Zed" Zaikin701625b2018-04-18 17:07:07 +0300326 # packets are dropped because bridge does not flood unknown unicast
Neale Ranns55d03782017-10-21 06:34:22 -0700327 #
328 self.send_and_assert_no_replies(self.pg0, pkt_no_tag)
329
330 #
331 # Enable L3 extraction on pgs
332 #
Ole Troane1ade682019-03-04 23:55:43 +0100333 self.vapi.l2_emulation(self.pg0.sw_if_index)
334 self.vapi.l2_emulation(self.pg1.sw_if_index)
335 self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index)
336 self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index)
Neale Ranns55d03782017-10-21 06:34:22 -0700337
338 #
339 # now we expect the packet forward according to the DVR route
340 #
341 rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1)
342 self.assert_same_mac_addr(pkt_no_tag, rx)
343 self.assert_has_no_tag(rx)
344
345 rx = self.send_and_expect(self.pg0, pkt_to_tag * 65, self.pg2)
346 self.assert_same_mac_addr(pkt_to_tag, rx)
347 self.assert_has_vlan_tag(92, rx)
348
349 rx = self.send_and_expect(self.pg3, pkt_from_tag * 65, self.pg1)
350 self.assert_same_mac_addr(pkt_from_tag, rx)
351 self.assert_has_no_tag(rx)
352
353 rx = self.send_and_expect(self.pg3, pkt_from_to_tag * 65, self.pg2)
354 self.assert_same_mac_addr(pkt_from_tag, rx)
355 self.assert_has_vlan_tag(92, rx)
356
357 #
358 # but broadcast packets are still flooded
359 #
360 self.send_and_expect(self.pg0, pkt_bcast * 33, self.pg2)
361
362 #
363 # cleanup
364 #
Ole Troane1ade682019-03-04 23:55:43 +0100365 self.vapi.l2_emulation(self.pg0.sw_if_index,
366 enable=0)
367 self.vapi.l2_emulation(self.pg1.sw_if_index,
368 enable=0)
369 self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index,
370 enable=0)
371 self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index,
372 enable=0)
Neale Ranns55d03782017-10-21 06:34:22 -0700373
374 self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index,
375 1, enable=0)
376 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
377 1, enable=0)
378 self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index,
379 1, enable=0)
380 self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index,
381 1, enable=0)
382
383 route_1.remove_vpp_config()
384 route_2.remove_vpp_config()
385 sub_if_on_pg3.remove_vpp_config()
386 sub_if_on_pg2.remove_vpp_config()
387
Neale Ranns6f631152017-10-03 08:20:21 -0700388
389if __name__ == '__main__':
390 unittest.main(testRunner=VppTestRunner)