tests: refactor. Replace literal constant w/ named constant.
[vpp.git] / test / test_bier.py
1 #!/usr/bin/env python
2
3 import unittest
4
5 from framework import VppTestCase, VppTestRunner, running_extended_tests
6 from vpp_ip import DpoProto
7 from vpp_ip_route import VppIpRoute, VppRoutePath, \
8     VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \
9     MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, \
10     VppMplsLabel
11 from vpp_bier import BIER_HDR_PAYLOAD, VppBierImp, VppBierDispEntry, \
12     VppBierDispTable, VppBierTable, VppBierTableID, VppBierRoute
13 from vpp_udp_encap import VppUdpEncap
14
15 import scapy.compat
16 from scapy.packet import Raw
17 from scapy.layers.l2 import Ether
18 from scapy.layers.inet import IP, UDP
19 from scapy.layers.inet6 import IPv6
20 from scapy.contrib.mpls import MPLS
21 from scapy.contrib.bier import BIER, BIERLength, BIFT
22
23 NUM_PKTS = 67
24
25
26 class TestBFIB(VppTestCase):
27     """ BIER FIB Test Case """
28
29     def test_bfib(self):
30         """ BFIB Unit Tests """
31         error = self.vapi.cli("test bier")
32
33         if error:
34             self.logger.critical(error)
35         self.assertNotIn("Failed", error)
36
37
38 class TestBier(VppTestCase):
39     """ BIER Test Case """
40
41     def setUp(self):
42         super(TestBier, self).setUp()
43
44         # create 2 pg interfaces
45         self.create_pg_interfaces(range(3))
46
47         # create the default MPLS table
48         self.tables = []
49         tbl = VppMplsTable(self, 0)
50         tbl.add_vpp_config()
51         self.tables.append(tbl)
52
53         tbl = VppIpTable(self, 10)
54         tbl.add_vpp_config()
55         self.tables.append(tbl)
56
57         # setup both interfaces
58         for i in self.pg_interfaces:
59             if i == self.pg2:
60                 i.set_table_ip4(10)
61             i.admin_up()
62             i.config_ip4()
63             i.resolve_arp()
64             i.enable_mpls()
65
66     def tearDown(self):
67         for i in self.pg_interfaces:
68             i.disable_mpls()
69             i.unconfig_ip4()
70             i.set_table_ip4(0)
71             i.admin_down()
72         super(TestBier, self).tearDown()
73
74     def bier_midpoint(self, hdr_len_id, n_bytes, max_bp):
75         """BIER midpoint"""
76
77         #
78         # Add a BIER table for sub-domain 0, set 0, and BSL 256
79         #
80         bti = VppBierTableID(0, 0, hdr_len_id)
81         bt = VppBierTable(self, bti, 77)
82         bt.add_vpp_config()
83
84         #
85         # A packet with no bits set gets dropped
86         #
87         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
88              MPLS(label=77, ttl=255) /
89              BIER(length=hdr_len_id) /
90              IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
91              UDP(sport=1234, dport=1234) /
92              Raw())
93         pkts = [p]
94
95         self.send_and_assert_no_replies(self.pg0, pkts,
96                                         "Empty Bit-String")
97
98         #
99         # Add a BIER route for each bit-position in the table via a different
100         # next-hop. Testing whether the BIER walk and replicate forwarding
101         # function works for all bit posisitons.
102         #
103         nh_routes = []
104         bier_routes = []
105         for i in range(1, max_bp+1):
106             nh = "10.0.%d.%d" % (i / 255, i % 255)
107             nh_routes.append(
108                 VppIpRoute(self, nh, 32,
109                            [VppRoutePath(self.pg1.remote_ip4,
110                                          self.pg1.sw_if_index,
111                                          labels=[VppMplsLabel(2000+i)])]))
112             nh_routes[-1].add_vpp_config()
113
114             bier_routes.append(
115                 VppBierRoute(self, bti, i,
116                              [VppRoutePath(nh, 0xffffffff,
117                                            labels=[VppMplsLabel(100+i)])]))
118             bier_routes[-1].add_vpp_config()
119
120         #
121         # A packet with all bits set gets replicated once for each bit
122         #
123         pkt_sizes = [64, 1400]
124
125         for pkt_size in pkt_sizes:
126             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
127                  MPLS(label=77, ttl=255) /
128                  BIER(length=hdr_len_id,
129                       BitString=scapy.compat.chb(255)*n_bytes) /
130                  IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
131                  UDP(sport=1234, dport=1234) /
132                  Raw(scapy.compat.chb(5) * pkt_size))
133             pkts = p
134
135             self.pg0.add_stream(pkts)
136             self.pg_enable_capture(self.pg_interfaces)
137             self.pg_start()
138
139             rx = self.pg1.get_capture(max_bp)
140
141             for rxp in rx:
142                 #
143                 # The packets are not required to be sent in bit-position order
144                 # when we setup the routes above we used the bit-position to
145                 # construct the out-label. so use that here to determine the BP
146                 #
147                 olabel = rxp[MPLS]
148                 bp = olabel.label - 2000
149
150                 blabel = olabel[MPLS].payload
151                 self.assertEqual(blabel.label, 100+bp)
152                 self.assertEqual(blabel.ttl, 254)
153
154                 bier_hdr = blabel[MPLS].payload
155
156                 self.assertEqual(bier_hdr.id, 5)
157                 self.assertEqual(bier_hdr.version, 0)
158                 self.assertEqual(bier_hdr.length, hdr_len_id)
159                 self.assertEqual(bier_hdr.entropy, 0)
160                 self.assertEqual(bier_hdr.OAM, 0)
161                 self.assertEqual(bier_hdr.RSV, 0)
162                 self.assertEqual(bier_hdr.DSCP, 0)
163                 self.assertEqual(bier_hdr.Proto, 5)
164
165                 # The bit-string should consist only of the BP given by i.
166                 byte_array = [b'\0'] * (n_bytes)
167                 byte_val = scapy.compat.chb(1 << (bp - 1) % 8)
168                 byte_pos = n_bytes - (((bp - 1) // 8) + 1)
169                 byte_array[byte_pos] = byte_val
170                 bitstring = ''.join([scapy.compat.chb(x) for x in byte_array])
171
172                 self.assertEqual(len(bitstring), len(bier_hdr.BitString))
173                 self.assertEqual(bitstring, bier_hdr.BitString)
174
175         #
176         # cleanup. not strictly necessary, but it's much quicker this way
177         # because the bier_fib_dump and ip_fib_dump will be empty when the
178         # auto-cleanup kicks in
179         #
180         for br in bier_routes:
181             br.remove_vpp_config()
182         for nhr in nh_routes:
183             nhr.remove_vpp_config()
184
185     @unittest.skipUnless(running_extended_tests, "part of extended tests")
186     def test_bier_midpoint_1024(self):
187         """BIER midpoint BSL:1024"""
188         self.bier_midpoint(BIERLength.BIER_LEN_1024, 128, 1024)
189
190     @unittest.skipUnless(running_extended_tests, "part of extended tests")
191     def test_bier_midpoint_512(self):
192         """BIER midpoint BSL:512"""
193         self.bier_midpoint(BIERLength.BIER_LEN_512, 64, 512)
194
195     @unittest.skipUnless(running_extended_tests, "part of extended tests")
196     def test_bier_midpoint_256(self):
197         """BIER midpoint BSL:256"""
198         self.bier_midpoint(BIERLength.BIER_LEN_256, 32, 256)
199
200     @unittest.skipUnless(running_extended_tests, "part of extended tests")
201     def test_bier_midpoint_128(self):
202         """BIER midpoint BSL:128"""
203         self.bier_midpoint(BIERLength.BIER_LEN_128, 16, 128)
204
205     def test_bier_midpoint_64(self):
206         """BIER midpoint BSL:64"""
207         self.bier_midpoint(BIERLength.BIER_LEN_64, 8, 64)
208
209     def test_bier_load_balance(self):
210         """BIER load-balance"""
211
212         #
213         # Add a BIER table for sub-domain 0, set 0, and BSL 256
214         #
215         bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_64)
216         bt = VppBierTable(self, bti, 77)
217         bt.add_vpp_config()
218
219         #
220         # packets with varying entropy
221         #
222         pkts = []
223         for ii in range(257):
224             pkts.append((Ether(dst=self.pg0.local_mac,
225                                src=self.pg0.remote_mac) /
226                          MPLS(label=77, ttl=255) /
227                          BIER(length=BIERLength.BIER_LEN_64,
228                               entropy=ii,
229                               BitString=scapy.compat.chb(255)*16) /
230                          IPv6(src=self.pg0.remote_ip6,
231                               dst=self.pg0.remote_ip6) /
232                          UDP(sport=1234, dport=1234) /
233                          Raw()))
234
235         #
236         # 4 next hops
237         #
238         nhs = [{'ip': "10.0.0.1", 'label': 201},
239                {'ip': "10.0.0.2", 'label': 202},
240                {'ip': "10.0.0.3", 'label': 203},
241                {'ip': "10.0.0.4", 'label': 204}]
242
243         for nh in nhs:
244             ipr = VppIpRoute(
245                 self, nh['ip'], 32,
246                 [VppRoutePath(self.pg1.remote_ip4,
247                               self.pg1.sw_if_index,
248                               labels=[VppMplsLabel(nh['label'])])])
249             ipr.add_vpp_config()
250
251         bier_route = VppBierRoute(
252             self, bti, 1,
253             [VppRoutePath(nhs[0]['ip'], 0xffffffff,
254                           labels=[VppMplsLabel(101)]),
255              VppRoutePath(nhs[1]['ip'], 0xffffffff,
256                           labels=[VppMplsLabel(101)])])
257         bier_route.add_vpp_config()
258
259         rx = self.send_and_expect(self.pg0, pkts, self.pg1)
260
261         #
262         # we should have recieved a packet from each neighbor
263         #
264         for nh in nhs[:2]:
265             self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx))
266
267         #
268         # add the other paths
269         #
270         bier_route.update_paths(
271             [VppRoutePath(nhs[0]['ip'], 0xffffffff,
272                           labels=[VppMplsLabel(101)]),
273              VppRoutePath(nhs[1]['ip'], 0xffffffff,
274                           labels=[VppMplsLabel(101)]),
275              VppRoutePath(nhs[2]['ip'], 0xffffffff,
276                           labels=[VppMplsLabel(101)]),
277              VppRoutePath(nhs[3]['ip'], 0xffffffff,
278                           labels=[VppMplsLabel(101)])])
279
280         rx = self.send_and_expect(self.pg0, pkts, self.pg1)
281         for nh in nhs:
282             self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx))
283
284         #
285         # remove first two paths
286         #
287         bier_route.remove_path(VppRoutePath(nhs[0]['ip'], 0xffffffff,
288                                             labels=[VppMplsLabel(101)]))
289         bier_route.remove_path(VppRoutePath(nhs[1]['ip'], 0xffffffff,
290                                             labels=[VppMplsLabel(101)]))
291
292         rx = self.send_and_expect(self.pg0, pkts, self.pg1)
293         for nh in nhs[2:]:
294             self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx))
295
296         #
297         # remove the last of the paths, deleteing the entry
298         #
299         bier_route.remove_all_paths()
300
301         self.send_and_assert_no_replies(self.pg0, pkts)
302
303     def test_bier_head(self):
304         """BIER head"""
305
306         #
307         # Add a BIER table for sub-domain 0, set 0, and BSL 256
308         #
309         bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
310         bt = VppBierTable(self, bti, 77)
311         bt.add_vpp_config()
312
313         #
314         # 2 bit positions via two next hops
315         #
316         nh1 = "10.0.0.1"
317         nh2 = "10.0.0.2"
318         ip_route_1 = VppIpRoute(self, nh1, 32,
319                                 [VppRoutePath(self.pg1.remote_ip4,
320                                               self.pg1.sw_if_index,
321                                               labels=[VppMplsLabel(2001)])])
322         ip_route_2 = VppIpRoute(self, nh2, 32,
323                                 [VppRoutePath(self.pg1.remote_ip4,
324                                               self.pg1.sw_if_index,
325                                               labels=[VppMplsLabel(2002)])])
326         ip_route_1.add_vpp_config()
327         ip_route_2.add_vpp_config()
328
329         bier_route_1 = VppBierRoute(self, bti, 1,
330                                     [VppRoutePath(nh1, 0xffffffff,
331                                                   labels=[VppMplsLabel(101)])])
332         bier_route_2 = VppBierRoute(self, bti, 2,
333                                     [VppRoutePath(nh2, 0xffffffff,
334                                                   labels=[VppMplsLabel(102)])])
335         bier_route_1.add_vpp_config()
336         bier_route_2.add_vpp_config()
337
338         #
339         # An imposition object with both bit-positions set
340         #
341         bi = VppBierImp(self, bti, 333, scapy.compat.chb(0x3) * 32)
342         bi.add_vpp_config()
343
344         #
345         # Add a multicast route that will forward into the BIER doamin
346         #
347         route_ing_232_1_1_1 = VppIpMRoute(
348             self,
349             "0.0.0.0",
350             "232.1.1.1", 32,
351             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
352             paths=[VppMRoutePath(self.pg0.sw_if_index,
353                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
354                    VppMRoutePath(0xffffffff,
355                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
356                                  proto=DpoProto.DPO_PROTO_BIER,
357                                  bier_imp=bi.bi_index)])
358         route_ing_232_1_1_1.add_vpp_config()
359
360         #
361         # inject an IP packet. We expect it to be BIER encapped and
362         # replicated.
363         #
364         p = (Ether(dst=self.pg0.local_mac,
365                    src=self.pg0.remote_mac) /
366              IP(src="1.1.1.1", dst="232.1.1.1") /
367              UDP(sport=1234, dport=1234))
368
369         self.pg0.add_stream([p])
370         self.pg_enable_capture(self.pg_interfaces)
371         self.pg_start()
372
373         rx = self.pg1.get_capture(2)
374
375         #
376         # Encap Stack is; eth, MPLS, MPLS, BIER
377         #
378         igp_mpls = rx[0][MPLS]
379         self.assertEqual(igp_mpls.label, 2001)
380         self.assertEqual(igp_mpls.ttl, 64)
381         self.assertEqual(igp_mpls.s, 0)
382         bier_mpls = igp_mpls[MPLS].payload
383         self.assertEqual(bier_mpls.label, 101)
384         self.assertEqual(bier_mpls.ttl, 64)
385         self.assertEqual(bier_mpls.s, 1)
386         self.assertEqual(rx[0][BIER].length, 2)
387
388         igp_mpls = rx[1][MPLS]
389         self.assertEqual(igp_mpls.label, 2002)
390         self.assertEqual(igp_mpls.ttl, 64)
391         self.assertEqual(igp_mpls.s, 0)
392         bier_mpls = igp_mpls[MPLS].payload
393         self.assertEqual(bier_mpls.label, 102)
394         self.assertEqual(bier_mpls.ttl, 64)
395         self.assertEqual(bier_mpls.s, 1)
396         self.assertEqual(rx[0][BIER].length, 2)
397
398     def test_bier_tail(self):
399         """BIER Tail"""
400
401         #
402         # Add a BIER table for sub-domain 0, set 0, and BSL 256
403         #
404         bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
405         bt = VppBierTable(self, bti, 77)
406         bt.add_vpp_config()
407
408         #
409         # disposition table
410         #
411         bdt = VppBierDispTable(self, 8)
412         bdt.add_vpp_config()
413
414         #
415         # BIER route in table that's for-us
416         #
417         bier_route_1 = VppBierRoute(
418             self, bti, 1,
419             [VppRoutePath("0.0.0.0",
420                           0xffffffff,
421                           proto=DpoProto.DPO_PROTO_BIER,
422                           nh_table_id=8)])
423         bier_route_1.add_vpp_config()
424
425         #
426         # An entry in the disposition table
427         #
428         bier_de_1 = VppBierDispEntry(self, bdt.id, 99,
429                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
430                                      DpoProto.DPO_PROTO_BIER,
431                                      "0.0.0.0", 0, rpf_id=8192)
432         bier_de_1.add_vpp_config()
433
434         #
435         # A multicast route to forward post BIER disposition
436         #
437         route_eg_232_1_1_1 = VppIpMRoute(
438             self,
439             "0.0.0.0",
440             "232.1.1.1", 32,
441             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
442             paths=[VppMRoutePath(self.pg1.sw_if_index,
443                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
444         route_eg_232_1_1_1.add_vpp_config()
445         route_eg_232_1_1_1.update_rpf_id(8192)
446
447         #
448         # A packet with all bits set gets spat out to BP:1
449         #
450         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
451              MPLS(label=77, ttl=255) /
452              BIER(length=BIERLength.BIER_LEN_256,
453                   BitString=scapy.compat.chb(255)*32,
454                   BFRID=99) /
455              IP(src="1.1.1.1", dst="232.1.1.1") /
456              UDP(sport=1234, dport=1234) /
457              Raw())
458
459         self.send_and_expect(self.pg0, [p], self.pg1)
460
461         #
462         # A packet that does not match the Disposition entry gets dropped
463         #
464         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
465              MPLS(label=77, ttl=255) /
466              BIER(length=BIERLength.BIER_LEN_256,
467                   BitString=scapy.compat.chb(255)*32,
468                   BFRID=77) /
469              IP(src="1.1.1.1", dst="232.1.1.1") /
470              UDP(sport=1234, dport=1234) /
471              Raw())
472         self.send_and_assert_no_replies(self.pg0, p*2,
473                                         "no matching disposition entry")
474
475         #
476         # Add the default route to the disposition table
477         #
478         bier_de_2 = VppBierDispEntry(self, bdt.id, 0,
479                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
480                                      DpoProto.DPO_PROTO_BIER,
481                                      "0.0.0.0", 0, rpf_id=8192)
482         bier_de_2.add_vpp_config()
483
484         #
485         # now the previous packet is forwarded
486         #
487         self.send_and_expect(self.pg0, [p], self.pg1)
488
489         #
490         # A multicast route to forward post BIER disposition that needs
491         # a check against sending back into the BIER core
492         #
493         bi = VppBierImp(self, bti, 333, scapy.compat.chb(0x3) * 32)
494         bi.add_vpp_config()
495
496         route_eg_232_1_1_2 = VppIpMRoute(
497             self,
498             "0.0.0.0",
499             "232.1.1.2", 32,
500             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
501             paths=[VppMRoutePath(0xffffffff,
502                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
503                                  proto=DpoProto.DPO_PROTO_BIER,
504                                  bier_imp=bi.bi_index),
505                    VppMRoutePath(self.pg1.sw_if_index,
506                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
507         route_eg_232_1_1_2.add_vpp_config()
508         route_eg_232_1_1_2.update_rpf_id(8192)
509
510         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
511              MPLS(label=77, ttl=255) /
512              BIER(length=BIERLength.BIER_LEN_256,
513                   BitString=scapy.compat.chb(255)*32,
514                   BFRID=77) /
515              IP(src="1.1.1.1", dst="232.1.1.2") /
516              UDP(sport=1234, dport=1234) /
517              Raw())
518         self.send_and_expect(self.pg0, [p], self.pg1)
519
520     def bier_e2e(self, hdr_len_id, n_bytes, max_bp):
521         """ BIER end-to-end"""
522
523         #
524         # Add a BIER table for sub-domain 0, set 0, and BSL 256
525         #
526         bti = VppBierTableID(0, 0, hdr_len_id)
527         bt = VppBierTable(self, bti, 77)
528         bt.add_vpp_config()
529
530         lowest = [b'\0'] * (n_bytes)
531         lowest[-1] = scapy.compat.chb(1)
532         highest = [b'\0'] * (n_bytes)
533         highest[0] = scapy.compat.chb(128)
534
535         #
536         # Impostion Sets bit strings
537         #
538         bi_low = VppBierImp(self, bti, 333, lowest)
539         bi_low.add_vpp_config()
540         bi_high = VppBierImp(self, bti, 334, highest)
541         bi_high.add_vpp_config()
542
543         #
544         # Add a multicast route that will forward into the BIER doamin
545         #
546         route_ing_232_1_1_1 = VppIpMRoute(
547             self,
548             "0.0.0.0",
549             "232.1.1.1", 32,
550             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
551             paths=[VppMRoutePath(self.pg0.sw_if_index,
552                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
553                    VppMRoutePath(0xffffffff,
554                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
555                                  proto=DpoProto.DPO_PROTO_BIER,
556                                  bier_imp=bi_low.bi_index)])
557         route_ing_232_1_1_1.add_vpp_config()
558         route_ing_232_1_1_2 = VppIpMRoute(
559             self,
560             "0.0.0.0",
561             "232.1.1.2", 32,
562             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
563             paths=[VppMRoutePath(self.pg0.sw_if_index,
564                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
565                    VppMRoutePath(0xffffffff,
566                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
567                                  proto=DpoProto.DPO_PROTO_BIER,
568                                  bier_imp=bi_high.bi_index)])
569         route_ing_232_1_1_2.add_vpp_config()
570
571         #
572         # disposition table 8
573         #
574         bdt = VppBierDispTable(self, 8)
575         bdt.add_vpp_config()
576
577         #
578         # BIER routes in table that are for-us, resolving through
579         # disp table 8.
580         #
581         bier_route_1 = VppBierRoute(
582             self, bti, 1,
583             [VppRoutePath("0.0.0.0",
584                           0xffffffff,
585                           proto=DpoProto.DPO_PROTO_BIER,
586                           nh_table_id=8)])
587         bier_route_1.add_vpp_config()
588         bier_route_max = VppBierRoute(
589             self, bti, max_bp,
590             [VppRoutePath("0.0.0.0",
591                           0xffffffff,
592                           nh_table_id=8,
593                           proto=DpoProto.DPO_PROTO_BIER)])
594         bier_route_max.add_vpp_config()
595
596         #
597         # An entry in the disposition table for sender 333
598         #  lookup in VRF 10
599         #
600         bier_de_1 = VppBierDispEntry(self, bdt.id, 333,
601                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
602                                      DpoProto.DPO_PROTO_BIER,
603                                      "0.0.0.0", 10, rpf_id=8192)
604         bier_de_1.add_vpp_config()
605         bier_de_1 = VppBierDispEntry(self, bdt.id, 334,
606                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
607                                      DpoProto.DPO_PROTO_BIER,
608                                      "0.0.0.0", 10, rpf_id=8193)
609         bier_de_1.add_vpp_config()
610
611         #
612         # Add a multicast routes that will forward the traffic
613         # post-disposition
614         #
615         route_eg_232_1_1_1 = VppIpMRoute(
616             self,
617             "0.0.0.0",
618             "232.1.1.1", 32,
619             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
620             table_id=10,
621             paths=[VppMRoutePath(self.pg1.sw_if_index,
622                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
623         route_eg_232_1_1_1.add_vpp_config()
624         route_eg_232_1_1_1.update_rpf_id(8192)
625         route_eg_232_1_1_2 = VppIpMRoute(
626             self,
627             "0.0.0.0",
628             "232.1.1.2", 32,
629             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
630             table_id=10,
631             paths=[VppMRoutePath(self.pg1.sw_if_index,
632                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
633         route_eg_232_1_1_2.add_vpp_config()
634         route_eg_232_1_1_2.update_rpf_id(8193)
635
636         #
637         # inject a packet in VRF-0. We expect it to be BIER encapped,
638         # replicated, then hit the disposition and be forwarded
639         # out of VRF 10, i.e. on pg1
640         #
641         p = (Ether(dst=self.pg0.local_mac,
642                    src=self.pg0.remote_mac) /
643              IP(src="1.1.1.1", dst="232.1.1.1") /
644              UDP(sport=1234, dport=1234) /
645              Raw(scapy.compat.chb(5) * 32))
646
647         rx = self.send_and_expect(self.pg0, p*NUM_PKTS, self.pg1)
648
649         self.assertEqual(rx[0][IP].src, "1.1.1.1")
650         self.assertEqual(rx[0][IP].dst, "232.1.1.1")
651
652         p = (Ether(dst=self.pg0.local_mac,
653                    src=self.pg0.remote_mac) /
654              IP(src="1.1.1.1", dst="232.1.1.2") /
655              UDP(sport=1234, dport=1234) /
656              Raw(scapy.compat.chb(5) * 512))
657
658         rx = self.send_and_expect(self.pg0, p*NUM_PKTS, self.pg1)
659         self.assertEqual(rx[0][IP].src, "1.1.1.1")
660         self.assertEqual(rx[0][IP].dst, "232.1.1.2")
661
662     @unittest.skipUnless(running_extended_tests, "part of extended tests")
663     def test_bier_e2e_1024(self):
664         """ BIER end-to-end BSL:1024"""
665         self.bier_e2e(BIERLength.BIER_LEN_1024, 128, 1024)
666
667     @unittest.skipUnless(running_extended_tests, "part of extended tests")
668     def test_bier_e2e_512(self):
669         """ BIER end-to-end BSL:512"""
670         self.bier_e2e(BIERLength.BIER_LEN_512, 64, 512)
671
672     @unittest.skipUnless(running_extended_tests, "part of extended tests")
673     def test_bier_e2e_256(self):
674         """ BIER end-to-end BSL:256"""
675         self.bier_e2e(BIERLength.BIER_LEN_256, 32, 256)
676
677     @unittest.skipUnless(running_extended_tests, "part of extended tests")
678     def test_bier_e2e_128(self):
679         """ BIER end-to-end BSL:128"""
680         self.bier_e2e(BIERLength.BIER_LEN_128, 16, 128)
681
682     def test_bier_e2e_64(self):
683         """ BIER end-to-end BSL:64"""
684         self.bier_e2e(BIERLength.BIER_LEN_64, 8, 64)
685
686     def test_bier_head_o_udp(self):
687         """BIER head over UDP"""
688
689         #
690         # Add a BIER table for sub-domain 1, set 0, and BSL 256
691         #
692         bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
693         bt = VppBierTable(self, bti, 77)
694         bt.add_vpp_config()
695
696         #
697         # 1 bit positions via 1 next hops
698         #
699         nh1 = "10.0.0.1"
700         ip_route = VppIpRoute(self, nh1, 32,
701                               [VppRoutePath(self.pg1.remote_ip4,
702                                             self.pg1.sw_if_index,
703                                             labels=[VppMplsLabel(2001)])])
704         ip_route.add_vpp_config()
705
706         udp_encap = VppUdpEncap(self,
707                                 self.pg0.local_ip4,
708                                 nh1,
709                                 330, 8138)
710         udp_encap.add_vpp_config()
711
712         bier_route = VppBierRoute(
713             self, bti, 1,
714             [VppRoutePath("0.0.0.0",
715                           0xFFFFFFFF,
716                           is_udp_encap=1,
717                           next_hop_id=udp_encap.id)])
718         bier_route.add_vpp_config()
719
720         #
721         # An 2 imposition objects with all bit-positions set
722         # only use the second, but creating 2 tests with a non-zero
723         # value index in the route add
724         #
725         bi = VppBierImp(self, bti, 333, scapy.compat.chb(0xff) * 32)
726         bi.add_vpp_config()
727         bi2 = VppBierImp(self, bti, 334, scapy.compat.chb(0xff) * 32)
728         bi2.add_vpp_config()
729
730         #
731         # Add a multicast route that will forward into the BIER doamin
732         #
733         route_ing_232_1_1_1 = VppIpMRoute(
734             self,
735             "0.0.0.0",
736             "232.1.1.1", 32,
737             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
738             paths=[VppMRoutePath(self.pg0.sw_if_index,
739                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
740                    VppMRoutePath(0xffffffff,
741                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
742                                  proto=DpoProto.DPO_PROTO_BIER,
743                                  bier_imp=bi2.bi_index)])
744         route_ing_232_1_1_1.add_vpp_config()
745
746         #
747         # inject a packet an IP. We expect it to be BIER and UDP encapped,
748         #
749         p = (Ether(dst=self.pg0.local_mac,
750                    src=self.pg0.remote_mac) /
751              IP(src="1.1.1.1", dst="232.1.1.1") /
752              UDP(sport=1234, dport=1234))
753
754         self.pg0.add_stream([p])
755         self.pg_enable_capture(self.pg_interfaces)
756         self.pg_start()
757
758         rx = self.pg1.get_capture(1)
759
760         #
761         # Encap Stack is, eth, IP, UDP, BIFT, BIER
762         #
763         self.assertEqual(rx[0][IP].src, self.pg0.local_ip4)
764         self.assertEqual(rx[0][IP].dst, nh1)
765         self.assertEqual(rx[0][UDP].sport, 330)
766         self.assertEqual(rx[0][UDP].dport, 8138)
767         self.assertEqual(rx[0][BIFT].bsl, BIERLength.BIER_LEN_256)
768         self.assertEqual(rx[0][BIFT].sd, 1)
769         self.assertEqual(rx[0][BIFT].set, 0)
770         self.assertEqual(rx[0][BIFT].ttl, 64)
771         self.assertEqual(rx[0][BIER].length, 2)
772
773     def test_bier_tail_o_udp(self):
774         """BIER Tail over UDP"""
775
776         #
777         # Add a BIER table for sub-domain 0, set 0, and BSL 256
778         #
779         bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
780         bt = VppBierTable(self, bti, MPLS_LABEL_INVALID)
781         bt.add_vpp_config()
782
783         #
784         # disposition table
785         #
786         bdt = VppBierDispTable(self, 8)
787         bdt.add_vpp_config()
788
789         #
790         # BIER route in table that's for-us
791         #
792         bier_route_1 = VppBierRoute(
793             self, bti, 1,
794             [VppRoutePath("0.0.0.0",
795                           0xffffffff,
796                           proto=DpoProto.DPO_PROTO_BIER,
797                           nh_table_id=8)])
798         bier_route_1.add_vpp_config()
799
800         #
801         # An entry in the disposition table
802         #
803         bier_de_1 = VppBierDispEntry(self, bdt.id, 99,
804                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
805                                      DpoProto.DPO_PROTO_BIER,
806                                      "0.0.0.0", 0, rpf_id=8192)
807         bier_de_1.add_vpp_config()
808
809         #
810         # A multicast route to forward post BIER disposition
811         #
812         route_eg_232_1_1_1 = VppIpMRoute(
813             self,
814             "0.0.0.0",
815             "232.1.1.1", 32,
816             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
817             paths=[VppMRoutePath(self.pg1.sw_if_index,
818                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
819         route_eg_232_1_1_1.add_vpp_config()
820         route_eg_232_1_1_1.update_rpf_id(8192)
821
822         #
823         # A packet with all bits set gets spat out to BP:1
824         #
825         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
826              IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
827              UDP(sport=333, dport=8138) /
828              BIFT(sd=1, set=0, bsl=2, ttl=255) /
829              BIER(length=BIERLength.BIER_LEN_256,
830                   BitString=scapy.compat.chb(255)*32,
831                   BFRID=99) /
832              IP(src="1.1.1.1", dst="232.1.1.1") /
833              UDP(sport=1234, dport=1234) /
834              Raw())
835
836         rx = self.send_and_expect(self.pg0, [p], self.pg1)
837
838
839 if __name__ == '__main__':
840     unittest.main(testRunner=VppTestRunner)