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