test_bier.py revision ead1e536
1#!/usr/bin/env python3
2
3import unittest
4
5from framework import VppTestCase, VppTestRunner, running_extended_tests
6from vpp_ip import DpoProto
7from vpp_ip_route import VppIpRoute, VppRoutePath, \
8    VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \
9    MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, \
10    VppMplsLabel, FibPathProto, FibPathType
11from vpp_bier import BIER_HDR_PAYLOAD, VppBierImp, VppBierDispEntry, \
12    VppBierDispTable, VppBierTable, VppBierTableID, VppBierRoute
13from vpp_udp_encap import VppUdpEncap
14
15import scapy.compat
16from scapy.packet import Raw
17from scapy.layers.l2 import Ether
18from scapy.layers.inet import IP, UDP
19from scapy.layers.inet6 import IPv6
20from scapy.contrib.mpls import MPLS
21from scapy.contrib.bier import BIER, BIERLength, BIFT
22
23NUM_PKTS = 67
24
25
26class 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
38class 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 = b''.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
845if __name__ == '__main__':
846    unittest.main(testRunner=VppTestRunner)
847