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