9a9db3b0b6ed05370ac7cdb03ee16636a35f8f28
[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 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether
17 from scapy.layers.inet import IP, UDP
18 from scapy.layers.inet6 import IPv6
19 from scapy.contrib.mpls import MPLS
20 from scapy.contrib.bier import BIER, BIERLength, BIFT
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.assertNotIn("Failed", error)
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_load_balance(self):
206         """BIER load-balance"""
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_64)
212         bt = VppBierTable(self, bti, 77)
213         bt.add_vpp_config()
214
215         #
216         # packets with varying entropy
217         #
218         pkts = []
219         for ii in range(257):
220             pkts.append((Ether(dst=self.pg0.local_mac,
221                                src=self.pg0.remote_mac) /
222                          MPLS(label=77, ttl=255) /
223                          BIER(length=BIERLength.BIER_LEN_64,
224                               entropy=ii,
225                               BitString=chr(255)*16) /
226                          IPv6(src=self.pg0.remote_ip6,
227                               dst=self.pg0.remote_ip6) /
228                          UDP(sport=1234, dport=1234) /
229                          Raw()))
230
231         #
232         # 4 next hops
233         #
234         nhs = [{'ip': "10.0.0.1", 'label': 201},
235                {'ip': "10.0.0.2", 'label': 202},
236                {'ip': "10.0.0.3", 'label': 203},
237                {'ip': "10.0.0.4", 'label': 204}]
238
239         for nh in nhs:
240             ipr = VppIpRoute(
241                 self, nh['ip'], 32,
242                 [VppRoutePath(self.pg1.remote_ip4,
243                               self.pg1.sw_if_index,
244                               labels=[VppMplsLabel(nh['label'])])])
245             ipr.add_vpp_config()
246
247         bier_route = VppBierRoute(
248             self, bti, 1,
249             [VppRoutePath(nhs[0]['ip'], 0xffffffff,
250                           labels=[VppMplsLabel(101)]),
251              VppRoutePath(nhs[1]['ip'], 0xffffffff,
252                           labels=[VppMplsLabel(101)])])
253         bier_route.add_vpp_config()
254
255         rx = self.send_and_expect(self.pg0, pkts, self.pg1)
256
257         #
258         # we should have recieved a packet from each neighbor
259         #
260         for nh in nhs[:2]:
261             self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx))
262
263         #
264         # add the other paths
265         #
266         bier_route.update_paths(
267             [VppRoutePath(nhs[0]['ip'], 0xffffffff,
268                           labels=[VppMplsLabel(101)]),
269              VppRoutePath(nhs[1]['ip'], 0xffffffff,
270                           labels=[VppMplsLabel(101)]),
271              VppRoutePath(nhs[2]['ip'], 0xffffffff,
272                           labels=[VppMplsLabel(101)]),
273              VppRoutePath(nhs[3]['ip'], 0xffffffff,
274                           labels=[VppMplsLabel(101)])])
275
276         rx = self.send_and_expect(self.pg0, pkts, self.pg1)
277         for nh in nhs:
278             self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx))
279
280         #
281         # remove first two paths
282         #
283         bier_route.remove_path(VppRoutePath(nhs[0]['ip'], 0xffffffff,
284                                             labels=[VppMplsLabel(101)]))
285         bier_route.remove_path(VppRoutePath(nhs[1]['ip'], 0xffffffff,
286                                             labels=[VppMplsLabel(101)]))
287
288         rx = self.send_and_expect(self.pg0, pkts, self.pg1)
289         for nh in nhs[2:]:
290             self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx))
291
292         #
293         # remove the last of the paths, deleteing the entry
294         #
295         bier_route.remove_all_paths()
296
297         self.send_and_assert_no_replies(self.pg0, pkts)
298
299     def test_bier_head(self):
300         """BIER head"""
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         # 2 bit positions via two next hops
311         #
312         nh1 = "10.0.0.1"
313         nh2 = "10.0.0.2"
314         ip_route_1 = VppIpRoute(self, nh1, 32,
315                                 [VppRoutePath(self.pg1.remote_ip4,
316                                               self.pg1.sw_if_index,
317                                               labels=[VppMplsLabel(2001)])])
318         ip_route_2 = VppIpRoute(self, nh2, 32,
319                                 [VppRoutePath(self.pg1.remote_ip4,
320                                               self.pg1.sw_if_index,
321                                               labels=[VppMplsLabel(2002)])])
322         ip_route_1.add_vpp_config()
323         ip_route_2.add_vpp_config()
324
325         bier_route_1 = VppBierRoute(self, bti, 1,
326                                     [VppRoutePath(nh1, 0xffffffff,
327                                                   labels=[VppMplsLabel(101)])])
328         bier_route_2 = VppBierRoute(self, bti, 2,
329                                     [VppRoutePath(nh2, 0xffffffff,
330                                                   labels=[VppMplsLabel(102)])])
331         bier_route_1.add_vpp_config()
332         bier_route_2.add_vpp_config()
333
334         #
335         # An imposition object with both bit-positions set
336         #
337         bi = VppBierImp(self, bti, 333, chr(0x3) * 32)
338         bi.add_vpp_config()
339
340         #
341         # Add a multicast route that will forward into the BIER doamin
342         #
343         route_ing_232_1_1_1 = VppIpMRoute(
344             self,
345             "0.0.0.0",
346             "232.1.1.1", 32,
347             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
348             paths=[VppMRoutePath(self.pg0.sw_if_index,
349                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
350                    VppMRoutePath(0xffffffff,
351                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
352                                  proto=DpoProto.DPO_PROTO_BIER,
353                                  bier_imp=bi.bi_index)])
354         route_ing_232_1_1_1.add_vpp_config()
355
356         #
357         # inject an IP packet. We expect it to be BIER encapped and
358         # replicated.
359         #
360         p = (Ether(dst=self.pg0.local_mac,
361                    src=self.pg0.remote_mac) /
362              IP(src="1.1.1.1", dst="232.1.1.1") /
363              UDP(sport=1234, dport=1234))
364
365         self.pg0.add_stream([p])
366         self.pg_enable_capture(self.pg_interfaces)
367         self.pg_start()
368
369         rx = self.pg1.get_capture(2)
370
371         #
372         # Encap Stack is; eth, MPLS, MPLS, BIER
373         #
374         igp_mpls = rx[0][MPLS]
375         self.assertEqual(igp_mpls.label, 2001)
376         self.assertEqual(igp_mpls.ttl, 64)
377         self.assertEqual(igp_mpls.s, 0)
378         bier_mpls = igp_mpls[MPLS].payload
379         self.assertEqual(bier_mpls.label, 101)
380         self.assertEqual(bier_mpls.ttl, 64)
381         self.assertEqual(bier_mpls.s, 1)
382         self.assertEqual(rx[0][BIER].length, 2)
383
384         igp_mpls = rx[1][MPLS]
385         self.assertEqual(igp_mpls.label, 2002)
386         self.assertEqual(igp_mpls.ttl, 64)
387         self.assertEqual(igp_mpls.s, 0)
388         bier_mpls = igp_mpls[MPLS].payload
389         self.assertEqual(bier_mpls.label, 102)
390         self.assertEqual(bier_mpls.ttl, 64)
391         self.assertEqual(bier_mpls.s, 1)
392         self.assertEqual(rx[0][BIER].length, 2)
393
394     def test_bier_tail(self):
395         """BIER Tail"""
396
397         #
398         # Add a BIER table for sub-domain 0, set 0, and BSL 256
399         #
400         bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
401         bt = VppBierTable(self, bti, 77)
402         bt.add_vpp_config()
403
404         #
405         # disposition table
406         #
407         bdt = VppBierDispTable(self, 8)
408         bdt.add_vpp_config()
409
410         #
411         # BIER route in table that's for-us
412         #
413         bier_route_1 = VppBierRoute(
414             self, bti, 1,
415             [VppRoutePath("0.0.0.0",
416                           0xffffffff,
417                           proto=DpoProto.DPO_PROTO_BIER,
418                           nh_table_id=8)])
419         bier_route_1.add_vpp_config()
420
421         #
422         # An entry in the disposition table
423         #
424         bier_de_1 = VppBierDispEntry(self, bdt.id, 99,
425                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
426                                      DpoProto.DPO_PROTO_BIER,
427                                      "0.0.0.0", 0, rpf_id=8192)
428         bier_de_1.add_vpp_config()
429
430         #
431         # A multicast route to forward post BIER disposition
432         #
433         route_eg_232_1_1_1 = VppIpMRoute(
434             self,
435             "0.0.0.0",
436             "232.1.1.1", 32,
437             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
438             paths=[VppMRoutePath(self.pg1.sw_if_index,
439                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
440         route_eg_232_1_1_1.add_vpp_config()
441         route_eg_232_1_1_1.update_rpf_id(8192)
442
443         #
444         # A packet with all bits set gets spat out to BP:1
445         #
446         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
447              MPLS(label=77, ttl=255) /
448              BIER(length=BIERLength.BIER_LEN_256,
449                   BitString=chr(255)*32,
450                   BFRID=99) /
451              IP(src="1.1.1.1", dst="232.1.1.1") /
452              UDP(sport=1234, dport=1234) /
453              Raw())
454
455         self.send_and_expect(self.pg0, [p], self.pg1)
456
457         #
458         # A packet that does not match the Disposition entry gets dropped
459         #
460         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
461              MPLS(label=77, ttl=255) /
462              BIER(length=BIERLength.BIER_LEN_256,
463                   BitString=chr(255)*32,
464                   BFRID=77) /
465              IP(src="1.1.1.1", dst="232.1.1.1") /
466              UDP(sport=1234, dport=1234) /
467              Raw())
468         self.send_and_assert_no_replies(self.pg0, p*2,
469                                         "no matching disposition entry")
470
471         #
472         # Add the default route to the disposition table
473         #
474         bier_de_2 = VppBierDispEntry(self, bdt.id, 0,
475                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
476                                      DpoProto.DPO_PROTO_BIER,
477                                      "0.0.0.0", 0, rpf_id=8192)
478         bier_de_2.add_vpp_config()
479
480         #
481         # now the previous packet is forwarded
482         #
483         self.send_and_expect(self.pg0, [p], self.pg1)
484
485         #
486         # A multicast route to forward post BIER disposition that needs
487         # a check against sending back into the BIER core
488         #
489         bi = VppBierImp(self, bti, 333, chr(0x3) * 32)
490         bi.add_vpp_config()
491
492         route_eg_232_1_1_2 = VppIpMRoute(
493             self,
494             "0.0.0.0",
495             "232.1.1.2", 32,
496             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
497             paths=[VppMRoutePath(0xffffffff,
498                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
499                                  proto=DpoProto.DPO_PROTO_BIER,
500                                  bier_imp=bi.bi_index),
501                    VppMRoutePath(self.pg1.sw_if_index,
502                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
503         route_eg_232_1_1_2.add_vpp_config()
504         route_eg_232_1_1_2.update_rpf_id(8192)
505
506         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
507              MPLS(label=77, ttl=255) /
508              BIER(length=BIERLength.BIER_LEN_256,
509                   BitString=chr(255)*32,
510                   BFRID=77) /
511              IP(src="1.1.1.1", dst="232.1.1.2") /
512              UDP(sport=1234, dport=1234) /
513              Raw())
514         self.send_and_expect(self.pg0, [p], self.pg1)
515
516     def bier_e2e(self, hdr_len_id, n_bytes, max_bp):
517         """ BIER end-to-end"""
518
519         #
520         # Add a BIER table for sub-domain 0, set 0, and BSL 256
521         #
522         bti = VppBierTableID(0, 0, hdr_len_id)
523         bt = VppBierTable(self, bti, 77)
524         bt.add_vpp_config()
525
526         lowest = ['\0'] * (n_bytes)
527         lowest[-1] = chr(1)
528         highest = ['\0'] * (n_bytes)
529         highest[0] = chr(128)
530
531         #
532         # Impostion Sets bit strings
533         #
534         bi_low = VppBierImp(self, bti, 333, lowest)
535         bi_low.add_vpp_config()
536         bi_high = VppBierImp(self, bti, 334, highest)
537         bi_high.add_vpp_config()
538
539         #
540         # Add a multicast route that will forward into the BIER doamin
541         #
542         route_ing_232_1_1_1 = VppIpMRoute(
543             self,
544             "0.0.0.0",
545             "232.1.1.1", 32,
546             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
547             paths=[VppMRoutePath(self.pg0.sw_if_index,
548                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
549                    VppMRoutePath(0xffffffff,
550                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
551                                  proto=DpoProto.DPO_PROTO_BIER,
552                                  bier_imp=bi_low.bi_index)])
553         route_ing_232_1_1_1.add_vpp_config()
554         route_ing_232_1_1_2 = VppIpMRoute(
555             self,
556             "0.0.0.0",
557             "232.1.1.2", 32,
558             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
559             paths=[VppMRoutePath(self.pg0.sw_if_index,
560                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
561                    VppMRoutePath(0xffffffff,
562                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
563                                  proto=DpoProto.DPO_PROTO_BIER,
564                                  bier_imp=bi_high.bi_index)])
565         route_ing_232_1_1_2.add_vpp_config()
566
567         #
568         # disposition table 8
569         #
570         bdt = VppBierDispTable(self, 8)
571         bdt.add_vpp_config()
572
573         #
574         # BIER routes in table that are for-us, resolving through
575         # disp table 8.
576         #
577         bier_route_1 = VppBierRoute(
578             self, bti, 1,
579             [VppRoutePath("0.0.0.0",
580                           0xffffffff,
581                           proto=DpoProto.DPO_PROTO_BIER,
582                           nh_table_id=8)])
583         bier_route_1.add_vpp_config()
584         bier_route_max = VppBierRoute(self, bti, max_bp,
585                                       [VppRoutePath("0.0.0.0",
586                                                     0xffffffff,
587                                                     nh_table_id=8)])
588         bier_route_max.add_vpp_config()
589
590         #
591         # An entry in the disposition table for sender 333
592         #  lookup in VRF 10
593         #
594         bier_de_1 = VppBierDispEntry(self, bdt.id, 333,
595                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
596                                      DpoProto.DPO_PROTO_BIER,
597                                      "0.0.0.0", 10, rpf_id=8192)
598         bier_de_1.add_vpp_config()
599         bier_de_1 = VppBierDispEntry(self, bdt.id, 334,
600                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
601                                      DpoProto.DPO_PROTO_BIER,
602                                      "0.0.0.0", 10, rpf_id=8193)
603         bier_de_1.add_vpp_config()
604
605         #
606         # Add a multicast routes that will forward the traffic
607         # post-disposition
608         #
609         route_eg_232_1_1_1 = VppIpMRoute(
610             self,
611             "0.0.0.0",
612             "232.1.1.1", 32,
613             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
614             table_id=10,
615             paths=[VppMRoutePath(self.pg1.sw_if_index,
616                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
617         route_eg_232_1_1_1.add_vpp_config()
618         route_eg_232_1_1_1.update_rpf_id(8192)
619         route_eg_232_1_1_2 = VppIpMRoute(
620             self,
621             "0.0.0.0",
622             "232.1.1.2", 32,
623             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
624             table_id=10,
625             paths=[VppMRoutePath(self.pg1.sw_if_index,
626                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
627         route_eg_232_1_1_2.add_vpp_config()
628         route_eg_232_1_1_2.update_rpf_id(8193)
629
630         #
631         # inject a packet in VRF-0. We expect it to be BIER encapped,
632         # replicated, then hit the disposition and be forwarded
633         # out of VRF 10, i.e. on pg1
634         #
635         p = (Ether(dst=self.pg0.local_mac,
636                    src=self.pg0.remote_mac) /
637              IP(src="1.1.1.1", dst="232.1.1.1") /
638              UDP(sport=1234, dport=1234) /
639              Raw(chr(5) * 32))
640
641         rx = self.send_and_expect(self.pg0, p*65, self.pg1)
642
643         self.assertEqual(rx[0][IP].src, "1.1.1.1")
644         self.assertEqual(rx[0][IP].dst, "232.1.1.1")
645
646         p = (Ether(dst=self.pg0.local_mac,
647                    src=self.pg0.remote_mac) /
648              IP(src="1.1.1.1", dst="232.1.1.2") /
649              UDP(sport=1234, dport=1234) /
650              Raw(chr(5) * 512))
651
652         rx = self.send_and_expect(self.pg0, p*65, self.pg1)
653         self.assertEqual(rx[0][IP].src, "1.1.1.1")
654         self.assertEqual(rx[0][IP].dst, "232.1.1.2")
655
656     @unittest.skipUnless(running_extended_tests, "part of extended tests")
657     def test_bier_e2e_1024(self):
658         """ BIER end-to-end BSL:1024"""
659         self.bier_e2e(BIERLength.BIER_LEN_1024, 128, 1024)
660
661     @unittest.skipUnless(running_extended_tests, "part of extended tests")
662     def test_bier_e2e_512(self):
663         """ BIER end-to-end BSL:512"""
664         self.bier_e2e(BIERLength.BIER_LEN_512, 64, 512)
665
666     @unittest.skipUnless(running_extended_tests, "part of extended tests")
667     def test_bier_e2e_256(self):
668         """ BIER end-to-end BSL:256"""
669         self.bier_e2e(BIERLength.BIER_LEN_256, 32, 256)
670
671     @unittest.skipUnless(running_extended_tests, "part of extended tests")
672     def test_bier_e2e_128(self):
673         """ BIER end-to-end BSL:128"""
674         self.bier_e2e(BIERLength.BIER_LEN_128, 16, 128)
675
676     def test_bier_e2e_64(self):
677         """ BIER end-to-end BSL:64"""
678         self.bier_e2e(BIERLength.BIER_LEN_64, 8, 64)
679
680     def test_bier_head_o_udp(self):
681         """BIER head over UDP"""
682
683         #
684         # Add a BIER table for sub-domain 1, set 0, and BSL 256
685         #
686         bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
687         bt = VppBierTable(self, bti, 77)
688         bt.add_vpp_config()
689
690         #
691         # 1 bit positions via 1 next hops
692         #
693         nh1 = "10.0.0.1"
694         ip_route = VppIpRoute(self, nh1, 32,
695                               [VppRoutePath(self.pg1.remote_ip4,
696                                             self.pg1.sw_if_index,
697                                             labels=[VppMplsLabel(2001)])])
698         ip_route.add_vpp_config()
699
700         udp_encap = VppUdpEncap(self,
701                                 self.pg0.local_ip4,
702                                 nh1,
703                                 330, 8138)
704         udp_encap.add_vpp_config()
705
706         bier_route = VppBierRoute(
707             self, bti, 1,
708             [VppRoutePath("0.0.0.0",
709                           0xFFFFFFFF,
710                           is_udp_encap=1,
711                           next_hop_id=udp_encap.id)])
712         bier_route.add_vpp_config()
713
714         #
715         # An 2 imposition objects with all bit-positions set
716         # only use the second, but creating 2 tests with a non-zero
717         # value index in the route add
718         #
719         bi = VppBierImp(self, bti, 333, chr(0xff) * 32)
720         bi.add_vpp_config()
721         bi2 = VppBierImp(self, bti, 334, chr(0xff) * 32)
722         bi2.add_vpp_config()
723
724         #
725         # Add a multicast route that will forward into the BIER doamin
726         #
727         route_ing_232_1_1_1 = VppIpMRoute(
728             self,
729             "0.0.0.0",
730             "232.1.1.1", 32,
731             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
732             paths=[VppMRoutePath(self.pg0.sw_if_index,
733                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
734                    VppMRoutePath(0xffffffff,
735                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
736                                  proto=DpoProto.DPO_PROTO_BIER,
737                                  bier_imp=bi2.bi_index)])
738         route_ing_232_1_1_1.add_vpp_config()
739
740         #
741         # inject a packet an IP. We expect it to be BIER and UDP encapped,
742         #
743         p = (Ether(dst=self.pg0.local_mac,
744                    src=self.pg0.remote_mac) /
745              IP(src="1.1.1.1", dst="232.1.1.1") /
746              UDP(sport=1234, dport=1234))
747
748         self.pg0.add_stream([p])
749         self.pg_enable_capture(self.pg_interfaces)
750         self.pg_start()
751
752         rx = self.pg1.get_capture(1)
753
754         #
755         # Encap Stack is, eth, IP, UDP, BIFT, BIER
756         #
757         self.assertEqual(rx[0][IP].src, self.pg0.local_ip4)
758         self.assertEqual(rx[0][IP].dst, nh1)
759         self.assertEqual(rx[0][UDP].sport, 330)
760         self.assertEqual(rx[0][UDP].dport, 8138)
761         self.assertEqual(rx[0][BIFT].bsl, BIERLength.BIER_LEN_256)
762         self.assertEqual(rx[0][BIFT].sd, 1)
763         self.assertEqual(rx[0][BIFT].set, 0)
764         self.assertEqual(rx[0][BIFT].ttl, 64)
765         self.assertEqual(rx[0][BIER].length, 2)
766
767     def test_bier_tail_o_udp(self):
768         """BIER Tail over UDP"""
769
770         #
771         # Add a BIER table for sub-domain 0, set 0, and BSL 256
772         #
773         bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
774         bt = VppBierTable(self, bti, MPLS_LABEL_INVALID)
775         bt.add_vpp_config()
776
777         #
778         # disposition table
779         #
780         bdt = VppBierDispTable(self, 8)
781         bdt.add_vpp_config()
782
783         #
784         # BIER route in table that's for-us
785         #
786         bier_route_1 = VppBierRoute(
787             self, bti, 1,
788             [VppRoutePath("0.0.0.0",
789                           0xffffffff,
790                           proto=DpoProto.DPO_PROTO_BIER,
791                           nh_table_id=8)])
792         bier_route_1.add_vpp_config()
793
794         #
795         # An entry in the disposition table
796         #
797         bier_de_1 = VppBierDispEntry(self, bdt.id, 99,
798                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
799                                      DpoProto.DPO_PROTO_BIER,
800                                      "0.0.0.0", 0, rpf_id=8192)
801         bier_de_1.add_vpp_config()
802
803         #
804         # A multicast route to forward post BIER disposition
805         #
806         route_eg_232_1_1_1 = VppIpMRoute(
807             self,
808             "0.0.0.0",
809             "232.1.1.1", 32,
810             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
811             paths=[VppMRoutePath(self.pg1.sw_if_index,
812                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
813         route_eg_232_1_1_1.add_vpp_config()
814         route_eg_232_1_1_1.update_rpf_id(8192)
815
816         #
817         # A packet with all bits set gets spat out to BP:1
818         #
819         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
820              IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
821              UDP(sport=333, dport=8138) /
822              BIFT(sd=1, set=0, bsl=2, ttl=255) /
823              BIER(length=BIERLength.BIER_LEN_256,
824                   BitString=chr(255)*32,
825                   BFRID=99) /
826              IP(src="1.1.1.1", dst="232.1.1.1") /
827              UDP(sport=1234, dport=1234) /
828              Raw())
829
830         rx = self.send_and_expect(self.pg0, [p], self.pg1)
831
832
833 if __name__ == '__main__':
834     unittest.main(testRunner=VppTestRunner)