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