blob: cca4f802089053797e3596514621773b7cc08ea6 [file] [log] [blame]
Neale Ranns32e1c012016-11-22 17:07:28 +00001#!/usr/bin/env python
2
3import unittest
4
5from framework import VppTestCase, VppTestRunner
Neale Rannsc0a93142018-09-05 15:42:26 -07006from vpp_ip import DpoProto
Neale Ranns180279b2017-03-16 15:49:09 -04007from vpp_ip_route import VppIpMRoute, VppMRoutePath, VppMFibSignal, \
Neale Rannsc0a93142018-09-05 15:42:26 -07008 MRouteItfFlags, MRouteEntryFlags, VppIpTable
Neale Ranns32e1c012016-11-22 17:07:28 +00009
10from scapy.packet import Raw
11from scapy.layers.l2 import Ether
Klement Sekerab9ef2732018-06-24 22:49:33 +020012from scapy.layers.inet import IP, UDP, getmacbyip
Neale Ranns32e1c012016-11-22 17:07:28 +000013from scapy.layers.inet6 import IPv6, getmacbyip6
Neale Ranns32e1c012016-11-22 17:07:28 +000014
Neale Ranns9bea8fb2017-02-03 04:34:01 -080015#
Neale Rannscf3561b2017-12-13 01:44:25 -080016# The number of packets sent is set to 91 so that when we replicate more than 3
Neale Ranns9bea8fb2017-02-03 04:34:01 -080017# times, which we do for some entries, we will generate more than 256 packets
Neale Rannsaaa396a2017-02-05 09:12:02 -080018# to the next node in the VLIB graph. Thus we are testing the code's
Neale Rannscf3561b2017-12-13 01:44:25 -080019# correctness handling this over-flow.
20# It's also an odd number so we hit any single loops.
Neale Ranns9bea8fb2017-02-03 04:34:01 -080021#
Neale Rannscf3561b2017-12-13 01:44:25 -080022N_PKTS_IN_STREAM = 91
Neale Ranns9bea8fb2017-02-03 04:34:01 -080023
Neale Ranns32e1c012016-11-22 17:07:28 +000024
Neale Ranns5a8123b2017-01-26 01:18:23 -080025class TestMFIB(VppTestCase):
26 """ MFIB Test Case """
27
28 def setUp(self):
29 super(TestMFIB, self).setUp()
30
31 def test_mfib(self):
32 """ MFIB Unit Tests """
33 error = self.vapi.cli("test mfib")
34
35 if error:
36 self.logger.critical(error)
37 self.assertEqual(error.find("Failed"), -1)
38
39
Neale Ranns32e1c012016-11-22 17:07:28 +000040class TestIPMcast(VppTestCase):
41 """ IP Multicast Test Case """
42
43 def setUp(self):
44 super(TestIPMcast, self).setUp()
45
Neale Ranns37be7362017-02-21 17:30:26 -080046 # create 8 pg interfaces
Neale Ranns15002542017-09-10 04:39:11 -070047 self.create_pg_interfaces(range(9))
Neale Ranns32e1c012016-11-22 17:07:28 +000048
49 # setup interfaces
Neale Ranns15002542017-09-10 04:39:11 -070050 for i in self.pg_interfaces[:8]:
Neale Ranns32e1c012016-11-22 17:07:28 +000051 i.admin_up()
52 i.config_ip4()
53 i.config_ip6()
54 i.resolve_arp()
55 i.resolve_ndp()
56
Neale Ranns15002542017-09-10 04:39:11 -070057 # one more in a vrf
58 tbl4 = VppIpTable(self, 10)
59 tbl4.add_vpp_config()
60 self.pg8.set_table_ip4(10)
61 self.pg8.config_ip4()
62
63 tbl6 = VppIpTable(self, 10, is_ip6=1)
64 tbl6.add_vpp_config()
65 self.pg8.set_table_ip6(10)
66 self.pg8.config_ip6()
67
68 def tearDown(self):
69 for i in self.pg_interfaces:
70 i.unconfig_ip4()
71 i.unconfig_ip6()
72 i.admin_down()
73
74 self.pg8.set_table_ip4(0)
75 self.pg8.set_table_ip6(0)
76 super(TestIPMcast, self).tearDown()
77
Neale Ranns9d676af2017-03-15 01:28:31 -070078 def create_stream_ip4(self, src_if, src_ip, dst_ip, payload_size=0):
Neale Ranns32e1c012016-11-22 17:07:28 +000079 pkts = []
Neale Ranns9d676af2017-03-15 01:28:31 -070080 # default to small packet sizes
81 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
82 IP(src=src_ip, dst=dst_ip) /
83 UDP(sport=1234, dport=1234))
84 if not payload_size:
85 payload_size = 64 - len(p)
86 p = p / Raw('\xa5' * payload_size)
87
Neale Ranns9bea8fb2017-02-03 04:34:01 -080088 for i in range(0, N_PKTS_IN_STREAM):
Neale Ranns32e1c012016-11-22 17:07:28 +000089 pkts.append(p)
90 return pkts
91
92 def create_stream_ip6(self, src_if, src_ip, dst_ip):
93 pkts = []
Neale Ranns9bea8fb2017-02-03 04:34:01 -080094 for i in range(0, N_PKTS_IN_STREAM):
Neale Ranns32e1c012016-11-22 17:07:28 +000095 info = self.create_packet_info(src_if, src_if)
96 payload = self.info_to_payload(info)
97 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
98 IPv6(src=src_ip, dst=dst_ip) /
99 UDP(sport=1234, dport=1234) /
100 Raw(payload))
101 info.data = p.copy()
102 pkts.append(p)
103 return pkts
104
105 def verify_filter(self, capture, sent):
106 if not len(capture) == len(sent):
107 # filter out any IPv6 RAs from the captur
108 for p in capture:
109 if (p.haslayer(IPv6)):
110 capture.remove(p)
111 return capture
112
Neale Rannse821ab12017-06-01 07:45:05 -0700113 def verify_capture_ip4(self, rx_if, sent, dst_mac=None):
Neale Rannsc2aad532017-05-30 09:53:52 -0700114 rxd = rx_if.get_capture(len(sent))
Neale Ranns32e1c012016-11-22 17:07:28 +0000115
116 try:
117 capture = self.verify_filter(rxd, sent)
118
119 self.assertEqual(len(capture), len(sent))
120
121 for i in range(len(capture)):
122 tx = sent[i]
123 rx = capture[i]
124
Neale Ranns32e1c012016-11-22 17:07:28 +0000125 eth = rx[Ether]
126 self.assertEqual(eth.type, 0x800)
127
128 tx_ip = tx[IP]
129 rx_ip = rx[IP]
130
Neale Rannse821ab12017-06-01 07:45:05 -0700131 if dst_mac is None:
132 dst_mac = getmacbyip(rx_ip.dst)
133
Neale Ranns32e1c012016-11-22 17:07:28 +0000134 # check the MAC address on the RX'd packet is correctly formed
Neale Rannse821ab12017-06-01 07:45:05 -0700135 self.assertEqual(eth.dst, dst_mac)
Neale Ranns32e1c012016-11-22 17:07:28 +0000136
137 self.assertEqual(rx_ip.src, tx_ip.src)
138 self.assertEqual(rx_ip.dst, tx_ip.dst)
139 # IP processing post pop has decremented the TTL
140 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
141
142 except:
143 raise
144
Neale Rannsc2aad532017-05-30 09:53:52 -0700145 def verify_capture_ip6(self, rx_if, sent):
146 capture = rx_if.get_capture(len(sent))
Neale Ranns32e1c012016-11-22 17:07:28 +0000147
148 self.assertEqual(len(capture), len(sent))
149
150 for i in range(len(capture)):
151 tx = sent[i]
152 rx = capture[i]
153
Neale Ranns32e1c012016-11-22 17:07:28 +0000154 eth = rx[Ether]
155 self.assertEqual(eth.type, 0x86DD)
156
157 tx_ip = tx[IPv6]
158 rx_ip = rx[IPv6]
159
160 # check the MAC address on the RX'd packet is correctly formed
161 self.assertEqual(eth.dst, getmacbyip6(rx_ip.dst))
162
163 self.assertEqual(rx_ip.src, tx_ip.src)
164 self.assertEqual(rx_ip.dst, tx_ip.dst)
165 # IP processing post pop has decremented the TTL
166 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
167
168 def test_ip_mcast(self):
169 """ IP Multicast Replication """
170
171 #
172 # a stream that matches the default route. gets dropped.
173 #
174 self.vapi.cli("clear trace")
175 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
176 self.pg0.add_stream(tx)
177
178 self.pg_enable_capture(self.pg_interfaces)
179 self.pg_start()
180
181 self.pg0.assert_nothing_captured(
182 remark="IP multicast packets forwarded on default route")
183
184 #
185 # A (*,G).
Neale Ranns37be7362017-02-21 17:30:26 -0800186 # one accepting interface, pg0, 7 forwarding interfaces
187 # many forwarding interfaces test the case where the replicare DPO
188 # needs to use extra cache lines for the buckets.
Neale Ranns32e1c012016-11-22 17:07:28 +0000189 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800190 route_232_1_1_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000191 self,
192 "0.0.0.0",
193 "232.1.1.1", 32,
194 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800195 [VppMRoutePath(self.pg0.sw_if_index,
196 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
197 VppMRoutePath(self.pg1.sw_if_index,
198 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
199 VppMRoutePath(self.pg2.sw_if_index,
200 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
201 VppMRoutePath(self.pg3.sw_if_index,
Neale Ranns37be7362017-02-21 17:30:26 -0800202 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
203 VppMRoutePath(self.pg4.sw_if_index,
204 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
205 VppMRoutePath(self.pg5.sw_if_index,
206 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
207 VppMRoutePath(self.pg6.sw_if_index,
208 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
209 VppMRoutePath(self.pg7.sw_if_index,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800210 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000211 route_232_1_1_1.add_vpp_config()
212
213 #
214 # An (S,G).
215 # one accepting interface, pg0, 2 forwarding interfaces
216 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800217 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000218 self,
219 "1.1.1.1",
Neale Ranns3e42ebe2018-10-04 08:36:56 -0700220 "232.1.1.1", 27, # any grp-len is ok when src is set
Neale Ranns32e1c012016-11-22 17:07:28 +0000221 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800222 [VppMRoutePath(self.pg0.sw_if_index,
223 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
224 VppMRoutePath(self.pg1.sw_if_index,
225 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
226 VppMRoutePath(self.pg2.sw_if_index,
227 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000228 route_1_1_1_1_232_1_1_1.add_vpp_config()
229
230 #
Neale Rannse821ab12017-06-01 07:45:05 -0700231 # An (S,G).
232 # one accepting interface, pg0, 2 forwarding interfaces
233 # that use unicast next-hops
234 #
235 route_1_1_1_1_232_1_1_2 = VppIpMRoute(
236 self,
237 "1.1.1.1",
238 "232.1.1.2", 64,
239 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
240 [VppMRoutePath(self.pg0.sw_if_index,
241 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
242 VppMRoutePath(self.pg1.sw_if_index,
243 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
244 nh=self.pg1.remote_ip4),
245 VppMRoutePath(self.pg2.sw_if_index,
246 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
247 nh=self.pg2.remote_ip4)])
248 route_1_1_1_1_232_1_1_2.add_vpp_config()
249
250 #
Neale Ranns32e1c012016-11-22 17:07:28 +0000251 # An (*,G/m).
252 # one accepting interface, pg0, 1 forwarding interfaces
253 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800254 route_232 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000255 self,
256 "0.0.0.0",
257 "232.0.0.0", 8,
258 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800259 [VppMRoutePath(self.pg0.sw_if_index,
260 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
261 VppMRoutePath(self.pg1.sw_if_index,
262 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000263 route_232.add_vpp_config()
264
265 #
266 # a stream that matches the route for (1.1.1.1,232.1.1.1)
Neale Ranns9d676af2017-03-15 01:28:31 -0700267 # small packets
Neale Ranns32e1c012016-11-22 17:07:28 +0000268 #
269 self.vapi.cli("clear trace")
270 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
271 self.pg0.add_stream(tx)
272
273 self.pg_enable_capture(self.pg_interfaces)
274 self.pg_start()
275
Neale Ranns28c142e2018-09-07 09:37:07 -0700276 self.assertEqual(route_1_1_1_1_232_1_1_1.get_stats()['packets'],
277 len(tx))
278
Neale Ranns37be7362017-02-21 17:30:26 -0800279 # We expect replications on Pg1->7
Neale Ranns32e1c012016-11-22 17:07:28 +0000280 self.verify_capture_ip4(self.pg1, tx)
281 self.verify_capture_ip4(self.pg2, tx)
282
283 # no replications on Pg0
284 self.pg0.assert_nothing_captured(
285 remark="IP multicast packets forwarded on PG0")
286 self.pg3.assert_nothing_captured(
287 remark="IP multicast packets forwarded on PG3")
288
289 #
Neale Ranns9d676af2017-03-15 01:28:31 -0700290 # a stream that matches the route for (1.1.1.1,232.1.1.1)
291 # large packets
292 #
293 self.vapi.cli("clear trace")
294 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1",
295 payload_size=1024)
296 self.pg0.add_stream(tx)
297
298 self.pg_enable_capture(self.pg_interfaces)
299 self.pg_start()
300
301 # We expect replications on Pg1->7
302 self.verify_capture_ip4(self.pg1, tx)
303 self.verify_capture_ip4(self.pg2, tx)
Neale Ranns9d676af2017-03-15 01:28:31 -0700304
Neale Ranns28c142e2018-09-07 09:37:07 -0700305 self.assertEqual(route_1_1_1_1_232_1_1_1.get_stats()['packets'],
306 2*len(tx))
307
Neale Ranns9d676af2017-03-15 01:28:31 -0700308 # no replications on Pg0
309 self.pg0.assert_nothing_captured(
310 remark="IP multicast packets forwarded on PG0")
311 self.pg3.assert_nothing_captured(
312 remark="IP multicast packets forwarded on PG3")
313
314 #
Neale Rannse821ab12017-06-01 07:45:05 -0700315 # a stream to the unicast next-hops
316 #
317 self.vapi.cli("clear trace")
318 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.2")
319 self.pg0.add_stream(tx)
320
321 self.pg_enable_capture(self.pg_interfaces)
322 self.pg_start()
323
324 # We expect replications on Pg1->7
325 self.verify_capture_ip4(self.pg1, tx, dst_mac=self.pg1.remote_mac)
326 self.verify_capture_ip4(self.pg2, tx, dst_mac=self.pg2.remote_mac)
327
328 # no replications on Pg0 nor pg3
329 self.pg0.assert_nothing_captured(
330 remark="IP multicast packets forwarded on PG0")
331 self.pg3.assert_nothing_captured(
332 remark="IP multicast packets forwarded on PG3")
333
334 #
Neale Ranns32e1c012016-11-22 17:07:28 +0000335 # a stream that matches the route for (*,232.0.0.0/8)
336 # Send packets with the 9th bit set so we test the correct clearing
337 # of that bit in the mac rewrite
338 #
339 self.vapi.cli("clear trace")
340 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.255.255.255")
341 self.pg0.add_stream(tx)
342
343 self.pg_enable_capture(self.pg_interfaces)
344 self.pg_start()
345
346 # We expect replications on Pg1 only
347 self.verify_capture_ip4(self.pg1, tx)
Neale Ranns28c142e2018-09-07 09:37:07 -0700348 self.assertEqual(route_232.get_stats()['packets'], len(tx))
Neale Ranns32e1c012016-11-22 17:07:28 +0000349
350 # no replications on Pg0, Pg2 not Pg3
351 self.pg0.assert_nothing_captured(
352 remark="IP multicast packets forwarded on PG0")
353 self.pg2.assert_nothing_captured(
354 remark="IP multicast packets forwarded on PG2")
355 self.pg3.assert_nothing_captured(
356 remark="IP multicast packets forwarded on PG3")
357
358 #
359 # a stream that matches the route for (*,232.1.1.1)
360 #
361 self.vapi.cli("clear trace")
362 tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "232.1.1.1")
363 self.pg0.add_stream(tx)
364
365 self.pg_enable_capture(self.pg_interfaces)
366 self.pg_start()
367
Neale Rannse821ab12017-06-01 07:45:05 -0700368 # We expect replications on Pg1->7
Neale Ranns32e1c012016-11-22 17:07:28 +0000369 self.verify_capture_ip4(self.pg1, tx)
370 self.verify_capture_ip4(self.pg2, tx)
371 self.verify_capture_ip4(self.pg3, tx)
Neale Rannsc2aad532017-05-30 09:53:52 -0700372 self.verify_capture_ip4(self.pg4, tx)
373 self.verify_capture_ip4(self.pg5, tx)
374 self.verify_capture_ip4(self.pg6, tx)
375 self.verify_capture_ip4(self.pg7, tx)
Neale Ranns32e1c012016-11-22 17:07:28 +0000376
Neale Rannse821ab12017-06-01 07:45:05 -0700377 # no replications on Pg0
378 self.pg0.assert_nothing_captured(
379 remark="IP multicast packets forwarded on PG0")
380
Neale Ranns32e1c012016-11-22 17:07:28 +0000381 def test_ip6_mcast(self):
382 """ IPv6 Multicast Replication """
383
384 #
385 # a stream that matches the default route. gets dropped.
386 #
387 self.vapi.cli("clear trace")
388 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
389 self.pg0.add_stream(tx)
390
391 self.pg_enable_capture(self.pg_interfaces)
392 self.pg_start()
393
394 self.pg0.assert_nothing_captured(
395 remark="IPv6 multicast packets forwarded on default route")
396
397 #
398 # A (*,G).
399 # one accepting interface, pg0, 3 forwarding interfaces
400 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800401 route_ff01_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000402 self,
403 "::",
404 "ff01::1", 128,
405 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800406 [VppMRoutePath(self.pg0.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700407 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
408 proto=DpoProto.DPO_PROTO_IP6),
Neale Ranns5a8123b2017-01-26 01:18:23 -0800409 VppMRoutePath(self.pg1.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700410 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
411 proto=DpoProto.DPO_PROTO_IP6),
Neale Ranns5a8123b2017-01-26 01:18:23 -0800412 VppMRoutePath(self.pg2.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700413 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
414 proto=DpoProto.DPO_PROTO_IP6),
Neale Ranns5a8123b2017-01-26 01:18:23 -0800415 VppMRoutePath(self.pg3.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700416 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
417 proto=DpoProto.DPO_PROTO_IP6)],
Neale Ranns32e1c012016-11-22 17:07:28 +0000418 is_ip6=1)
419 route_ff01_1.add_vpp_config()
420
421 #
422 # An (S,G).
423 # one accepting interface, pg0, 2 forwarding interfaces
424 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800425 route_2001_ff01_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000426 self,
427 "2001::1",
Neale Ranns3e42ebe2018-10-04 08:36:56 -0700428 "ff01::1", 0, # any grp-len is ok when src is set
Neale Ranns32e1c012016-11-22 17:07:28 +0000429 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800430 [VppMRoutePath(self.pg0.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700431 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
432 proto=DpoProto.DPO_PROTO_IP6),
Neale Ranns5a8123b2017-01-26 01:18:23 -0800433 VppMRoutePath(self.pg1.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700434 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
435 proto=DpoProto.DPO_PROTO_IP6),
Neale Ranns5a8123b2017-01-26 01:18:23 -0800436 VppMRoutePath(self.pg2.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700437 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
438 proto=DpoProto.DPO_PROTO_IP6)],
Neale Ranns32e1c012016-11-22 17:07:28 +0000439 is_ip6=1)
440 route_2001_ff01_1.add_vpp_config()
441
442 #
443 # An (*,G/m).
444 # one accepting interface, pg0, 1 forwarding interface
445 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800446 route_ff01 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000447 self,
448 "::",
449 "ff01::", 16,
450 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800451 [VppMRoutePath(self.pg0.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700452 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
453 proto=DpoProto.DPO_PROTO_IP6),
Neale Ranns5a8123b2017-01-26 01:18:23 -0800454 VppMRoutePath(self.pg1.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700455 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
456 proto=DpoProto.DPO_PROTO_IP6)],
Neale Ranns32e1c012016-11-22 17:07:28 +0000457 is_ip6=1)
458 route_ff01.add_vpp_config()
459
460 #
461 # a stream that matches the route for (*, ff01::/16)
Neale Rannsce111d22018-01-23 08:38:50 -0800462 # sent on the non-accepting interface
463 #
464 self.vapi.cli("clear trace")
465 tx = self.create_stream_ip6(self.pg1, "2002::1", "ff01:2::255")
466 self.send_and_assert_no_replies(self.pg1, tx, "RPF miss")
467
468 #
469 # a stream that matches the route for (*, ff01::/16)
470 # sent on the accepting interface
Neale Ranns32e1c012016-11-22 17:07:28 +0000471 #
472 self.vapi.cli("clear trace")
473 tx = self.create_stream_ip6(self.pg0, "2002::1", "ff01:2::255")
474 self.pg0.add_stream(tx)
475
476 self.pg_enable_capture(self.pg_interfaces)
477 self.pg_start()
478
479 # We expect replications on Pg1
480 self.verify_capture_ip6(self.pg1, tx)
481
482 # no replications on Pg0, Pg3
483 self.pg0.assert_nothing_captured(
484 remark="IP multicast packets forwarded on PG0")
485 self.pg2.assert_nothing_captured(
486 remark="IP multicast packets forwarded on PG2")
487 self.pg3.assert_nothing_captured(
488 remark="IP multicast packets forwarded on PG3")
489
490 #
Neale Rannsc2aad532017-05-30 09:53:52 -0700491 # Bounce the interface and it should still work
492 #
493 self.pg1.admin_down()
494 self.pg0.add_stream(tx)
495 self.pg_enable_capture(self.pg_interfaces)
496 self.pg_start()
497 self.pg1.assert_nothing_captured(
498 remark="IP multicast packets forwarded on down PG1")
499
500 self.pg1.admin_up()
501 self.pg0.add_stream(tx)
502 self.pg_enable_capture(self.pg_interfaces)
503 self.pg_start()
504 self.verify_capture_ip6(self.pg1, tx)
505
506 #
Neale Ranns32e1c012016-11-22 17:07:28 +0000507 # a stream that matches the route for (*,ff01::1)
508 #
509 self.vapi.cli("clear trace")
510 tx = self.create_stream_ip6(self.pg0, "2002::2", "ff01::1")
511 self.pg0.add_stream(tx)
512
513 self.pg_enable_capture(self.pg_interfaces)
514 self.pg_start()
515
516 # We expect replications on Pg1, 2, 3.
517 self.verify_capture_ip6(self.pg1, tx)
518 self.verify_capture_ip6(self.pg2, tx)
519 self.verify_capture_ip6(self.pg3, tx)
520
521 # no replications on Pg0
522 self.pg0.assert_nothing_captured(
523 remark="IPv6 multicast packets forwarded on PG0")
524
525 #
526 # a stream that matches the route for (2001::1, ff00::1)
527 #
528 self.vapi.cli("clear trace")
529 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
530 self.pg0.add_stream(tx)
531
532 self.pg_enable_capture(self.pg_interfaces)
533 self.pg_start()
534
535 # We expect replications on Pg1, 2,
536 self.verify_capture_ip6(self.pg1, tx)
537 self.verify_capture_ip6(self.pg2, tx)
538
539 # no replications on Pg0, Pg3
540 self.pg0.assert_nothing_captured(
541 remark="IP multicast packets forwarded on PG0")
542 self.pg3.assert_nothing_captured(
543 remark="IP multicast packets forwarded on PG3")
544
Neale Ranns32e1c012016-11-22 17:07:28 +0000545 def _mcast_connected_send_stream(self, dst_ip):
546 self.vapi.cli("clear trace")
547 tx = self.create_stream_ip4(self.pg0,
548 self.pg0.remote_ip4,
549 dst_ip)
550 self.pg0.add_stream(tx)
551
552 self.pg_enable_capture(self.pg_interfaces)
553 self.pg_start()
554
555 # We expect replications on Pg1.
556 self.verify_capture_ip4(self.pg1, tx)
557
558 return tx
559
560 def test_ip_mcast_connected(self):
561 """ IP Multicast Connected Source check """
562
563 #
564 # A (*,G).
565 # one accepting interface, pg0, 1 forwarding interfaces
566 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800567 route_232_1_1_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000568 self,
569 "0.0.0.0",
570 "232.1.1.1", 32,
571 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800572 [VppMRoutePath(self.pg0.sw_if_index,
573 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
574 VppMRoutePath(self.pg1.sw_if_index,
575 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000576
577 route_232_1_1_1.add_vpp_config()
578 route_232_1_1_1.update_entry_flags(
579 MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
580
581 #
582 # Now the (*,G) is present, send from connected source
583 #
584 tx = self._mcast_connected_send_stream("232.1.1.1")
585
586 #
587 # Constrct a representation of the signal we expect on pg0
588 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800589 signal_232_1_1_1_itf_0 = VppMFibSignal(self,
590 route_232_1_1_1,
591 self.pg0.sw_if_index,
592 tx[0])
Neale Ranns32e1c012016-11-22 17:07:28 +0000593
594 #
595 # read the only expected signal
596 #
597 signals = self.vapi.mfib_signal_dump()
598
599 self.assertEqual(1, len(signals))
600
601 signal_232_1_1_1_itf_0.compare(signals[0])
602
603 #
604 # reading the signal allows for the generation of another
605 # so send more packets and expect the next signal
606 #
607 tx = self._mcast_connected_send_stream("232.1.1.1")
608
609 signals = self.vapi.mfib_signal_dump()
610 self.assertEqual(1, len(signals))
611 signal_232_1_1_1_itf_0.compare(signals[0])
612
613 #
614 # A Second entry with connected check
615 # one accepting interface, pg0, 1 forwarding interfaces
616 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800617 route_232_1_1_2 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000618 self,
619 "0.0.0.0",
620 "232.1.1.2", 32,
621 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800622 [VppMRoutePath(self.pg0.sw_if_index,
623 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
624 VppMRoutePath(self.pg1.sw_if_index,
625 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000626
627 route_232_1_1_2.add_vpp_config()
628 route_232_1_1_2.update_entry_flags(
629 MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
630
631 #
632 # Send traffic to both entries. One read should net us two signals
633 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800634 signal_232_1_1_2_itf_0 = VppMFibSignal(self,
635 route_232_1_1_2,
636 self.pg0.sw_if_index,
637 tx[0])
Neale Ranns32e1c012016-11-22 17:07:28 +0000638 tx = self._mcast_connected_send_stream("232.1.1.1")
639 tx2 = self._mcast_connected_send_stream("232.1.1.2")
640
641 #
642 # read the only expected signal
643 #
644 signals = self.vapi.mfib_signal_dump()
645
646 self.assertEqual(2, len(signals))
647
648 signal_232_1_1_1_itf_0.compare(signals[1])
649 signal_232_1_1_2_itf_0.compare(signals[0])
650
Neale Rannsd792d9c2017-10-21 10:53:20 -0700651 route_232_1_1_1.update_entry_flags(
652 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
653 route_232_1_1_2.update_entry_flags(
654 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
Neale Ranns32e1c012016-11-22 17:07:28 +0000655
656 def test_ip_mcast_signal(self):
657 """ IP Multicast Signal """
658
659 #
660 # A (*,G).
661 # one accepting interface, pg0, 1 forwarding interfaces
662 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800663 route_232_1_1_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000664 self,
665 "0.0.0.0",
666 "232.1.1.1", 32,
667 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800668 [VppMRoutePath(self.pg0.sw_if_index,
669 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
670 VppMRoutePath(self.pg1.sw_if_index,
671 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000672
673 route_232_1_1_1.add_vpp_config()
674 route_232_1_1_1.update_entry_flags(
675 MRouteEntryFlags.MFIB_ENTRY_FLAG_SIGNAL)
676
677 #
678 # Now the (*,G) is present, send from connected source
679 #
680 tx = self._mcast_connected_send_stream("232.1.1.1")
681
682 #
683 # Constrct a representation of the signal we expect on pg0
684 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800685 signal_232_1_1_1_itf_0 = VppMFibSignal(self,
686 route_232_1_1_1,
687 self.pg0.sw_if_index,
688 tx[0])
Neale Ranns32e1c012016-11-22 17:07:28 +0000689
690 #
691 # read the only expected signal
692 #
693 signals = self.vapi.mfib_signal_dump()
694
695 self.assertEqual(1, len(signals))
696
697 signal_232_1_1_1_itf_0.compare(signals[0])
698
699 #
700 # reading the signal allows for the generation of another
701 # so send more packets and expect the next signal
702 #
703 tx = self._mcast_connected_send_stream("232.1.1.1")
704
705 signals = self.vapi.mfib_signal_dump()
706 self.assertEqual(1, len(signals))
707 signal_232_1_1_1_itf_0.compare(signals[0])
708
709 #
710 # Set the negate-signal on the accepting interval - the signals
711 # should stop
712 #
713 route_232_1_1_1.update_path_flags(
714 self.pg0.sw_if_index,
715 (MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
716 MRouteItfFlags.MFIB_ITF_FLAG_NEGATE_SIGNAL))
717
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800718 self.vapi.cli("clear trace")
Neale Ranns32e1c012016-11-22 17:07:28 +0000719 tx = self._mcast_connected_send_stream("232.1.1.1")
720
721 signals = self.vapi.mfib_signal_dump()
722 self.assertEqual(0, len(signals))
723
724 #
725 # Clear the SIGNAL flag on the entry and the signals should
726 # come back since the interface is still NEGATE-SIGNAL
727 #
728 route_232_1_1_1.update_entry_flags(
729 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
730
731 tx = self._mcast_connected_send_stream("232.1.1.1")
732
733 signals = self.vapi.mfib_signal_dump()
734 self.assertEqual(1, len(signals))
735 signal_232_1_1_1_itf_0.compare(signals[0])
736
737 #
738 # Lastly remove the NEGATE-SIGNAL from the interface and the
739 # signals should stop
740 #
741 route_232_1_1_1.update_path_flags(self.pg0.sw_if_index,
742 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT)
743
744 tx = self._mcast_connected_send_stream("232.1.1.1")
745 signals = self.vapi.mfib_signal_dump()
746 self.assertEqual(0, len(signals))
747
Neale Ranns15002542017-09-10 04:39:11 -0700748 def test_ip_mcast_vrf(self):
749 """ IP Multicast Replication in non-default table"""
750
751 #
752 # An (S,G).
753 # one accepting interface, pg0, 2 forwarding interfaces
754 #
755 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
756 self,
757 "1.1.1.1",
758 "232.1.1.1", 64,
759 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
760 [VppMRoutePath(self.pg8.sw_if_index,
761 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
762 VppMRoutePath(self.pg1.sw_if_index,
763 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
764 VppMRoutePath(self.pg2.sw_if_index,
765 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
766 table_id=10)
767 route_1_1_1_1_232_1_1_1.add_vpp_config()
768
769 #
770 # a stream that matches the route for (1.1.1.1,232.1.1.1)
771 # small packets
772 #
773 self.vapi.cli("clear trace")
774 tx = self.create_stream_ip4(self.pg8, "1.1.1.1", "232.1.1.1")
775 self.pg8.add_stream(tx)
776
777 self.pg_enable_capture(self.pg_interfaces)
778 self.pg_start()
779
780 # We expect replications on Pg1 & 2
781 self.verify_capture_ip4(self.pg1, tx)
782 self.verify_capture_ip4(self.pg2, tx)
783
784 def test_ip6_mcast_vrf(self):
785 """ IPv6 Multicast Replication in non-default table"""
786
787 #
788 # An (S,G).
789 # one accepting interface, pg0, 2 forwarding interfaces
790 #
791 route_2001_ff01_1 = VppIpMRoute(
792 self,
793 "2001::1",
794 "ff01::1", 256,
795 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
796 [VppMRoutePath(self.pg8.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700797 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
798 proto=DpoProto.DPO_PROTO_IP6),
Neale Ranns15002542017-09-10 04:39:11 -0700799 VppMRoutePath(self.pg1.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700800 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
801 proto=DpoProto.DPO_PROTO_IP6),
Neale Ranns15002542017-09-10 04:39:11 -0700802 VppMRoutePath(self.pg2.sw_if_index,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700803 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
804 proto=DpoProto.DPO_PROTO_IP6)],
Neale Ranns15002542017-09-10 04:39:11 -0700805 table_id=10,
806 is_ip6=1)
807 route_2001_ff01_1.add_vpp_config()
808
809 #
810 # a stream that matches the route for (2001::1, ff00::1)
811 #
812 self.vapi.cli("clear trace")
813 tx = self.create_stream_ip6(self.pg8, "2001::1", "ff01::1")
814 self.pg8.add_stream(tx)
815
816 self.pg_enable_capture(self.pg_interfaces)
817 self.pg_start()
818
819 # We expect replications on Pg1, 2,
820 self.verify_capture_ip6(self.pg1, tx)
821 self.verify_capture_ip6(self.pg2, tx)
Neale Ranns32e1c012016-11-22 17:07:28 +0000822
Neale Rannscf3561b2017-12-13 01:44:25 -0800823 def test_bidir(self):
824 """ IP Multicast Bi-directional """
825
826 #
827 # A (*,G). The set of accepting interfaces matching the forwarding
828 #
829 route_232_1_1_1 = VppIpMRoute(
830 self,
831 "0.0.0.0",
832 "232.1.1.1", 32,
833 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
834 [VppMRoutePath(self.pg0.sw_if_index,
835 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
836 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
837 VppMRoutePath(self.pg1.sw_if_index,
838 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
839 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
840 VppMRoutePath(self.pg2.sw_if_index,
841 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
842 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
843 VppMRoutePath(self.pg3.sw_if_index,
844 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
845 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
846 route_232_1_1_1.add_vpp_config()
847
848 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
849 self.pg0.add_stream(tx)
850
851 self.pg_enable_capture(self.pg_interfaces)
852 self.pg_start()
853
854 # We expect replications on Pg1, 2, 3, but not on pg0
855 self.verify_capture_ip4(self.pg1, tx)
856 self.verify_capture_ip4(self.pg2, tx)
857 self.verify_capture_ip4(self.pg3, tx)
858 self.pg0.assert_nothing_captured(
859 remark="IP multicast packets forwarded on PG0")
860
861
Neale Ranns32e1c012016-11-22 17:07:28 +0000862if __name__ == '__main__':
863 unittest.main(testRunner=VppTestRunner)