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