blob: f6ce8e80720dcfa8d81deab8a14934cce50c8df2 [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_ip_route import VppIpRoute, VppRoutePath
Paul Vinciguerra95c0ca42019-03-28 13:07:00 -07006from vpp_l2 import L2_PORT_TYPE
7from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
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
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070018 @classmethod
19 def setUpClass(cls):
20 super(TestDVR, cls).setUpClass()
21
22 @classmethod
23 def tearDownClass(cls):
24 super(TestDVR, cls).tearDownClass()
25
Neale Ranns6f631152017-10-03 08:20:21 -070026 def setUp(self):
27 super(TestDVR, self).setUp()
28
29 self.create_pg_interfaces(range(4))
Klement Sekerab9ef2732018-06-24 22:49:33 +020030 self.create_loopback_interfaces(1)
Neale Ranns6f631152017-10-03 08:20:21 -070031
32 for i in self.pg_interfaces:
33 i.admin_up()
34
35 self.loop0.config_ip4()
36
37 def tearDown(self):
38 for i in self.pg_interfaces:
39 i.admin_down()
40 self.loop0.unconfig_ip4()
41
42 super(TestDVR, self).tearDown()
43
Neale Ranns55d03782017-10-21 06:34:22 -070044 def assert_same_mac_addr(self, tx, rx):
45 t_eth = tx[Ether]
46 for p in rx:
47 r_eth = p[Ether]
48 self.assertEqual(t_eth.src, r_eth.src)
49 self.assertEqual(t_eth.dst, r_eth.dst)
50
51 def assert_has_vlan_tag(self, tag, rx):
52 for p in rx:
53 r_1q = p[Dot1Q]
54 self.assertEqual(tag, r_1q.vlan)
55
56 def assert_has_no_tag(self, rx):
57 for p in rx:
58 self.assertFalse(p.haslayer(Dot1Q))
59
Neale Ranns6f631152017-10-03 08:20:21 -070060 def test_dvr(self):
61 """ Distributed Virtual Router """
62
63 #
64 # A packet destined to an IP address that is L2 bridged via
65 # a non-tag interface
66 #
67 ip_non_tag_bridged = "10.10.10.10"
68 ip_tag_bridged = "10.10.10.11"
69 any_src_addr = "1.1.1.1"
70
71 pkt_no_tag = (Ether(src=self.pg0.remote_mac,
72 dst=self.loop0.local_mac) /
73 IP(src=any_src_addr,
74 dst=ip_non_tag_bridged) /
75 UDP(sport=1234, dport=1234) /
76 Raw('\xa5' * 100))
77 pkt_tag = (Ether(src=self.pg0.remote_mac,
78 dst=self.loop0.local_mac) /
79 IP(src=any_src_addr,
80 dst=ip_tag_bridged) /
81 UDP(sport=1234, dport=1234) /
82 Raw('\xa5' * 100))
83
84 #
85 # Two sub-interfaces so we can test VLAN tag push/pop
86 #
87 sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92)
88 sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93)
89 sub_if_on_pg2.admin_up()
90 sub_if_on_pg3.admin_up()
91
92 #
93 # Put all the interfaces into a new bridge domain
94 #
Ole Troana5b2eec2019-03-11 19:23:25 +010095 self.vapi.sw_interface_set_l2_bridge(
96 rx_sw_if_index=self.pg0.sw_if_index, bd_id=1)
97 self.vapi.sw_interface_set_l2_bridge(
98 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
99 self.vapi.sw_interface_set_l2_bridge(
100 rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1)
101 self.vapi.sw_interface_set_l2_bridge(
102 rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1)
103 self.vapi.sw_interface_set_l2_bridge(
104 rx_sw_if_index=self.loop0.sw_if_index, bd_id=1,
105 port_type=L2_PORT_TYPE.BVI)
Neale Ranns6f631152017-10-03 08:20:21 -0700106
Ole Troane1ade682019-03-04 23:55:43 +0100107 self.vapi.l2_interface_vlan_tag_rewrite(
Ole Troana5b2eec2019-03-11 19:23:25 +0100108 sw_if_index=sub_if_on_pg2.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
109 push_dot1q=92)
Ole Troane1ade682019-03-04 23:55:43 +0100110 self.vapi.l2_interface_vlan_tag_rewrite(
Ole Troana5b2eec2019-03-11 19:23:25 +0100111 sw_if_index=sub_if_on_pg3.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
112 push_dot1q=93)
Neale Ranns6f631152017-10-03 08:20:21 -0700113
Neale Ranns6f631152017-10-03 08:20:21 -0700114 #
115 # Add routes to bridge the traffic via a tagged an nontagged interface
116 #
117 route_no_tag = VppIpRoute(
118 self, ip_non_tag_bridged, 32,
119 [VppRoutePath("0.0.0.0",
120 self.pg1.sw_if_index,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800121 is_dvr=1)])
Neale Ranns6f631152017-10-03 08:20:21 -0700122 route_no_tag.add_vpp_config()
123
124 #
125 # Inject the packet that arrives and leaves on a non-tagged interface
126 # Since it's 'bridged' expect that the MAC headed is unchanged.
127 #
Neale Rannsf068c3e2018-01-03 04:18:48 -0800128 rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1)
129 self.assert_same_mac_addr(pkt_no_tag, rx)
130 self.assert_has_no_tag(rx)
Neale Ranns6f631152017-10-03 08:20:21 -0700131
132 #
133 # Add routes to bridge the traffic via a tagged interface
134 #
Neale Ranns55d03782017-10-21 06:34:22 -0700135 route_with_tag = VppIpRoute(
Neale Ranns6f631152017-10-03 08:20:21 -0700136 self, ip_tag_bridged, 32,
137 [VppRoutePath("0.0.0.0",
138 sub_if_on_pg3.sw_if_index,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800139 is_dvr=1)])
Neale Ranns55d03782017-10-21 06:34:22 -0700140 route_with_tag.add_vpp_config()
Neale Ranns6f631152017-10-03 08:20:21 -0700141
142 #
Neale Rannsf068c3e2018-01-03 04:18:48 -0800143 # Inject the packet that arrives non-tag and leaves on a tagged
144 # interface
Neale Ranns6f631152017-10-03 08:20:21 -0700145 #
Neale Ranns55d03782017-10-21 06:34:22 -0700146 rx = self.send_and_expect(self.pg0, pkt_tag * 65, self.pg3)
147 self.assert_same_mac_addr(pkt_tag, rx)
148 self.assert_has_vlan_tag(93, rx)
Neale Ranns6f631152017-10-03 08:20:21 -0700149
150 #
151 # Tag to tag
152 #
153 pkt_tag_to_tag = (Ether(src=self.pg2.remote_mac,
154 dst=self.loop0.local_mac) /
155 Dot1Q(vlan=92) /
156 IP(src=any_src_addr,
157 dst=ip_tag_bridged) /
158 UDP(sport=1234, dport=1234) /
159 Raw('\xa5' * 100))
160
Neale Ranns55d03782017-10-21 06:34:22 -0700161 rx = self.send_and_expect(self.pg2, pkt_tag_to_tag * 65, self.pg3)
162 self.assert_same_mac_addr(pkt_tag_to_tag, rx)
163 self.assert_has_vlan_tag(93, rx)
Neale Ranns6f631152017-10-03 08:20:21 -0700164
165 #
166 # Tag to non-Tag
167 #
168 pkt_tag_to_non_tag = (Ether(src=self.pg2.remote_mac,
169 dst=self.loop0.local_mac) /
170 Dot1Q(vlan=92) /
171 IP(src=any_src_addr,
172 dst=ip_non_tag_bridged) /
173 UDP(sport=1234, dport=1234) /
174 Raw('\xa5' * 100))
175
Neale Ranns55d03782017-10-21 06:34:22 -0700176 rx = self.send_and_expect(self.pg2, pkt_tag_to_non_tag * 65, self.pg1)
177 self.assert_same_mac_addr(pkt_tag_to_tag, rx)
178 self.assert_has_no_tag(rx)
Neale Ranns6f631152017-10-03 08:20:21 -0700179
Neale Ranns55d03782017-10-21 06:34:22 -0700180 #
Neale Rannsf068c3e2018-01-03 04:18:48 -0800181 # Add an output L3 ACL that will block the traffic
182 #
183 rule_1 = ({'is_permit': 0,
184 'is_ipv6': 0,
185 'proto': 17,
186 'srcport_or_icmptype_first': 1234,
187 'srcport_or_icmptype_last': 1234,
188 'src_ip_prefix_len': 32,
189 'src_ip_addr': inet_pton(AF_INET, any_src_addr),
190 'dstport_or_icmpcode_first': 1234,
191 'dstport_or_icmpcode_last': 1234,
192 'dst_ip_prefix_len': 32,
193 'dst_ip_addr': inet_pton(AF_INET, ip_non_tag_bridged)})
194 acl = self.vapi.acl_add_replace(acl_index=4294967295,
195 r=[rule_1])
196
197 #
198 # Apply the ACL on the output interface
199 #
200 self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index,
201 0,
202 [acl.acl_index])
203
204 #
205 # Send packet's that should match the ACL and be dropped
206 #
207 rx = self.send_and_assert_no_replies(self.pg2, pkt_tag_to_non_tag * 65)
208
209 #
Neale Ranns55d03782017-10-21 06:34:22 -0700210 # cleanup
211 #
Neale Rannsf068c3e2018-01-03 04:18:48 -0800212 self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index,
213 0, [])
214 self.vapi.acl_del(acl.acl_index)
215
Ole Troana5b2eec2019-03-11 19:23:25 +0100216 self.vapi.sw_interface_set_l2_bridge(
217 rx_sw_if_index=self.pg0.sw_if_index, bd_id=1, enable=0)
218 self.vapi.sw_interface_set_l2_bridge(
219 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
220 self.vapi.sw_interface_set_l2_bridge(
221 rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1, enable=0)
222 self.vapi.sw_interface_set_l2_bridge(
223 rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1, enable=0)
224 self.vapi.sw_interface_set_l2_bridge(
225 rx_sw_if_index=self.loop0.sw_if_index, bd_id=1,
226 port_type=L2_PORT_TYPE.BVI, enable=0)
Neale Ranns55d03782017-10-21 06:34:22 -0700227
228 #
Neale Ranns81458422018-03-12 06:59:36 -0700229 # Do a FIB dump to make sure the paths are correctly reported as DVR
230 #
231 routes = self.vapi.ip_fib_dump()
232
233 for r in routes:
234 if (inet_pton(AF_INET, ip_tag_bridged) == r.address):
Neale Ranns81458422018-03-12 06:59:36 -0700235 self.assertEqual(r.path[0].sw_if_index,
236 sub_if_on_pg3.sw_if_index)
237 self.assertEqual(r.path[0].is_dvr, 1)
238 if (inet_pton(AF_INET, ip_non_tag_bridged) == r.address):
Neale Ranns81458422018-03-12 06:59:36 -0700239 self.assertEqual(r.path[0].sw_if_index,
240 self.pg1.sw_if_index)
241 self.assertEqual(r.path[0].is_dvr, 1)
242
243 #
Neale Ranns55d03782017-10-21 06:34:22 -0700244 # the explicit route delete is require so it happens before
245 # the sbu-interface delete. subinterface delete is required
246 # because that object type does not use the object registry
247 #
248 route_no_tag.remove_vpp_config()
249 route_with_tag.remove_vpp_config()
250 sub_if_on_pg3.remove_vpp_config()
251 sub_if_on_pg2.remove_vpp_config()
252
253 def test_l2_emulation(self):
254 """ L2 Emulation """
255
256 #
257 # non distinct L3 packets, in the tag/non-tag combos
258 #
259 pkt_no_tag = (Ether(src=self.pg0.remote_mac,
260 dst=self.pg1.remote_mac) /
261 IP(src="2.2.2.2",
262 dst="1.1.1.1") /
263 UDP(sport=1234, dport=1234) /
264 Raw('\xa5' * 100))
265 pkt_to_tag = (Ether(src=self.pg0.remote_mac,
266 dst=self.pg2.remote_mac) /
267 IP(src="2.2.2.2",
268 dst="1.1.1.2") /
269 UDP(sport=1234, dport=1234) /
270 Raw('\xa5' * 100))
271 pkt_from_tag = (Ether(src=self.pg3.remote_mac,
272 dst=self.pg2.remote_mac) /
273 Dot1Q(vlan=93) /
274 IP(src="2.2.2.2",
275 dst="1.1.1.1") /
276 UDP(sport=1234, dport=1234) /
277 Raw('\xa5' * 100))
278 pkt_from_to_tag = (Ether(src=self.pg3.remote_mac,
279 dst=self.pg2.remote_mac) /
280 Dot1Q(vlan=93) /
281 IP(src="2.2.2.2",
282 dst="1.1.1.2") /
283 UDP(sport=1234, dport=1234) /
284 Raw('\xa5' * 100))
285 pkt_bcast = (Ether(src=self.pg0.remote_mac,
286 dst="ff:ff:ff:ff:ff:ff") /
287 IP(src="2.2.2.2",
288 dst="255.255.255.255") /
289 UDP(sport=1234, dport=1234) /
290 Raw('\xa5' * 100))
291
292 #
293 # A couple of sub-interfaces for tags
294 #
295 sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92)
296 sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93)
297 sub_if_on_pg2.admin_up()
298 sub_if_on_pg3.admin_up()
299
300 #
301 # Put all the interfaces into a new bridge domain
302 #
Ole Troana5b2eec2019-03-11 19:23:25 +0100303 self.vapi.sw_interface_set_l2_bridge(
304 rx_sw_if_index=self.pg0.sw_if_index, bd_id=1)
305 self.vapi.sw_interface_set_l2_bridge(
306 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
307 self.vapi.sw_interface_set_l2_bridge(
308 rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1)
309 self.vapi.sw_interface_set_l2_bridge(
310 rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1)
Ole Troane1ade682019-03-04 23:55:43 +0100311 self.vapi.l2_interface_vlan_tag_rewrite(
Ole Troana5b2eec2019-03-11 19:23:25 +0100312 sw_if_index=sub_if_on_pg2.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
313 push_dot1q=92)
Ole Troane1ade682019-03-04 23:55:43 +0100314 self.vapi.l2_interface_vlan_tag_rewrite(
Ole Troana5b2eec2019-03-11 19:23:25 +0100315 sw_if_index=sub_if_on_pg3.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
316 push_dot1q=93)
Neale Ranns55d03782017-10-21 06:34:22 -0700317
318 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700319 # Disable UU flooding, learning and ARP termination. makes this test
Neale Ranns55d03782017-10-21 06:34:22 -0700320 # easier as unicast packets are dropped if not extracted.
321 #
Ole Troana5b2eec2019-03-11 19:23:25 +0100322 self.vapi.bridge_flags(bd_id=1, is_set=0,
323 flags=(1 << 0) | (1 << 3) | (1 << 4))
Neale Ranns55d03782017-10-21 06:34:22 -0700324
325 #
326 # Add a DVR route to steer traffic at L3
327 #
328 route_1 = VppIpRoute(self, "1.1.1.1", 32,
329 [VppRoutePath("0.0.0.0",
330 self.pg1.sw_if_index,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800331 is_dvr=1)])
Neale Ranns55d03782017-10-21 06:34:22 -0700332 route_2 = VppIpRoute(self, "1.1.1.2", 32,
333 [VppRoutePath("0.0.0.0",
334 sub_if_on_pg2.sw_if_index,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800335 is_dvr=1)])
Neale Ranns55d03782017-10-21 06:34:22 -0700336 route_1.add_vpp_config()
337 route_2.add_vpp_config()
338
339 #
Andrey "Zed" Zaikin701625b2018-04-18 17:07:07 +0300340 # packets are dropped because bridge does not flood unknown unicast
Neale Ranns55d03782017-10-21 06:34:22 -0700341 #
342 self.send_and_assert_no_replies(self.pg0, pkt_no_tag)
343
344 #
345 # Enable L3 extraction on pgs
346 #
Ole Troane1ade682019-03-04 23:55:43 +0100347 self.vapi.l2_emulation(self.pg0.sw_if_index)
348 self.vapi.l2_emulation(self.pg1.sw_if_index)
349 self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index)
350 self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index)
Neale Ranns55d03782017-10-21 06:34:22 -0700351
352 #
353 # now we expect the packet forward according to the DVR route
354 #
355 rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1)
356 self.assert_same_mac_addr(pkt_no_tag, rx)
357 self.assert_has_no_tag(rx)
358
359 rx = self.send_and_expect(self.pg0, pkt_to_tag * 65, self.pg2)
360 self.assert_same_mac_addr(pkt_to_tag, rx)
361 self.assert_has_vlan_tag(92, rx)
362
363 rx = self.send_and_expect(self.pg3, pkt_from_tag * 65, self.pg1)
364 self.assert_same_mac_addr(pkt_from_tag, rx)
365 self.assert_has_no_tag(rx)
366
367 rx = self.send_and_expect(self.pg3, pkt_from_to_tag * 65, self.pg2)
368 self.assert_same_mac_addr(pkt_from_tag, rx)
369 self.assert_has_vlan_tag(92, rx)
370
371 #
372 # but broadcast packets are still flooded
373 #
374 self.send_and_expect(self.pg0, pkt_bcast * 33, self.pg2)
375
376 #
377 # cleanup
378 #
Ole Troane1ade682019-03-04 23:55:43 +0100379 self.vapi.l2_emulation(self.pg0.sw_if_index,
380 enable=0)
381 self.vapi.l2_emulation(self.pg1.sw_if_index,
382 enable=0)
383 self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index,
384 enable=0)
385 self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index,
386 enable=0)
Neale Ranns55d03782017-10-21 06:34:22 -0700387
Ole Troana5b2eec2019-03-11 19:23:25 +0100388 self.vapi.sw_interface_set_l2_bridge(
389 rx_sw_if_index=self.pg0.sw_if_index, bd_id=1, enable=0)
390 self.vapi.sw_interface_set_l2_bridge(
391 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
392 self.vapi.sw_interface_set_l2_bridge(
393 rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1, enable=0)
394 self.vapi.sw_interface_set_l2_bridge(
395 rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1, enable=0)
Neale Ranns55d03782017-10-21 06:34:22 -0700396
397 route_1.remove_vpp_config()
398 route_2.remove_vpp_config()
399 sub_if_on_pg3.remove_vpp_config()
400 sub_if_on_pg2.remove_vpp_config()
401
Neale Ranns6f631152017-10-03 08:20:21 -0700402
403if __name__ == '__main__':
404 unittest.main(testRunner=VppTestRunner)