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