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