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