summaryrefslogtreecommitdiffstats
path: root/src/vlib/physmem_funcs.h
blob: 3e9208b4e95ba52d595e557ce0ff6e8bcee00241 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 * Copyright (c) 2015 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * physmem.h: virtual <-> physical memory mapping for VLIB buffers
 *
 * Copyright (c) 2008 Eliot Dresselhaus
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef included_vlib_physmem_funcs_h
#define included_vlib_physmem_funcs_h

#include <vppinfra/clib.h>
#include <vppinfra/clib_error.h>
#include <vlib/physmem.h>
#include <vlib/main.h>

clib_error_t *vlib_physmem_init (vlib_main_t * vm);
clib_error_t *vlib_physmem_shared_map_create (vlib_main_t * vm, char *name,
					      uword size, u32 log2_page_sz,
					      u32 numa_node, u32 * map_index);

vlib_physmem_map_t *vlib_physmem_get_map (vlib_main_t * vm, u32 index);

always_inline void *
vlib_physmem_alloc_aligned (vlib_main_t * vm, uword n_bytes, uword alignment)
{
  clib_pmalloc_main_t *pm = vm->physmem_main.pmalloc_main;
  return clib_pmalloc_alloc_aligned (pm, n_bytes, alignment);
}

always_inline void *
vlib_physmem_alloc_aligned_on_numa (vlib_main_t * vm, uword n_bytes,
				    uword alignment, u32 numa_node)
{
  clib_pmalloc_main_t *pm = vm->physmem_main.pmalloc_main;
  return clib_pmalloc_alloc_aligned_on_numa (pm, n_bytes, alignment,
					     numa_node);
}

/* By default allocate I/O memory with cache line alignment. */
always_inline void *
vlib_physmem_alloc (vlib_main_t * vm, uword n_bytes)
{
  return vlib_physmem_alloc_aligned (vm, n_bytes, CLIB_CACHE_LINE_BYTES);
}

always_inline void *
vlib_physmem_alloc_from_map (vlib_main_t * vm, u32 physmem_map_index,
			     uword n_bytes, uword alignment)
{
  clib_pmalloc_main_t *pm = vm->physmem_main.pmalloc_main;
  vlib_physmem_map_t *map = vlib_physmem_get_map (vm, physmem_map_index);
  return clib_pmalloc_alloc_from_arena (pm, map->base, n_bytes,
					CLIB_CACHE_LINE_BYTES);
}

always_inline void
vlib_physmem_free (vlib_main_t * vm, void *p)
{
  if (p)
    clib_pmalloc_free (vm->physmem_main.pmalloc_main, p);
}

always_inline u64
vlib_physmem_get_page_index (vlib_main_t * vm, void *mem)
{
  clib_pmalloc_main_t *pm = vm->physmem_main.pmalloc_main;
  return clib_pmalloc_get_page_index (pm, mem);
}

always_inline u64
vlib_physmem_get_pa (vlib_main_t * vm, void *mem)
{
  clib_pmalloc_main_t *pm = vm->physmem_main.pmalloc_main;
  return clib_pmalloc_get_pa (pm, mem);
}

always_inline clib_error_t *
vlib_physmem_last_error (struct vlib_main_t * vm)
{
  clib_pmalloc_main_t *pm = vm->physmem_main.pmalloc_main;
  return pm->error;
}

#endif /* included_vlib_physmem_funcs_h */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */
ighlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
#!/usr/bin/env python

import unittest
import socket

from framework import VppTestCase, VppTestRunner, running_extended_tests
from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
    VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \
    MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, DpoProto, \
    VppMplsLabel
from vpp_bier import *
from vpp_udp_encap import *

from scapy.packet import Raw
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, UDP, ICMP
from scapy.layers.inet6 import IPv6
from scapy.contrib.mpls import MPLS
from scapy.contrib.bier import *


class TestBFIB(VppTestCase):
    """ BIER FIB Test Case """

    def test_bfib(self):
        """ BFIB Unit Tests """
        error = self.vapi.cli("test bier")

        if error:
            self.logger.critical(error)
        self.assertEqual(error.find("Failed"), -1)


class TestBier(VppTestCase):
    """ BIER Test Case """

    def setUp(self):
        super(TestBier, self).setUp()

        # create 2 pg interfaces
        self.create_pg_interfaces(range(3))

        # create the default MPLS table
        self.tables = []
        tbl = VppMplsTable(self, 0)
        tbl.add_vpp_config()
        self.tables.append(tbl)

        tbl = VppIpTable(self, 10)
        tbl.add_vpp_config()
        self.tables.append(tbl)

        # setup both interfaces
        for i in self.pg_interfaces:
            if i == self.pg2:
                i.set_table_ip4(10)
            i.admin_up()
            i.config_ip4()
            i.resolve_arp()
            i.enable_mpls()

    def tearDown(self):
        for i in self.pg_interfaces:
            i.disable_mpls()
            i.unconfig_ip4()
            i.set_table_ip4(0)
            i.admin_down()
        super(TestBier, self).tearDown()

    def bier_midpoint(self, hdr_len_id, n_bytes, max_bp):
        """BIER midpoint"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(0, 0, hdr_len_id)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        #
        # A packet with no bits set gets dropped
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             MPLS(label=77, ttl=255) /
             BIER(length=hdr_len_id) /
             IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
             UDP(sport=1234, dport=1234) /
             Raw())
        pkts = [p]

        self.send_and_assert_no_replies(self.pg0, pkts,
                                        "Empty Bit-String")

        #
        # Add a BIER route for each bit-position in the table via a different
        # next-hop. Testing whether the BIER walk and replicate forwarding
        # function works for all bit posisitons.
        #
        nh_routes = []
        bier_routes = []
        for i in range(1, max_bp+1):
            nh = "10.0.%d.%d" % (i / 255, i % 255)
            nh_routes.append(
                VppIpRoute(self, nh, 32,
                           [VppRoutePath(self.pg1.remote_ip4,
                                         self.pg1.sw_if_index,
                                         labels=[VppMplsLabel(2000+i)])]))
            nh_routes[-1].add_vpp_config()

            bier_routes.append(
                VppBierRoute(self, bti, i,
                             [VppRoutePath(nh, 0xffffffff,
                                           labels=[VppMplsLabel(100+i)])]))
            bier_routes[-1].add_vpp_config()

        #
        # A packet with all bits set gets replicated once for each bit
        #
        pkt_sizes = [64, 1400]

        for pkt_size in pkt_sizes:
            p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                 MPLS(label=77, ttl=255) /
                 BIER(length=hdr_len_id, BitString=chr(255)*n_bytes) /
                 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
                 UDP(sport=1234, dport=1234) /
                 Raw(chr(5) * pkt_size))
            pkts = p

            self.pg0.add_stream(pkts)
            self.pg_enable_capture(self.pg_interfaces)
            self.pg_start()

            rx = self.pg1.get_capture(max_bp)

            for rxp in rx:
                #
                # The packets are not required to be sent in bit-position order
                # when we setup the routes above we used the bit-position to
                # construct the out-label. so use that here to determine the BP
                #
                olabel = rxp[MPLS]
                bp = olabel.label - 2000

                blabel = olabel[MPLS].payload
                self.assertEqual(blabel.label, 100+bp)
                self.assertEqual(blabel.ttl, 254)

                bier_hdr = blabel[MPLS].payload

                self.assertEqual(bier_hdr.id, 5)
                self.assertEqual(bier_hdr.version, 0)
                self.assertEqual(bier_hdr.length, hdr_len_id)
                self.assertEqual(bier_hdr.entropy, 0)
                self.assertEqual(bier_hdr.OAM, 0)
                self.assertEqual(bier_hdr.RSV, 0)
                self.assertEqual(bier_hdr.DSCP, 0)
                self.assertEqual(bier_hdr.Proto, 5)

                # The bit-string should consist only of the BP given by i.
                byte_array = ['\0'] * (n_bytes)
                byte_val = chr(1 << (bp - 1) % 8)
                byte_pos = n_bytes - (((bp - 1) / 8) + 1)
                byte_array[byte_pos] = byte_val
                bitstring = ''.join(byte_array)

                self.assertEqual(len(bitstring), len(bier_hdr.BitString))
                self.assertEqual(bitstring, bier_hdr.BitString)

        #
        # cleanup. not strictly necessary, but it's much quicker this way
        # becuase the bier_fib_dump and ip_fib_dump will be empty when the
        # auto-cleanup kicks in
        #
        for br in bier_routes:
            br.remove_vpp_config()
        for nhr in nh_routes:
            nhr.remove_vpp_config()

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_midpoint_1024(self):
        """BIER midpoint BSL:1024"""
        self.bier_midpoint(BIERLength.BIER_LEN_1024, 128, 1024)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_midpoint_512(self):
        """BIER midpoint BSL:512"""
        self.bier_midpoint(BIERLength.BIER_LEN_512, 64, 512)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_midpoint_256(self):
        """BIER midpoint BSL:256"""
        self.bier_midpoint(BIERLength.BIER_LEN_256, 32, 256)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_midpoint_128(self):
        """BIER midpoint BSL:128"""
        self.bier_midpoint(BIERLength.BIER_LEN_128, 16, 128)

    def test_bier_midpoint_64(self):
        """BIER midpoint BSL:64"""
        self.bier_midpoint(BIERLength.BIER_LEN_64, 8, 64)

    def test_bier_head(self):
        """BIER head"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        #
        # 2 bit positions via two next hops
        #
        nh1 = "10.0.0.1"
        nh2 = "10.0.0.2"
        ip_route_1 = VppIpRoute(self, nh1, 32,
                                [VppRoutePath(self.pg1.remote_ip4,
                                              self.pg1.sw_if_index,
                                              labels=[VppMplsLabel(2001)])])
        ip_route_2 = VppIpRoute(self, nh2, 32,
                                [VppRoutePath(self.pg1.remote_ip4,
                                              self.pg1.sw_if_index,
                                              labels=[VppMplsLabel(2002)])])
        ip_route_1.add_vpp_config()
        ip_route_2.add_vpp_config()

        bier_route_1 = VppBierRoute(self, bti, 1,
                                    [VppRoutePath(nh1, 0xffffffff,
                                                  labels=[VppMplsLabel(101)])])
        bier_route_2 = VppBierRoute(self, bti, 2,
                                    [VppRoutePath(nh2, 0xffffffff,
                                                  labels=[VppMplsLabel(102)])])
        bier_route_1.add_vpp_config()
        bier_route_2.add_vpp_config()

        #
        # An imposition object with both bit-positions set
        #
        bi = VppBierImp(self, bti, 333, chr(0x3) * 32)
        bi.add_vpp_config()

        #
        # Add a multicast route that will forward into the BIER doamin
        #
        route_ing_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1", 32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[VppMRoutePath(self.pg0.sw_if_index,
                                 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
                   VppMRoutePath(0xffffffff,
                                 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
                                 proto=DpoProto.DPO_PROTO_BIER,
                                 bier_imp=bi.bi_index)])
        route_ing_232_1_1_1.add_vpp_config()

        #
        # inject an IP packet. We expect it to be BIER encapped and
        # replicated.
        #
        p = (Ether(dst=self.pg0.local_mac,
                   src=self.pg0.remote_mac) /
             IP(src="1.1.1.1", dst="232.1.1.1") /
             UDP(sport=1234, dport=1234))

        self.pg0.add_stream([p])
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(2)

        #
        # Encap Stack is; eth, MPLS, MPLS, BIER
        #
        igp_mpls = rx[0][MPLS]
        self.assertEqual(igp_mpls.label, 2001)
        self.assertEqual(igp_mpls.ttl, 64)
        self.assertEqual(igp_mpls.s, 0)
        bier_mpls = igp_mpls[MPLS].payload
        self.assertEqual(bier_mpls.label, 101)
        self.assertEqual(bier_mpls.ttl, 64)
        self.assertEqual(bier_mpls.s, 1)
        self.assertEqual(rx[0][BIER].length, 2)

        igp_mpls = rx[1][MPLS]
        self.assertEqual(igp_mpls.label, 2002)
        self.assertEqual(igp_mpls.ttl, 64)
        self.assertEqual(igp_mpls.s, 0)
        bier_mpls = igp_mpls[MPLS].payload
        self.assertEqual(bier_mpls.label, 102)
        self.assertEqual(bier_mpls.ttl, 64)
        self.assertEqual(bier_mpls.s, 1)
        self.assertEqual(rx[0][BIER].length, 2)

    def test_bier_tail(self):
        """BIER Tail"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        #
        # disposition table
        #
        bdt = VppBierDispTable(self, 8)
        bdt.add_vpp_config()

        #
        # BIER route in table that's for-us
        #
        bier_route_1 = VppBierRoute(self, bti, 1,
                                    [VppRoutePath("0.0.0.0",
                                                  0xffffffff,
                                                  nh_table_id=8)])
        bier_route_1.add_vpp_config()

        #
        # An entry in the disposition table
        #
        bier_de_1 = VppBierDispEntry(self, bdt.id, 99,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0", 0, rpf_id=8192)
        bier_de_1.add_vpp_config()

        #
        # A multicast route to forward post BIER disposition
        #
        route_eg_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1", 32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[VppMRoutePath(self.pg1.sw_if_index,
                                 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
        route_eg_232_1_1_1.add_vpp_config()
        route_eg_232_1_1_1.update_rpf_id(8192)

        #
        # A packet with all bits set gets spat out to BP:1
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             MPLS(label=77, ttl=255) /
             BIER(length=BIERLength.BIER_LEN_256,
                  BitString=chr(255)*32,
                  BFRID=99) /
             IP(src="1.1.1.1", dst="232.1.1.1") /
             UDP(sport=1234, dport=1234) /
             Raw())

        self.send_and_expect(self.pg0, [p], self.pg1)

        #
        # A packet that does not match the Disposition entry gets dropped
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             MPLS(label=77, ttl=255) /
             BIER(length=BIERLength.BIER_LEN_256,
                  BitString=chr(255)*32,
                  BFRID=77) /
             IP(src="1.1.1.1", dst="232.1.1.1") /
             UDP(sport=1234, dport=1234) /
             Raw())
        self.send_and_assert_no_replies(self.pg0, p*2,
                                        "no matching disposition entry")

        #
        # Add the default route to the disposition table
        #
        bier_de_2 = VppBierDispEntry(self, bdt.id, 0,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0", 0, rpf_id=8192)
        bier_de_2.add_vpp_config()

        #
        # now the previous packet is forwarded
        #
        self.send_and_expect(self.pg0, [p], self.pg1)

    def bier_e2e(self, hdr_len_id, n_bytes, max_bp):
        """ BIER end-to-end"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(0, 0, hdr_len_id)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        lowest = ['\0'] * (n_bytes)
        lowest[-1] = chr(1)
        highest = ['\0'] * (n_bytes)
        highest[0] = chr(128)

        #
        # Impostion Sets bit strings
        #
        bi_low = VppBierImp(self, bti, 333, lowest)
        bi_low.add_vpp_config()
        bi_high = VppBierImp(self, bti, 334, highest)
        bi_high.add_vpp_config()

        #
        # Add a multicast route that will forward into the BIER doamin
        #
        route_ing_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1", 32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[VppMRoutePath(self.pg0.sw_if_index,
                                 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
                   VppMRoutePath(0xffffffff,
                                 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
                                 proto=DpoProto.DPO_PROTO_BIER,
                                 bier_imp=bi_low.bi_index)])
        route_ing_232_1_1_1.add_vpp_config()
        route_ing_232_1_1_2 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.2", 32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[VppMRoutePath(self.pg0.sw_if_index,
                                 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
                   VppMRoutePath(0xffffffff,
                                 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
                                 proto=DpoProto.DPO_PROTO_BIER,
                                 bier_imp=bi_high.bi_index)])
        route_ing_232_1_1_2.add_vpp_config()

        #
        # disposition table 8
        #
        bdt = VppBierDispTable(self, 8)
        bdt.add_vpp_config()

        #
        # BIER routes in table that are for-us, resolving through
        # disp table 8.
        #
        bier_route_1 = VppBierRoute(self, bti, 1,
                                    [VppRoutePath("0.0.0.0",
                                                  0xffffffff,
                                                  nh_table_id=8)])
        bier_route_1.add_vpp_config()
        bier_route_max = VppBierRoute(self, bti, max_bp,
                                      [VppRoutePath("0.0.0.0",
                                                    0xffffffff,
                                                    nh_table_id=8)])
        bier_route_max.add_vpp_config()

        #
        # An entry in the disposition table for sender 333
        #  lookup in VRF 10
        #
        bier_de_1 = VppBierDispEntry(self, bdt.id, 333,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0", 10, rpf_id=8192)
        bier_de_1.add_vpp_config()
        bier_de_1 = VppBierDispEntry(self, bdt.id, 334,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0", 10, rpf_id=8193)
        bier_de_1.add_vpp_config()

        #
        # Add a multicast routes that will forward the traffic
        # post-disposition
        #
        route_eg_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1", 32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            table_id=10,
            paths=[VppMRoutePath(self.pg1.sw_if_index,
                                 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
        route_eg_232_1_1_1.add_vpp_config()
        route_eg_232_1_1_1.update_rpf_id(8192)
        route_eg_232_1_1_2 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.2", 32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            table_id=10,
            paths=[VppMRoutePath(self.pg1.sw_if_index,
                                 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
        route_eg_232_1_1_2.add_vpp_config()
        route_eg_232_1_1_2.update_rpf_id(8193)

        #
        # inject a packet in VRF-0. We expect it to be BIER encapped,
        # replicated, then hit the disposition and be forwarded
        # out of VRF 10, i.e. on pg1
        #
        p = (Ether(dst=self.pg0.local_mac,
                   src=self.pg0.remote_mac) /
             IP(src="1.1.1.1", dst="232.1.1.1") /
             UDP(sport=1234, dport=1234) /
             Raw(chr(5) * 32))

        rx = self.send_and_expect(self.pg0, p*65, self.pg1)

        self.assertEqual(rx[0][IP].src, "1.1.1.1")
        self.assertEqual(rx[0][IP].dst, "232.1.1.1")

        p = (Ether(dst=self.pg0.local_mac,
                   src=self.pg0.remote_mac) /
             IP(src="1.1.1.1", dst="232.1.1.2") /
             UDP(sport=1234, dport=1234) /
             Raw(chr(5) * 512))

        rx = self.send_and_expect(self.pg0, p*65, self.pg1)
        self.assertEqual(rx[0][IP].src, "1.1.1.1")
        self.assertEqual(rx[0][IP].dst, "232.1.1.2")

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_e2e_1024(self):
        """ BIER end-to-end BSL:1024"""
        self.bier_e2e(BIERLength.BIER_LEN_1024, 128, 1024)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_e2e_512(self):
        """ BIER end-to-end BSL:512"""
        self.bier_e2e(BIERLength.BIER_LEN_512, 64, 512)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_e2e_256(self):
        """ BIER end-to-end BSL:256"""
        self.bier_e2e(BIERLength.BIER_LEN_256, 32, 256)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_e2e_128(self):
        """ BIER end-to-end BSL:128"""
        self.bier_e2e(BIERLength.BIER_LEN_128, 16, 128)

    def test_bier_e2e_64(self):
        """ BIER end-to-end BSL:64"""
        self.bier_e2e(BIERLength.BIER_LEN_64, 8, 64)

    def test_bier_head_o_udp(self):
        """BIER head over UDP"""

        #
        # Add a BIER table for sub-domain 1, set 0, and BSL 256
        #
        bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        #
        # 1 bit positions via 1 next hops
        #
        nh1 = "10.0.0.1"
        ip_route = VppIpRoute(self, nh1, 32,
                              [VppRoutePath(self.pg1.remote_ip4,
                                            self.pg1.sw_if_index,
                                            labels=[VppMplsLabel(2001)])])
        ip_route.add_vpp_config()

        udp_encap = VppUdpEncap(self, 4,
                                self.pg0.local_ip4,
                                nh1,
                                330, 8138)
        udp_encap.add_vpp_config()

        bier_route = VppBierRoute(self, bti, 1,
                                  [VppRoutePath("0.0.0.0",
                                                0xFFFFFFFF,
                                                is_udp_encap=1,
                                                next_hop_id=4)])
        bier_route.add_vpp_config()

        #
        # An 2 imposition objects with all bit-positions set
        # only use the second, but creating 2 tests with a non-zero
        # value index in the route add
        #
        bi = VppBierImp(self, bti, 333, chr(0xff) * 32)
        bi.add_vpp_config()
        bi2 = VppBierImp(self, bti, 334, chr(0xff) * 32)
        bi2.add_vpp_config()

        #
        # Add a multicast route that will forward into the BIER doamin
        #
        route_ing_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1", 32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[VppMRoutePath(self.pg0.sw_if_index,
                                 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
                   VppMRoutePath(0xffffffff,
                                 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
                                 proto=DpoProto.DPO_PROTO_BIER,
                                 bier_imp=bi2.bi_index)])
        route_ing_232_1_1_1.add_vpp_config()

        #
        # inject a packet an IP. We expect it to be BIER and UDP encapped,
        #
        p = (Ether(dst=self.pg0.local_mac,
                   src=self.pg0.remote_mac) /
             IP(src="1.1.1.1", dst="232.1.1.1") /
             UDP(sport=1234, dport=1234))

        self.pg0.add_stream([p])
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(1)

        #
        # Encap Stack is, eth, IP, UDP, BIFT, BIER
        #
        self.assertEqual(rx[0][IP].src, self.pg0.local_ip4)
        self.assertEqual(rx[0][IP].dst, nh1)
        self.assertEqual(rx[0][UDP].sport, 330)
        self.assertEqual(rx[0][UDP].dport, 8138)
        self.assertEqual(rx[0][BIFT].bsl, 2)
        self.assertEqual(rx[0][BIFT].sd, 1)
        self.assertEqual(rx[0][BIFT].set, 0)
        self.assertEqual(rx[0][BIFT].ttl, 64)
        self.assertEqual(rx[0][BIER].length, 2)

    def test_bier_tail_o_udp(self):
        """BIER Tail over UDP"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
        bt = VppBierTable(self, bti, MPLS_LABEL_INVALID)
        bt.add_vpp_config()

        #
        # disposition table
        #
        bdt = VppBierDispTable(self, 8)
        bdt.add_vpp_config()

        #
        # BIER route in table that's for-us
        #
        bier_route_1 = VppBierRoute(self, bti, 1,
                                    [VppRoutePath("0.0.0.0",
                                                  0xffffffff,
                                                  nh_table_id=8)])
        bier_route_1.add_vpp_config()

        #
        # An entry in the disposition table
        #
        bier_de_1 = VppBierDispEntry(self, bdt.id, 99,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0", 0, rpf_id=8192)
        bier_de_1.add_vpp_config()

        #
        # A multicast route to forward post BIER disposition
        #
        route_eg_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1", 32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[VppMRoutePath(self.pg1.sw_if_index,
                                 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
        route_eg_232_1_1_1.add_vpp_config()
        route_eg_232_1_1_1.update_rpf_id(8192)

        #
        # A packet with all bits set gets spat out to BP:1
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
             UDP(sport=333, dport=8138) /
             BIFT(sd=1, set=0, bsl=2, ttl=255) /
             BIER(length=BIERLength.BIER_LEN_256,
                  BitString=chr(255)*32,
                  BFRID=99) /
             IP(src="1.1.1.1", dst="232.1.1.1") /
             UDP(sport=1234, dport=1234) /
             Raw())

        rx = self.send_and_expect(self.pg0, [p], self.pg1)


if __name__ == '__main__':
    unittest.main(testRunner=VppTestRunner)