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