BIER in non-MPLS netowrks 36/9736/7
authorNeale Ranns <nranns@cisco.com>
Tue, 5 Dec 2017 21:24:04 +0000 (13:24 -0800)
committerFlorin Coras <florin.coras@gmail.com>
Sat, 9 Dec 2017 20:55:08 +0000 (20:55 +0000)
as decsribed in section 2.2
  ihttps://tools.ietf.org/html/draft-ietf-bier-mpls-encapsulation-10
with BIFT encoding from:
  https://tools.ietf.org/html/draft-wijnandsxu-bier-non-mpls-bift-encoding-00

changes:
1 - introduce the new BIFT lookup table. BIER tables that have an associated
    MPLS label are added to the MPLS-FIB. Those that don't are added to the
    BIER table
2 - BIER routes that have no associated output MPLS label will add a BIFT label.
3 - The BIER FMask has a path-list as a member to resolve via any possible path.

Change-Id: I1fd4d9dbd074f0e855c16e9329b81460ebe1efce
Signed-off-by: Neale Ranns <nranns@cisco.com>
39 files changed:
src/vnet.am
src/vnet/bier/bier.api
src/vnet/bier/bier_api.c
src/vnet/bier/bier_bift_table.c [new file with mode: 0644]
src/vnet/bier/bier_bift_table.h [new file with mode: 0644]
src/vnet/bier/bier_disp_dispatch_node.c
src/vnet/bier/bier_disp_entry.c
src/vnet/bier/bier_disp_table.c
src/vnet/bier/bier_entry.c
src/vnet/bier/bier_fmask.c
src/vnet/bier/bier_fmask.h
src/vnet/bier/bier_fmask_db.c
src/vnet/bier/bier_fmask_db.h
src/vnet/bier/bier_imp_node.c
src/vnet/bier/bier_input.c
src/vnet/bier/bier_lookup.c
src/vnet/bier/bier_output.c
src/vnet/bier/bier_table.c
src/vnet/bier/bier_test.c
src/vnet/bier/bier_types.c
src/vnet/bier/bier_types.h
src/vnet/bier/bier_update.c
src/vnet/buffer.h
src/vnet/dpo/load_balance.c
src/vnet/dpo/load_balance.h
src/vnet/fib/fib_entry_src.c
src/vnet/fib/fib_path.c
src/vnet/fib/fib_path.h
src/vnet/fib/fib_path_list.c
src/vnet/fib/fib_path_list.h
src/vnet/fib/fib_types.h
src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
src/vnet/mpls/mpls_output.c
src/vnet/udp/udp.h
src/vnet/udp/udp_encap.c
test/patches/scapy-2.3.3/bier.patch
test/test_bier.py
test/vpp_bier.py
test/vpp_papi_provider.py

index bd7efb2..ae125bc 100644 (file)
@@ -1175,7 +1175,8 @@ libvnet_la_SOURCES +=                           \
   vnet/bier/bier_disp_entry.c                  \
   vnet/bier/bier_disp_lookup_node.c            \
   vnet/bier/bier_disp_dispatch_node.c          \
-  vnet/bier/bier_disp_table.c
+  vnet/bier/bier_disp_table.c                  \
+  vnet/bier/bier_bift_table.c
 
 nobase_include_HEADERS +=                      \
   vnet/bier/bier_types.h                        \
index 466524c..e4edfa1 100644 (file)
@@ -36,7 +36,9 @@ typeonly define bier_table_id
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
     @param bt_tbl_id - The BIER table-id the route is added in
-    @param bt_mpls_label - The MPLS label for the table
+    @param bt_label - The MPLS label for the table (0 or all ones means not set)
+                      If the label is not set, then it is assumed that non-MPLS
+                     encoding is used.
     @param bt_is_add - Is this a route add or delete
 */
 autoreply define bier_table_add_del
@@ -67,10 +69,11 @@ define bier_table_details
     @param preference - The preference of the path. lowest preference is prefered
     @param is_local - local if non-zero, else remote
     @param is_drop - Drop the packet
-    @param is_unreach - Drop the packet and rate limit send ICMP unreachable
-    @param is_prohibit - Drop the packet and rate limit send ICMP prohibited
+    @param is_udp_encap - The path describes a UDP-o-IP encapsulation.
     @param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2
     @param next_hop[16] - the next hop address
+    @param next_hop_id - Used when the path resolves via an object that has a unique
+                         identifier. e.g. the UDP encap object
 
     WARNING: this type is replicated, pending cleanup completion
 */
@@ -82,10 +85,10 @@ typeonly define fib_path3
   u8 preference;
   u8 is_local;
   u8 is_drop;
-  u8 is_unreach;
-  u8 is_prohibit;
+  u8 is_udp_encap;
   u8 afi;
   u8 next_hop[16];
+  u32 next_hop_id;
   u32 rpf_id;
   u8 n_labels;
   u32 label_stack[16];
index cd1f40b..67c7046 100644 (file)
@@ -83,7 +83,17 @@ vl_api_bier_table_add_del_t_handler (vl_api_bier_table_add_del_t * mp)
 
     if (mp->bt_is_add)
     {
-        bier_table_add_or_lock(&bti, ntohl(mp->bt_label));
+        mpls_label_t label = ntohl(mp->bt_label);
+
+        /*
+         * convert acceptable 'don't want a label' values from 
+         * the API to the correct internal INVLID value
+         */
+        if ((0 == label) || (~0 == label))
+        {
+            label = MPLS_LABEL_INVALID;
+        }
+        bier_table_add_or_lock(&bti, label);
     }
     else
     {
@@ -175,7 +185,7 @@ vl_api_bier_route_add_del_t_handler (vl_api_bier_route_add_del_t * mp)
     {
         brpath = &brpaths[ii];
         memset(brpath, 0, sizeof(*brpath));
-        brpath->frp_flags = FIB_ROUTE_PATH_BIER_FMASK;
+        brpath->frp_sw_if_index = ~0;
 
         vec_validate(brpath->frp_label_stack,
                      mp->br_paths[ii].n_labels - 1);
@@ -185,30 +195,41 @@ vl_api_bier_route_add_del_t_handler (vl_api_bier_route_add_del_t * mp)
                 ntohl(mp->br_paths[ii].label_stack[jj]);
         }
 
-        if (0 == mp->br_paths[ii].afi)
+        if (mp->br_paths[ii].is_udp_encap)
         {
-            clib_memcpy (&brpath->frp_addr.ip4,
-                         mp->br_paths[ii].next_hop,
-                         sizeof (brpath->frp_addr.ip4));
+            brpath->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
+            brpath->frp_udp_encap_id = ntohl(mp->br_paths[ii].next_hop_id);
         }
         else
         {
-            clib_memcpy (&brpath->frp_addr.ip6,
-                         mp->br_paths[ii].next_hop,
-                         sizeof (brpath->frp_addr.ip6));
-        }
-        if (ip46_address_is_zero(&brpath->frp_addr))
-        {
-            index_t bdti;
-
-            bdti = bier_disp_table_find(ntohl(mp->br_paths[ii].table_id));
-
-            if (INDEX_INVALID != bdti)
-                brpath->frp_fib_index = bdti;
+            if (0 == mp->br_paths[ii].afi)
+            {
+                clib_memcpy (&brpath->frp_addr.ip4,
+                             mp->br_paths[ii].next_hop,
+                             sizeof (brpath->frp_addr.ip4));
+            }
             else
             {
-                rv = VNET_API_ERROR_NO_SUCH_FIB;
-                goto done;
+                clib_memcpy (&brpath->frp_addr.ip6,
+                             mp->br_paths[ii].next_hop,
+                             sizeof (brpath->frp_addr.ip6));
+            }
+            if (ip46_address_is_zero(&brpath->frp_addr))
+            {
+                index_t bdti;
+
+                bdti = bier_disp_table_find(ntohl(mp->br_paths[ii].table_id));
+
+                if (INDEX_INVALID != bdti)
+                {
+                    brpath->frp_fib_index = bdti;
+                    brpath->frp_proto = DPO_PROTO_BIER;
+                }
+                else
+                {
+                    rv = VNET_API_ERROR_NO_SUCH_FIB;
+                    goto done;
+                }
             }
         }
     }
diff --git a/src/vnet/bier/bier_bift_table.c b/src/vnet/bier/bier_bift_table.c
new file mode 100644 (file)
index 0000000..e0f6c64
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#include <vnet/bier/bier_bift_table.h>
+#include <vnet/dpo/drop_dpo.h>
+#include <vnet/udp/udp.h>
+
+typedef enum {
+#define bier_error(n,s) BIER_INPUT_ERROR_##n,
+#include <vnet/bier/bier_input_error.def>
+#undef bier_error
+    BIER_INPUT_N_ERROR,
+} bier_input_error_t;
+
+static char * bier_error_strings[] = {
+#define bier_error(n,s) s,
+#include <vnet/bier/bier_input_error.def>
+#undef bier_error
+};
+
+/**
+ * Global BIFT table
+ */
+bier_bfit_table_t *bier_bift_table;
+
+/**
+ * Forward declare the node
+ */
+vlib_node_registration_t bier_bift_input_node;
+
+void
+bier_bift_table_entry_add (bier_bift_id_t id,
+                           const dpo_id_t *dpo)
+{
+    if (NULL == bier_bift_table)
+    {
+        u32 ii;
+
+        /*
+         * allocate the table and
+         * set each of the entries therein to a BIER drop
+         */
+        bier_bift_table = clib_mem_alloc_aligned(sizeof(*bier_bift_table),
+                                                 CLIB_CACHE_LINE_BYTES);
+        memset(bier_bift_table, 0, sizeof(*bier_bift_table));
+
+        for (ii = 0; ii < BIER_BIFT_N_ENTRIES; ii++)
+        {
+            dpo_stack_from_node(bier_bift_input_node.index,
+                                &bier_bift_table->bblt_dpos[ii],
+                                drop_dpo_get(DPO_PROTO_BIER));
+        }
+
+        /*
+         * register to handle packets that arrive on the assigned
+         * UDP port
+         */
+        udp_register_dst_port(vlib_get_main(),
+                              UDP_DST_PORT_BIER,
+                              bier_bift_input_node.index,
+                              0);
+        udp_register_dst_port(vlib_get_main(),
+                              UDP_DST_PORT_BIER,
+                              bier_bift_input_node.index,
+                              1);
+    }
+
+    dpo_stack_from_node(bier_bift_input_node.index,
+                        &bier_bift_table->bblt_dpos[id],
+                        dpo);
+
+    bier_bift_table->bblt_n_entries++;
+}
+
+void
+bier_bift_table_entry_remove (bier_bift_id_t id)
+{
+    ASSERT(NULL != bier_bift_table);
+
+    dpo_reset(&bier_bift_table->bblt_dpos[id]);
+
+    bier_bift_table->bblt_n_entries--;
+
+    if (0 == bier_bift_table->bblt_n_entries)
+    {
+        udp_unregister_dst_port(vlib_get_main(),
+                                UDP_DST_PORT_BIER,
+                                0);
+        udp_unregister_dst_port(vlib_get_main(),
+                                UDP_DST_PORT_BIER,
+                                1);
+
+        clib_mem_free(bier_bift_table);
+        bier_bift_table = NULL;
+    }
+}
+
+/**
+ * @brief Packet trace record for BIER input
+ */
+typedef struct bier_bift_input_trace_t_
+{
+    u32 bift_id;
+} bier_bift_input_trace_t;
+
+static uword
+bier_bift_input (vlib_main_t * vm,
+                 vlib_node_runtime_t * node,
+                 vlib_frame_t * from_frame)
+{
+    u32 n_left_from, next_index, * from, * to_next;
+
+    from = vlib_frame_vector_args (from_frame);
+    n_left_from = from_frame->n_vectors;
+    next_index = node->cached_next_index;
+
+    while (n_left_from > 0)
+    {
+        u32 n_left_to_next;
+
+        vlib_get_next_frame (vm, node, next_index,
+                             to_next, n_left_to_next);
+
+        while (n_left_from > 0 && n_left_to_next > 0)
+        {
+            bier_bift_id_t *biftp0, bift0;
+            const dpo_id_t *dpo0;
+            vlib_buffer_t * b0;
+            u32 bi0, next0;
+
+            bi0 = from[0];
+            to_next[0] = bi0;
+            from += 1;
+            to_next += 1;
+            n_left_from -= 1;
+            n_left_to_next -= 1;
+
+            b0 = vlib_get_buffer (vm, bi0);
+            biftp0 = vlib_buffer_get_current (b0);
+            vlib_buffer_advance(b0, sizeof(bift0));
+            bift0 = clib_net_to_host_u32(*biftp0);
+
+            /*
+             * Do the lookup based on the first 20 bits, i.e. the
+             * encoding of the set, sub-domain and BSL
+             */
+            dpo0 = bier_bift_dp_lookup(bift0);
+
+            /*
+             * save the TTL for later during egress
+             */
+            vnet_buffer(b0)->mpls.ttl = vnet_mpls_uc_get_ttl(bift0);
+
+            next0 = dpo0->dpoi_next_node;
+            vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+
+            if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+            {
+                bier_bift_input_trace_t *tr;
+
+                tr = vlib_add_trace(vm, node, b0, sizeof (*tr));
+                tr->bift_id = bift0;
+            }
+
+            vlib_validate_buffer_enqueue_x1(vm, node, next_index,
+                                            to_next, n_left_to_next,
+                                            bi0, next0);
+        }
+
+        vlib_put_next_frame(vm, node, next_index, n_left_to_next);
+    }
+
+    vlib_node_increment_counter(vm, bier_bift_input_node.index,
+                                BIER_INPUT_ERROR_PKTS_VALID,
+                                from_frame->n_vectors);
+    return (from_frame->n_vectors);
+}
+
+static u8 *
+format_bier_bift_input_trace (u8 * s, va_list * args)
+{
+    CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+    CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+    bier_bift_input_trace_t * t = va_arg (*args, bier_bift_input_trace_t *);
+
+    s = format (s, "BIFT-ID:[%U]", format_bier_bift_id,
+                vnet_mpls_uc_get_label(t->bift_id));
+    return s;
+}
+
+VLIB_REGISTER_NODE (bier_bift_input_node) = {
+    .function = bier_bift_input,
+    .name = "bier-bift-input",
+    /* Takes a vector of packets. */
+    .vector_size = sizeof (u32),
+    .n_errors = BIER_INPUT_N_ERROR,
+    .error_strings = bier_error_strings,
+    .n_next_nodes = 0,
+    .format_trace = format_bier_bift_input_trace,
+};
+
+clib_error_t *
+show_bier_bift_cmd (vlib_main_t * vm,
+                    unformat_input_t * input,
+                    vlib_cli_command_t * cmd)
+{
+    clib_error_t * error = NULL;
+    u32 hdr_len, set, sub_domain;
+
+    set = hdr_len = sub_domain = ~0;
+
+    while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+        if (unformat (input, "sd %d", &sub_domain)) {
+            ;
+        } else if (unformat (input, "set %d", &set)) {
+            ;
+        } else if (unformat (input, "bsl %d", &hdr_len)) {
+            ;
+        }
+        else
+        {
+            error = unformat_parse_error (input);
+            goto done;
+        }
+    }
+
+    if (NULL == bier_bift_table)
+    {
+        vlib_cli_output(vm, "no BIFT entries");
+    }
+
+    if (~0 == set)
+    {
+        u32 ii;
+
+        for (ii = 0; ii < BIER_BIFT_N_ENTRIES; ii++)
+        {
+            if (!dpo_is_drop(&bier_bift_table->bblt_dpos[ii]))
+            {
+                bier_hdr_len_id_t bsl;
+
+                bier_bift_id_decode(ii, &set, &sub_domain, &bsl);
+
+                vlib_cli_output(vm, "set: %d, sub-domain:%d, BSL:%U",
+                                set, sub_domain,
+                                format_bier_hdr_len_id, bsl);
+                vlib_cli_output(vm, "  %U",
+                                format_dpo_id,
+                                &bier_bift_table->bblt_dpos[ii], 0);
+            }
+        }
+    }
+    else
+    {
+        bier_bift_id_t id;
+
+        id = bier_bift_id_encode(set, sub_domain,
+                                 bier_hdr_bit_len_to_id(hdr_len));
+
+        if (!dpo_is_drop(&bier_bift_table->bblt_dpos[id]))
+        {
+            vlib_cli_output(vm, "set: %d, sub-domain:%d, BSL:%U",
+                            set, sub_domain,
+                            format_bier_hdr_len_id, hdr_len);
+            vlib_cli_output(vm, "  %U",
+                            format_dpo_id,
+                            &bier_bift_table->bblt_dpos[id], 0);
+        }
+    }
+done:
+    return (error);
+}
+
+VLIB_CLI_COMMAND (show_bier_bift_command, static) = {
+    .path = "show bier bift",
+    .short_help = "show bier bift [set <value> sd <value> bsl <value>]",
+    .function = show_bier_bift_cmd,
+};
diff --git a/src/vnet/bier/bier_bift_table.h b/src/vnet/bier/bier_bift_table.h
new file mode 100644 (file)
index 0000000..bc77c37
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#ifndef __BIER_BIFT_TABLE_H__
+#define __BIER_BIFT_TABLE_H__
+
+#include <vnet/dpo/dpo.h>
+#include <vnet/bier/bier_types.h>
+#include <vnet/mpls/packet.h>
+
+/*
+ * the lookup table used to get from a BFIT_ID to a load-balance.
+ * As per-draft draft-ietf-bier-mpls-encapsulation-10 this isthe
+ * use case for non-MPLS networks
+ */
+#define BIER_BIFT_N_ENTRIES (1 << 20)
+typedef struct bier_bfit_table_t_
+{
+    /**
+     * Forwarding information for each BIFT ID
+     */
+    dpo_id_t bblt_dpos[BIER_BIFT_N_ENTRIES];
+
+    /**
+     * The number of entries in the table
+     */
+    u32 bblt_n_entries;
+} bier_bfit_table_t;
+
+
+extern void bier_bift_table_entry_add(bier_bift_id_t id,
+                                      const dpo_id_t *dpo);
+
+extern void bier_bift_table_entry_remove(bier_bift_id_t id);
+
+/**
+ * Global BIFT table
+ */
+extern bier_bfit_table_t *bier_bift_table;
+
+static inline const dpo_id_t*
+bier_bift_dp_lookup (bier_bift_id_t key_host_order)
+{
+    return (&bier_bift_table->bblt_dpos[vnet_mpls_uc_get_label(key_host_order)]);
+}
+#endif
index a00c2ee..40d0a29 100644 (file)
@@ -86,7 +86,7 @@ bier_disp_dispatch_inline (vlib_main_t * vm,
              * the packets flow-hash field
              * DSCP mumble mumble...
              */
-            vlib_buffer_advance(b0, (vnet_buffer(b0)->bier.n_bytes +
+            vlib_buffer_advance(b0, (vnet_buffer(b0)->mpls.bier.n_bytes +
                                      sizeof(*hdr0)));
             vnet_buffer(b0)->ip.flow_hash = entropy0;
 
index 3326aba..2fe2e4a 100644 (file)
@@ -145,6 +145,7 @@ bier_disp_entry_restack (bier_disp_entry_t *bde,
         fib_path_list_contribute_forwarding(pli,
                                             fib_forw_chain_type_from_dpo_proto(
                                                 bier_hdr_proto_to_dpo(pproto)),
+                                            FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
                                             &via_dpo);
 
         bier_disp_entry_path_list_walk_ctx_t ctx = {
@@ -254,24 +255,26 @@ format_bier_disp_entry (u8* s, va_list *args)
 
     bde = bier_disp_entry_get(bdei);
 
-    s = format(s, "bier-disp:[%d]", bdei);
+    s = format(s, "%Ubier-disp:[%d]", format_white_space, indent, bdei);
 
     FOR_EACH_BIER_HDR_PROTO(pproto)
     {
         if (INDEX_INVALID != bde->bde_pl[pproto])
         {
-            s = format(s, "\n");
-            s = fib_path_list_format(bde->bde_pl[pproto], s);
+            s = format(s, "\n%U%U\n",
+                       format_white_space, indent+2,
+                       format_bier_hdr_proto, pproto);
+            s = format(s, "%U", format_fib_path_list, bde->bde_pl[pproto], indent+4);
 
             if (flags & BIER_SHOW_DETAIL)
             {
                 s = format(s, "\n%UForwarding:",
-                           format_white_space, indent);
+                           format_white_space, indent+4);
                 s = format(s, "\n%Urpf-id:%d",
-                           format_white_space, indent+1,
+                           format_white_space, indent+6,
                            bde->bde_fwd[pproto].bde_rpf_id);
                 s = format(s, "\n%U%U",
-                           format_white_space, indent+1,
+                           format_white_space, indent+6,
                            format_dpo_id, &bde->bde_fwd[pproto].bde_dpo, indent+2);
             }
         }
index 47d23e8..db4a2a8 100644 (file)
@@ -161,9 +161,9 @@ format_bier_disp_table (u8* s, va_list *ap)
             if (INDEX_INVALID != bdt->bdt_db[ii])
             {
                 u16 src = ii;
-                s = format(s, "\n%Usrc:%d", format_white_space, indent,
+                s = format(s, "\n%Usrc:%d", format_white_space, indent+1,
                            clib_host_to_net_u16(src));
-                s = format(s, "\n%U%U", format_white_space, indent+2,
+                s = format(s, "\n%U",
                            format_bier_disp_entry, bdt->bdt_db[ii],
                            indent+4, BIER_SHOW_BRIEF);
             }
@@ -380,13 +380,12 @@ show_bier_disp_table (vlib_main_t * vm,
         ({
             vlib_cli_output(vm, "%U", format_bier_disp_table,
                             bier_disp_table_get_index(bdt),
-                            1,
-                            BIER_SHOW_BRIEF);
+                            0, BIER_SHOW_BRIEF);
         }));
     }
     else
     {
-        vlib_cli_output(vm, "%U", format_bier_disp_table, bdti, 1,
+        vlib_cli_output(vm, "%U", format_bier_disp_table, bdti, 0,
                         BIER_SHOW_DETAIL);
     }
     return (NULL);
index 88be812..2f8d250 100644 (file)
@@ -116,18 +116,23 @@ bier_entry_table_ecmp_walk_add_fmask (index_t btei,
 
         fib_path_list_contribute_forwarding(be->be_path_list,
                                             FIB_FORW_CHAIN_TYPE_BIER,
+                                            FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
                                             &dpo);
 
         /*
          * select the appropriate bucket from the LB
          */
-        ASSERT(dpo.dpoi_type == DPO_LOAD_BALANCE);
-
-        lb = load_balance_get(dpo.dpoi_index);
-
-        choice = load_balance_get_bucket_i(lb,
-                                           btid->bti_ecmp &
-                                           (lb->lb_n_buckets_minus_1));
+        if (dpo.dpoi_type == DPO_LOAD_BALANCE)
+        {
+            lb = load_balance_get(dpo.dpoi_index);
+            choice = load_balance_get_bucket_i(lb,
+                                               btid->bti_ecmp &
+                                               (lb->lb_n_buckets_minus_1));
+        }
+        else
+        {
+            choice = &dpo;
+        }
 
         if (choice->dpoi_type == DPO_BIER_FMASK)
         {
@@ -293,6 +298,7 @@ bier_entry_contribute_forwarding(index_t bei,
 
     fib_path_list_contribute_forwarding(be->be_path_list,
                                         FIB_FORW_CHAIN_TYPE_BIER,
+                                        FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
                                         dpo);
 }
 
index 32bece0..2fc24dc 100644 (file)
@@ -16,6 +16,7 @@
 #include <vnet/fib/fib_entry.h>
 #include <vnet/fib/fib_table.h>
 #include <vnet/fib/fib_walk.h>
+#include <vnet/fib/fib_path_list.h>
 
 #include <vnet/bier/bier_table.h>
 #include <vnet/bier/bier_fmask.h>
@@ -74,26 +75,27 @@ static void
 bier_fmask_stack (bier_fmask_t *bfm)
 {
     dpo_id_t via_dpo = DPO_INVALID;
+    fib_forward_chain_type_t fct;
 
-    if (bfm->bfm_flags & BIER_FMASK_FLAG_DISP)
+    if (bfm->bfm_flags & BIER_FMASK_FLAG_MPLS)
     {
-        bier_disp_table_contribute_forwarding(bfm->bfm_disp,
-                                              &via_dpo);
+        fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
     }
     else
     {
-        fib_entry_contribute_forwarding(bfm->bfm_fei,
-                                        FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
-                                        &via_dpo);
+        fct = FIB_FORW_CHAIN_TYPE_BIER;
     }
 
+    fib_path_list_contribute_forwarding(bfm->bfm_pl, fct,
+                                        FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
+                                        &via_dpo);
+
     /*
-     * If the via fib entry provides no forwarding (i.e. a drop)
-     * then niether does this fmask. That way children consider this fmask
+     * If the via PL entry provides no forwarding (i.e. a drop)
+     * then neither does this fmask. That way children consider this fmask
      * unresolved and other ECMP options are used instead.
      */
-    if (dpo_is_drop(&via_dpo) ||
-        load_balance_is_drop(&via_dpo))
+    if (dpo_is_drop(&via_dpo))
     {
         bfm->bfm_flags &= ~BIER_FMASK_FLAG_FORWARDING;
     }
@@ -130,65 +132,6 @@ bier_fmask_contribute_forwarding (index_t bfmi,
     }
 }
 
-static void
-bier_fmask_resolve (bier_fmask_t *bfm)
-{
-    if (bfm->bfm_flags & BIER_FMASK_FLAG_DISP)
-    {
-        bier_disp_table_lock(bfm->bfm_disp);
-    }
-    else
-    {
-        /*
-         * source a recursive route through which we resolve.
-         */
-        fib_prefix_t pfx = {
-            .fp_addr = bfm->bfm_id.bfmi_nh,
-            .fp_proto = (ip46_address_is_ip4(&(bfm->bfm_id.bfmi_nh)) ?
-                         FIB_PROTOCOL_IP4 :
-                         FIB_PROTOCOL_IP6),
-            .fp_len = (ip46_address_is_ip4(&(bfm->bfm_id.bfmi_nh)) ? 32 : 128),
-        };
-
-        bfm->bfm_fei = fib_table_entry_special_add(0, // default table
-                                                   &pfx,
-                                                   FIB_SOURCE_RR,
-                                                   FIB_ENTRY_FLAG_NONE);
-
-        bfm->bfm_sibling = fib_entry_child_add(bfm->bfm_fei,
-                                               FIB_NODE_TYPE_BIER_FMASK,
-                                               bier_fmask_get_index(bfm));
-    }
-
-    bier_fmask_stack(bfm);
-}
-
-static void
-bier_fmask_unresolve (bier_fmask_t *bfm)
-{
-    if (bfm->bfm_flags & BIER_FMASK_FLAG_DISP)
-    {
-        bier_disp_table_unlock(bfm->bfm_disp);
-    }
-    else
-    {
-        /*
-         * un-source the recursive route through which we resolve.
-         */
-        fib_prefix_t pfx = {
-            .fp_addr = bfm->bfm_id.bfmi_nh,
-            .fp_proto = (ip46_address_is_ip4(&(bfm->bfm_id.bfmi_nh)) ?
-                         FIB_PROTOCOL_IP4 :
-                         FIB_PROTOCOL_IP6),
-            .fp_len = (ip46_address_is_ip4(&(bfm->bfm_id.bfmi_nh)) ? 32 : 128),
-        };
-
-        fib_entry_child_remove(bfm->bfm_fei, bfm->bfm_sibling);
-        fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_RR);
-    }
-    dpo_reset(&bfm->bfm_dpo);
-}
-
 u32
 bier_fmask_child_add (fib_node_index_t bfmi,
                      fib_node_type_t child_type,
@@ -204,6 +147,11 @@ void
 bier_fmask_child_remove (fib_node_index_t bfmi,
                          u32 sibling_index)
 {
+    if (INDEX_INVALID == bfmi)
+    {
+        return;
+    }
+
     fib_node_child_remove(FIB_NODE_TYPE_BIER_FMASK,
                           bfmi,
                           sibling_index);
@@ -212,38 +160,64 @@ bier_fmask_child_remove (fib_node_index_t bfmi,
 static void
 bier_fmask_init (bier_fmask_t *bfm,
                  const bier_fmask_id_t *fmid,
-                 index_t bti,
-                 const fib_route_path_t *rpath)
+                 const fib_route_path_t *rpaths)
 {
     const bier_table_id_t *btid;
     mpls_label_t olabel;
 
-    bfm->bfm_id = *fmid;
-    bfm->bfm_fib_index = bti;
+    *bfm->bfm_id = *fmid;
     dpo_reset(&bfm->bfm_dpo);
+    btid = bier_table_get_id(bfm->bfm_id->bfmi_bti);
+    bier_fmask_bits_init(&bfm->bfm_bits, btid->bti_hdr_len);
 
-    if (ip46_address_is_zero(&(bfm->bfm_id.bfmi_nh)))
+    if (ip46_address_is_zero(&(bfm->bfm_id->bfmi_nh)))
     {
         bfm->bfm_flags |= BIER_FMASK_FLAG_DISP;
     }
 
     if (!(bfm->bfm_flags & BIER_FMASK_FLAG_DISP))
     {
-        olabel = rpath->frp_label_stack[0];
-        vnet_mpls_uc_set_label(&bfm->bfm_label, olabel);
-        vnet_mpls_uc_set_exp(&bfm->bfm_label, 0);
-        vnet_mpls_uc_set_s(&bfm->bfm_label, 1);
-        vnet_mpls_uc_set_ttl(&bfm->bfm_label, 0xff);
-        bfm->bfm_label = clib_host_to_net_u32(bfm->bfm_label);
-    }
-    else
-    {
-        bfm->bfm_disp = rpath->frp_bier_fib_index;
+        /*
+         * leave this label in host byte order so we can OR in the TTL
+         */
+        if (NULL != rpaths->frp_label_stack)
+        {
+            olabel = rpaths->frp_label_stack[0];
+            vnet_mpls_uc_set_label(&bfm->bfm_label, olabel);
+            vnet_mpls_uc_set_exp(&bfm->bfm_label, 0);
+            vnet_mpls_uc_set_s(&bfm->bfm_label, 1);
+            vnet_mpls_uc_set_ttl(&bfm->bfm_label, 0);
+            bfm->bfm_flags |= BIER_FMASK_FLAG_MPLS;
+        }
+        else
+        {
+            bier_bift_id_t id;
+
+            /*
+             * not an MPLS label
+             */
+            bfm->bfm_flags &= ~BIER_FMASK_FLAG_MPLS;
+
+            /*
+             * use a label as encoded for BIFT value
+             */
+            id = bier_bift_id_encode(btid->bti_set,
+                                     btid->bti_sub_domain,
+                                     btid->bti_hdr_len);
+            vnet_mpls_uc_set_label(&bfm->bfm_label, id);
+            vnet_mpls_uc_set_s(&bfm->bfm_label, 1);
+            vnet_mpls_uc_set_exp(&bfm->bfm_label, 0);
+        }
     }
 
-    btid = bier_table_get_id(bfm->bfm_fib_index);
-    bier_fmask_bits_init(&bfm->bfm_bits, btid->bti_hdr_len);
-    bier_fmask_resolve(bfm);
+    bfm->bfm_pl = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED |
+                                        FIB_PATH_LIST_FLAG_NO_URPF),
+                                       rpaths);
+    bfm->bfm_sibling = fib_path_list_child_add(bfm->bfm_pl,
+                                               FIB_NODE_TYPE_BIER_FMASK,
+                                               bier_fmask_get_index(bfm));
+
+    bier_fmask_stack(bfm);
 }
 
 static void
@@ -252,8 +226,11 @@ bier_fmask_destroy (bier_fmask_t *bfm)
     clib_mem_free(bfm->bfm_bits.bfmb_refs);
     clib_mem_free(bfm->bfm_bits.bfmb_input_reset_string.bbs_buckets);
 
-    bier_fmask_db_remove(bfm->bfm_fib_index, &(bfm->bfm_id));
-    bier_fmask_unresolve(bfm);
+    bier_fmask_db_remove(bfm->bfm_id);
+    fib_path_list_child_remove(bfm->bfm_pl,
+                               bfm->bfm_sibling);
+    dpo_reset(&bfm->bfm_dpo);
+    clib_mem_free(bfm->bfm_id);
     pool_put(bier_fmask_pool, bfm);
 }
 
@@ -289,8 +266,7 @@ bier_fmask_lock (index_t bfmi)
 
 index_t
 bier_fmask_create_and_lock (const bier_fmask_id_t *fmid,
-                            index_t bti,
-                            const fib_route_path_t *rpath)
+                            const fib_route_path_t *rpaths)
 {
     bier_fmask_t *bfm;
 
@@ -298,8 +274,11 @@ bier_fmask_create_and_lock (const bier_fmask_id_t *fmid,
 
     memset(bfm, 0, sizeof(*bfm));
 
+    bfm->bfm_id = clib_mem_alloc(sizeof(*bfm->bfm_id));
+
+    ASSERT(1 == vec_len(rpaths));
     fib_node_init(&bfm->bfm_node, FIB_NODE_TYPE_BIER_FMASK);
-    bier_fmask_init(bfm, fmid, bti, rpath);
+    bier_fmask_init(bfm, fmid, rpaths);
 
     bier_fmask_lock(bier_fmask_get_index(bfm));
 
@@ -362,7 +341,7 @@ format_bier_fmask (u8 *s, va_list *ap)
     bfm = bier_fmask_get(bfmi);
 
     s = format(s, "fmask: nh:%U bs:%U locks:%d ",
-               format_ip46_address, &bfm->bfm_id.bfmi_nh, IP46_TYPE_ANY,
+               format_ip46_address, &bfm->bfm_id->bfmi_nh, IP46_TYPE_ANY,
                format_bier_bit_string, &bfm->bfm_bits.bfmb_input_reset_string,
                bfm->bfm_node.fn_locks);
     s = format(s, "flags:");
@@ -371,7 +350,22 @@ format_bier_fmask (u8 *s, va_list *ap)
             s = format (s, "%s,", bier_fmask_attr_names[attr]);
         }
     }
-    s = format(s, "\n%U%U",
+    s = format(s, "\n");
+    s = fib_path_list_format(bfm->bfm_pl, s);
+
+    if (bfm->bfm_flags & BIER_FMASK_FLAG_MPLS)
+    {
+        s = format(s, "  output-label:%U",
+                   format_mpls_unicast_label,
+                   vnet_mpls_uc_get_label(bfm->bfm_label));
+    }
+    else
+    {
+        s = format(s, "  output-bfit:[%U]",
+                   format_bier_bift_id,
+                   vnet_mpls_uc_get_label(bfm->bfm_label));
+    }
+    s = format(s, "\n %U%U",
                format_white_space, indent,
                format_dpo_id, &bfm->bfm_dpo, indent+2);
 
@@ -509,7 +503,8 @@ bier_fmask_show (vlib_main_t * vm,
     {
         pool_foreach(bfm, bier_fmask_pool,
         ({
-            vlib_cli_output (vm, "%U",
+            vlib_cli_output (vm, "[@%d] %U",
+                             bier_fmask_get_index(bfm),
                              format_bier_fmask, bier_fmask_get_index(bfm), 0);
         }));
     }
index 13eab53..81b3923 100644 (file)
@@ -65,12 +65,14 @@ typedef enum bier_fmask_attributes_t_
     BIER_FMASK_ATTR_FIRST,
     BIER_FMASK_ATTR_FORWARDING = BIER_FMASK_ATTR_FIRST,
     BIER_FMASK_ATTR_DISP,
+    BIER_FMASK_ATTR_MPLS,
     BIER_FMASK_ATTR_LAST = BIER_FMASK_ATTR_DISP,
 } bier_fmask_attributes_t;
 
 #define BIER_FMASK_ATTR_NAMES {                         \
      [BIER_FMASK_ATTR_FORWARDING] = "forwarding",       \
      [BIER_FMASK_ATTR_DISP] = "disposition",            \
+     [BIER_FMASK_ATTR_MPLS] = "mpls",                   \
 }
 
 #define FOR_EACH_BIER_FMASK_ATTR(_item)          \
@@ -82,6 +84,7 @@ typedef enum bier_fmask_flags_t_
 {
     BIER_FMASK_FLAG_FORWARDING = (1 << BIER_FMASK_ATTR_FORWARDING),
     BIER_FMASK_FLAG_DISP = (1 << BIER_FMASK_ATTR_DISP),
+    BIER_FMASK_FLAG_MPLS = (1 << BIER_FMASK_ATTR_MPLS),
 } bier_fmask_flags_t;
 
 /**
@@ -110,47 +113,20 @@ typedef struct bier_fmask_t_ {
      */
     bier_fmask_bits_t bfm_bits;
 
-    struct
-    {
-        /**
-         * The key to this fmask - used for store/lookup in the DB
-         */
-        bier_fmask_id_t bfm_id;
-
-        /**
-         * The BIER Table this Fmask is used in
-         */
-        index_t bfm_fib_index;
-    };
-
-    union
-    {
-        /**
-         * For forwarding via a next-hop
-         */
-        struct
-        {
-            /**
-             * The parent fib entry
-             */
-            fib_node_index_t bfm_fei;
-            /**
-             * The MPLS label to paint on the header during forwarding
-             */
-            mpls_label_t bfm_label;
-        };
-
-        /**
-         * For disposition
-         */
-        struct
-        {
-            /**
-             * The parent disposition table object
-             */
-            index_t bfm_disp;
-        };
-    };
+    /**
+     * The key to this fmask - used for store/lookup in the DB
+     */
+    bier_fmask_id_t *bfm_id;
+
+    /**
+     * The MPLS label to paint on the header during forwarding
+     */
+    mpls_label_t bfm_label;
+
+    /**
+     * The path-list
+     */
+    fib_node_index_t bfm_pl;
 
     /**
      * the index of this fmask in the parent's child list.
@@ -170,7 +146,6 @@ extern void bier_fmask_unlock(index_t bfmi);
 extern void bier_fmask_lock(index_t bfmi);
 
 extern index_t bier_fmask_create_and_lock(const bier_fmask_id_t *fmid,
-                                          index_t bti,
                                           const fib_route_path_t *rpath);
 
 extern u8* format_bier_fmask(u8 *s, va_list *ap);
index 37cbb36..67d3bd1 100644 (file)
@@ -39,16 +39,6 @@ typedef struct bier_fmask_db_t_ {
     struct bier_fmask_t_ *bfdb_pool;
 } bier_fmask_db_t;
 
-/**
- * The key used in the fmask DB to compare fmask objects.
- * There is one global DB, so we need to use the table's ID and the fmasks ID
- */
-typedef struct bier_fmask_db_key_t_ {
-    bier_fmask_id_t bfmdbk_fm_id;
-    index_t bfmdbk_tbl_id;
-} bier_fmask_db_key_t;
-// TODO packed?
-
 /**
  * Single fmask DB
  */
@@ -61,82 +51,93 @@ bier_fmask_get_index (const bier_fmask_t *bfm)
     return (bfm - bier_fmask_db.bfdb_pool);
 }
 
-u32
-bier_fmask_db_find_or_create_and_lock (index_t bti,
-                                       const bier_fmask_id_t *fmid,
-                                       const fib_route_path_t *rpath)
+static void
+bier_fmask_db_mk_key (index_t bti,
+                      const fib_route_path_t *rpath,
+                      bier_fmask_id_t *key)
 {
-    bier_fmask_db_key_t key;
-    u32 index;
-    uword *p;
-
     /*
-     * there be padding in that thar key, and it's
-     * used as a memcmp in the mhash.
+     * Depending on what the ID is there may be padding.
+     * This key will be memcmp'd in the mhash, so make sure it's all 0
      */
-    memset(&key, 0, sizeof(key));
-    key.bfmdbk_tbl_id = bti;
-    key.bfmdbk_fm_id = *fmid;
-
-    index = INDEX_INVALID;
-    p = mhash_get (&bier_fmask_db.bfdb_hash, &key);
+    memset(key, 0, sizeof(*key));
 
-    if (NULL == p)
+    /*
+     * Pick the attributes from the path that make the FMask unique
+     */
+    if (FIB_ROUTE_PATH_UDP_ENCAP & rpath->frp_flags)
     {
-        /*
-         * adding a new fmask object
-         */
-        index = bier_fmask_create_and_lock(fmid, bti, rpath);
-
-        mhash_set (&bier_fmask_db.bfdb_hash, &key, index, 0 /*old_value*/);
+        key->bfmi_id = rpath->frp_udp_encap_id;
     }
     else
     {
-        index = p[0];
-        bier_fmask_lock(index);
+        key->bfmi_sw_if_index = rpath->frp_sw_if_index;
+        memcpy(&key->bfmi_nh, &rpath->frp_addr, sizeof(rpath->frp_addr));
+    }
+    if (NULL == rpath->frp_label_stack)
+    {
+        key->bfmi_hdr_type = BIER_HDR_O_OTHER;
+    }
+    else
+    {
+        key->bfmi_hdr_type = BIER_HDR_O_MPLS;
     }
-
-    return (index);
 }
 
 u32
 bier_fmask_db_find (index_t bti,
-                    const bier_fmask_id_t *fmid)
+                    const fib_route_path_t *rpath)
 {
-    bier_fmask_db_key_t key;
-    u32 index;
+    bier_fmask_id_t fmid;
     uword *p;
 
-    /*
-     * there be padding in that thar key, and it's
-     * used as a memcmp in the mhash.
-     */
-    memset(&key, 0, sizeof(key));
-    key.bfmdbk_tbl_id = bti;
-    key.bfmdbk_fm_id = *fmid;
-
-    index = INDEX_INVALID;
-    p = mhash_get(&bier_fmask_db.bfdb_hash, &key);
+    bier_fmask_db_mk_key(bti, rpath, &fmid);
+    p = mhash_get(&bier_fmask_db.bfdb_hash, &fmid);
 
     if (NULL != p)
+    {
+        return (p[0]);
+    }
+
+    return (INDEX_INVALID);
+}
+
+u32
+bier_fmask_db_find_or_create_and_lock (index_t bti,
+                                       const fib_route_path_t *rpath)
+{
+    bier_fmask_id_t fmid;
+    u32 index;
+    uword *p;
+
+    bier_fmask_db_mk_key(bti, rpath, &fmid);
+    p = mhash_get(&bier_fmask_db.bfdb_hash, &fmid);
+
+    if (NULL == p)
+    {
+        bier_fmask_t *bfm;
+        /*
+         * adding a new fmask object
+         */
+        index = bier_fmask_create_and_lock(&fmid, rpath);
+        bfm = bier_fmask_get(index);
+        mhash_set(&bier_fmask_db.bfdb_hash, bfm->bfm_id, index, 0);
+    }
+    else
     {
         index = p[0];
+        bier_fmask_lock(index);
     }
 
     return (index);
 }
 
 void
-bier_fmask_db_remove (index_t bti,
-                      const bier_fmask_id_t *fmid)
+bier_fmask_db_remove (const bier_fmask_id_t *fmid)
 {
-    bier_fmask_db_key_t key = {
-        .bfmdbk_tbl_id = bti,
-        .bfmdbk_fm_id = *fmid,
-    };
     uword *p;
 
-    p = mhash_get (&bier_fmask_db.bfdb_hash, &key);
+    p = mhash_get(&bier_fmask_db.bfdb_hash, fmid);
 
     if (NULL == p) {
         /*
@@ -144,16 +145,16 @@ bier_fmask_db_remove (index_t bti,
          */
         ASSERT (!"remove non-existant fmask");
     } else {
-        mhash_unset (&(bier_fmask_db.bfdb_hash), &key, 0);
+        mhash_unset(&(bier_fmask_db.bfdb_hash), (void*)fmid, 0);
     }
 }
 
 clib_error_t *
 bier_fmask_db_module_init (vlib_main_t *vm)
 {
-    mhash_init (&bier_fmask_db.bfdb_hash,
-                sizeof(uword),
-                sizeof(bier_fmask_db_key_t));
+    mhash_init(&bier_fmask_db.bfdb_hash,
+               sizeof(index_t),
+               sizeof(bier_fmask_id_t));
 
     return (NULL);
 }
index 6ba40f3..a7f29c2 100644 (file)
 
 #include <vnet/ip/ip.h>
 
-#include <vnet/bier/bier_types.h>
+#include <vnet/fib/fib_types.h>
 
 /**
- * Foward declarations
+ * BIER header encapulsation types
  */
-struct bier_fmask_t_;
-
 typedef enum bier_hdr_type_t_ {
-    BIER_HDR_IN_IP6,
+    /**
+     * BIER Header in MPLS networks
+     */
     BIER_HDR_O_MPLS,
+
+    /**
+     * BIER header in non-MPLS networks
+     */
+    BIER_HDR_O_OTHER,
 } bier_hdr_type_t;
 
+/**
+ * A key/ID for a BIER forwarding Mas (FMask).
+ * This is a simplified version of a fib_route_path_t.
+ */
 typedef struct bier_fmask_id_t_ {
     /**
      * Type of BIER header this fmask supports
@@ -40,22 +49,35 @@ typedef struct bier_fmask_id_t_ {
     bier_hdr_type_t bfmi_hdr_type;
 
     /**
-     * next-hop of the peer
+     * The BIER table this fmask is in
+     */
+    index_t bfmi_bti;
+
+    union {
+        /**
+         * next-hop of the peer
+         */
+        ip46_address_t bfmi_nh;
+
+        /**
+         * ID of the next-hop object, e.g. a UDP-encap
+         */
+        u32 bfmi_id;
+    };
+
+    /**
+     * Software interface index
      */
-    ip46_address_t bfmi_nh;
-} bier_fmask_id_t;
+    u32 bfmi_sw_if_index;
+} __attribute__((packed)) bier_fmask_id_t;
 
-extern u32
+extern index_t
 bier_fmask_db_find_or_create_and_lock(index_t bti,
-                                      const bier_fmask_id_t *fmid,
                                       const fib_route_path_t *rpath);
+extern index_t bier_fmask_db_find (index_t bti,
+                                   const fib_route_path_t *rpath);
 
-extern u32
-bier_fmask_db_find(index_t bti,
-                   const bier_fmask_id_t *fmid);
+extern void bier_fmask_db_remove (const bier_fmask_id_t *fmid);
 
-extern void
-bier_fmask_db_remove(index_t bti,
-                     const bier_fmask_id_t *fmid);
 
 #endif
index e9aae93..9c09d67 100644 (file)
@@ -134,6 +134,12 @@ bier_imp_dpo_inline (vlib_main_t * vm,
                                       BIER_HDR_ENTROPY_FIELD_MASK) <<
                                      BIER_HDR_ENTROPY_FIELD_SHIFT);
 
+            /*
+             * use TTL 64 for the post enacp MPLS label/BIFT-ID
+             * this we be decremeted in bier_output node.
+             */
+            vnet_buffer(b0)->mpls.ttl = 65;
+
             /* next node */
             next0 = bimp0->bi_dpo[fproto].dpoi_next_node;
             vnet_buffer(b0)->ip.adj_index[VLIB_TX] =
index 88b37fc..dca990d 100644 (file)
@@ -40,7 +40,7 @@ typedef enum bier_input_next_t_ {
 vlib_node_registration_t bier_input_node;
 
 /**
- * @brief Packet trace recoed for a BIER output
+ * @brief Packet trace record for BIER input
  */
 typedef struct bier_input_trace_t_
 {
index 4cf29f8..817dcc6 100644 (file)
@@ -138,7 +138,7 @@ bier_lookup (vlib_main_t * vm,
              * number of integer sized buckets
              */
             n_bytes = bier_hdr_len_id_to_num_buckets(bt0->bt_id.bti_hdr_len);
-            vnet_buffer(b0)->bier.n_bytes = n_bytes;
+            vnet_buffer(b0)->mpls.bier.n_bytes = n_bytes;
             vnet_buffer(b0)->sw_if_index[VLIB_TX] = ~0;
             num_buckets = n_bytes / sizeof(int);
             bier_bit_string_init(&bbs,
@@ -178,7 +178,6 @@ bier_lookup (vlib_main_t * vm,
                     if (PREDICT_TRUE(INDEX_INVALID != bfmi0))
                     {
                         bfm0 = bier_fmask_get(bfmi0);
-                        vnet_buffer (b0)->ip.adj_index[VLIB_TX] = bfmi0;
 
                         /*
                          * use the bit-string on the fmask to reset
@@ -237,6 +236,8 @@ bier_lookup (vlib_main_t * vm,
 
                     ci0 = blm->blm_clones[thread_index][clone];
                     c0 = vlib_get_buffer(vm, ci0);
+                    vnet_buffer(c0)->ip.adj_index[VLIB_TX] =
+                        blm->blm_fmasks[thread_index][clone];
 
                     to_next[0] = ci0;
                     to_next += 1;
index fce6c50..db115d3 100644 (file)
@@ -89,9 +89,10 @@ bier_output (vlib_main_t * vm,
             bier_bit_string_t bbs;
             vlib_buffer_t * b0;
             bier_fmask_t *bfm0;
+            mpls_label_t *h0;
             bier_hdr_t *bh0;
-            u32 bi0, *h0;
             u32 bfmi0;
+            u32 bi0;
 
             bi0 = from[0];
             to_next[0] = bi0;
@@ -131,9 +132,16 @@ bier_output (vlib_main_t * vm,
              */
             if (!(bfm0->bfm_flags & BIER_FMASK_FLAG_DISP))
             {
+                /*
+                 * since a BIFT value and a MPLS label are formated the
+                 * same, this painting works OK.
+                 */
                 vlib_buffer_advance(b0, -(word)sizeof(mpls_label_t));
                 h0 = vlib_buffer_get_current(b0);
+                
                 h0[0] = bfm0->bfm_label;
+                vnet_mpls_uc_set_ttl(h0, vnet_buffer(b0)->mpls.ttl - 1);
+                h0[0] = clib_host_to_net_u32(h0[0]);
             }
 
             /*
index 191ac01..0f0f376 100644 (file)
@@ -20,6 +20,7 @@
 #include <vnet/bier/bier_update.h>
 #include <vnet/bier/bier_fmask_db.h>
 #include <vnet/bier/bier_fmask.h>
+#include <vnet/bier/bier_bift_table.h>
 
 #include <vnet/fib/mpls_fib.h>
 #include <vnet/mpls/mpls.h>
@@ -96,9 +97,6 @@ bier_table_init (bier_table_t *bt,
                                         num_entries,
                                         INDEX_INVALID,
                                         CLIB_CACHE_LINE_BYTES);
-        fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS,
-                                          MPLS_FIB_DEFAULT_TABLE_ID,
-                                          FIB_SOURCE_BIER);
     }
     else
     {
@@ -109,6 +107,33 @@ bier_table_init (bier_table_t *bt,
     }
 }
 
+static void
+bier_table_rm_bift (bier_table_t *bt)
+{
+    ASSERT(MPLS_LABEL_INVALID == bt->bt_ll);
+
+    bier_bift_table_entry_remove(bier_bift_id_encode(bt->bt_id.bti_set,
+                                                     bt->bt_id.bti_sub_domain,
+                                                     bt->bt_id.bti_hdr_len));
+}
+
+static void
+bier_table_mk_bift (bier_table_t *bt)
+{
+    dpo_id_t dpo = DPO_INVALID;
+
+    ASSERT(MPLS_LABEL_INVALID == bt->bt_ll);
+
+    bier_table_contribute_forwarding(bier_table_get_index(bt), &dpo);
+
+    bier_bift_table_entry_add(bier_bift_id_encode(bt->bt_id.bti_set,
+                                                  bt->bt_id.bti_sub_domain,
+                                                  bt->bt_id.bti_hdr_len),
+                               &dpo);
+
+    dpo_reset(&dpo);
+}
+
 static void
 bier_table_rm_lfib (bier_table_t *bt)
 {
@@ -116,6 +141,9 @@ bier_table_rm_lfib (bier_table_t *bt)
     {
         fib_table_entry_delete_index(bt->bt_lfei,
                                      FIB_SOURCE_BIER);
+        fib_table_unlock(MPLS_FIB_DEFAULT_TABLE_ID,
+                         FIB_PROTOCOL_MPLS,
+                         FIB_SOURCE_BIER);
     }
     bt->bt_lfei = FIB_NODE_INDEX_INVALID;
 }
@@ -127,6 +155,15 @@ bier_table_destroy (bier_table_t *bt)
     {
         index_t *bei;
 
+        if (MPLS_LABEL_INVALID != bt->bt_ll)
+        {
+            bier_table_rm_lfib(bt);
+        }
+        else
+        {
+            bier_table_rm_bift(bt);
+        }
+
         fib_path_list_unlock(bt->bt_pl);
         bt->bt_pl = FIB_NODE_INDEX_INVALID;
         /*
@@ -140,10 +177,6 @@ bier_table_destroy (bier_table_t *bt)
             }
         }
         vec_free (bt->bt_entries);
-        fib_table_unlock(fib_table_find(FIB_PROTOCOL_MPLS,
-                                        MPLS_FIB_DEFAULT_TABLE_ID),
-                         FIB_PROTOCOL_MPLS,
-                         FIB_SOURCE_BIER);
     }
     else
     {
@@ -177,7 +210,6 @@ bier_table_unlock_i (bier_table_t *bt)
 
     if (0 == bt->bt_locks)
     {
-        bier_table_rm_lfib(bt);
         bier_table_destroy(bt);
     }
 }
@@ -214,12 +246,17 @@ bier_table_mk_lfib (bier_table_t *bt)
         u32 mpls_fib_index;
         dpo_id_t dpo = DPO_INVALID;
 
+        fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS,
+                                          MPLS_FIB_DEFAULT_TABLE_ID,
+                                          FIB_SOURCE_BIER);
+
         /*
          * stack the entry on the forwarding chain prodcued by the
          * path-list via the ECMP tables.
          */
         fib_path_list_contribute_forwarding(bt->bt_pl,
                                             FIB_FORW_CHAIN_TYPE_BIER,
+                                            FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
                                             &dpo);
 
         mpls_fib_index = fib_table_find(FIB_PROTOCOL_MPLS,
@@ -306,13 +343,37 @@ bier_table_add_or_lock (const bier_table_id_t *btid,
          * modify an existing table.
          * change the lfib entry to the new local label
          */
-        if (bier_table_is_main(bt) &&
-            (local_label != MPLS_LABEL_INVALID))
+        if (bier_table_is_main(bt))
         {
-            bier_table_rm_lfib(bt);
+            /*
+             * remove the mpls-fib or bift entry
+             */
+            if (MPLS_LABEL_INVALID != bt->bt_ll)
+            {
+                bier_table_rm_lfib(bt);
+            }
+            else
+            {
+                bier_table_rm_bift(bt);
+            }
+
+            /*
+             * reset
+             */
+            bt->bt_ll = MPLS_LABEL_INVALID;
 
-            bt->bt_ll = local_label;
-            bier_table_mk_lfib(bt);
+            /*
+             * add whichever mpls-fib or bift we need
+             */
+            if (local_label != MPLS_LABEL_INVALID)
+            {
+                bt->bt_ll = local_label;
+                bier_table_mk_lfib(bt);
+            }
+            else
+            {
+                bier_table_mk_bift(bt);
+            }
         }
         bti = bier_table_get_index(bt);
     }
@@ -334,7 +395,19 @@ bier_table_add_or_lock (const bier_table_id_t *btid,
         if (bier_table_is_main(bt))
         {
             bt = bier_table_mk_ecmp(bti);
-            bier_table_mk_lfib(bt);
+
+            /*
+             * add whichever mpls-fib or bift we need
+             */
+            if (local_label != MPLS_LABEL_INVALID)
+            {
+                bt->bt_ll = local_label;
+                bier_table_mk_lfib(bt);
+            }
+            else
+            {
+                bier_table_mk_bift(bt);
+            }
         }
     }
 
@@ -459,16 +532,19 @@ bier_table_route_add (const bier_table_id_t *btid,
      */
     vec_foreach(brp, brps)
     {
-        bier_fmask_id_t fmid = {
-            .bfmi_nh = brp->frp_addr,
-            .bfmi_hdr_type = BIER_HDR_O_MPLS,
-        };
-        bfmi = bier_fmask_db_find_or_create_and_lock(bier_table_get_index(bt),
-                                                     &fmid,
-                                                     brp);
-
-        brp->frp_bier_fib_index = bti;
+        /*
+         * First use the path to find or construct an FMask object
+         * via the next-hop
+         */
+        bfmi = bier_fmask_db_find_or_create_and_lock(bti, brp);
         vec_add1(bfmis, bfmi);
+
+        /*
+         * then modify the path to resolve via this fmask object
+         * and use it to resolve the BIER entry.
+         */
+        brp->frp_flags = FIB_ROUTE_PATH_BIER_FMASK;
+        brp->frp_bier_fmask = bfmi;
     }
 
     if (INDEX_INVALID == bei)
@@ -536,6 +612,7 @@ bier_table_contribute_forwarding (index_t bti,
          */
         fib_path_list_contribute_forwarding(bt->bt_pl,
                                             FIB_FORW_CHAIN_TYPE_BIER,
+                                            FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
                                             dpo);
     }
     else
@@ -642,12 +719,12 @@ format_bier_table (u8 *s, va_list *ap)
 
     if (pool_is_free_index(bier_table_pool, bti))
     {
-        return (format(s, "No BIER f-mask %d", bti));
+        return (format(s, "No BIER table %d", bti));
     }
 
     bt = bier_table_get(bti);
 
-    s = format(s, "[@%d] bier-table:[%U local-label:%U]",
+    s = format(s, "[@%d] bier-table:[%U local-label:%U",
                bti,
                format_bier_table_id, &bt->bt_id,
                format_mpls_unicast_label, bt->bt_ll);
index f0e7b0c..cf75c2e 100644 (file)
@@ -312,7 +312,7 @@ bier_test_mpls_spf (void)
     fib_route_path_t path_1_1_1_1 = {
         .frp_addr = nh_1_1_1_1,
         .frp_bier_fib_index = bti,
-        .frp_flags = FIB_ROUTE_PATH_BIER_FMASK,
+        .frp_sw_if_index = ~0,
     };
     vec_add1(path_1_1_1_1.frp_label_stack, 500);
     vec_add1(paths_1_1_1_1, path_1_1_1_1);
@@ -321,10 +321,6 @@ bier_test_mpls_spf (void)
         .fp_len = 32,
         .fp_proto = FIB_PROTOCOL_IP4,
     };
-    const bier_fmask_id_t bfm_id_1_1_1_1 = {
-        .bfmi_hdr_type = BIER_HDR_O_MPLS,
-        .bfmi_nh = nh_1_1_1_1,
-    };
     index_t bei_1;
 
     bier_table_route_add(&bt_0_0_0_256, 1, paths_1_1_1_1);
@@ -345,20 +341,12 @@ bier_test_mpls_spf (void)
                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
                                     &neos_dpo_1_1_1_1);
 
-    bfmi_1_1_1_1 = bier_fmask_db_find(bti, &bfm_id_1_1_1_1);
+    bfmi_1_1_1_1 = bier_fmask_db_find(bti, &path_1_1_1_1);
     bfm_1_1_1_1 = bier_fmask_get(bfmi_1_1_1_1);
 
-    BIER_TEST(!dpo_cmp(&neos_dpo_1_1_1_1, &bfm_1_1_1_1->bfm_dpo),
-              "Fmask via 1.1.1.1 stacks on neos from 1.1.1.1/32");
-
-    /*
-     * and that n-eos LB at this stage is a drop..
-     */
-    const fib_test_lb_bucket_t bucket_drop = {
-        .type = FT_LB_DROP,
-    };
-    BIER_TEST(fib_test_validate_lb(&neos_dpo_1_1_1_1, 1, &bucket_drop),
-             "1.1.1.1/32 n-eos LB 1 buckets via: DROP");
+    BIER_TEST(!dpo_cmp(drop_dpo_get(DPO_PROTO_MPLS),
+                       &bfm_1_1_1_1->bfm_dpo),
+              "Fmask via 1.1.1.1 stacks on MPLS drop");
 
     /*
      * The BIER entry should stack on the forwarding chain of the fmask
@@ -369,8 +357,11 @@ bier_test_mpls_spf (void)
             .fmask = bfmi_1_1_1_1,
         },
     };
-    BIER_TEST(bier_test_validate_entry(bei_1, 1, &bucket_drop),
-              "BP:1  stacks on bier drop");
+    dpo_id_t dpo_bei = DPO_INVALID;
+    bier_entry_contribute_forwarding(bei_1, &dpo_bei);
+
+    BIER_TEST(!dpo_cmp(&dpo_bei, drop_dpo_get(DPO_PROTO_BIER)),
+              "BP:1 stacks on bier drop");
 
     /*
      * give 1.1.1.1/32 a path and hence a interesting n-eos chain
@@ -418,7 +409,8 @@ bier_test_mpls_spf (void)
     BIER_TEST(!dpo_cmp(&neos_dpo_1_1_1_1,
                        &bfm_1_1_1_1->bfm_dpo),
               "Fmask via 1.1.1.1 stacks on updated non-eos of 1.1.1.1/32");
-    BIER_TEST(bier_test_validate_entry(bei_1, 1, &dpo_o_bfm_1_1_1_1),
+    bier_entry_contribute_forwarding(bei_1, &dpo_bei);
+    BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1),
               "BP:1  stacks on fmask 1.1.1.1");
 
     /*
@@ -486,8 +478,9 @@ bier_test_mpls_spf (void)
     bier_table_route_add(&bt_0_0_0_256, 2, paths_1_1_1_1);
     bei_2 = bier_table_lookup(bier_table_get(bti), 2);
 
-    BIER_TEST(bier_test_validate_entry(bei_2, 1, &dpo_o_bfm_1_1_1_1),
-              "BP:2 stacks on fmask 1.1.1.1");
+    bier_entry_contribute_forwarding(bei_2, &dpo_bei);
+    BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1),
+              "BP:2  stacks on fmask 1.1.1.1");
 
     /*
      * now add a bit-position via a different next hop and expect to
@@ -506,14 +499,10 @@ bier_test_mpls_spf (void)
     fib_route_path_t *paths_1_1_1_2 = NULL, path_1_1_1_2 = {
         .frp_addr = nh_1_1_1_2,
         .frp_bier_fib_index = bti,
-        .frp_flags = FIB_ROUTE_PATH_BIER_FMASK,
+        .frp_sw_if_index = ~0,
     };
     vec_add1(path_1_1_1_2.frp_label_stack, 501);
     vec_add1(paths_1_1_1_2, path_1_1_1_2);
-    const bier_fmask_id_t bfm_id_1_1_1_2 = {
-        .bfmi_hdr_type = BIER_HDR_O_MPLS,
-        .bfmi_nh = nh_1_1_1_2,
-    };
     index_t bei_3;
 
     mpls_label_t *out_lbl_101 = NULL;
@@ -547,7 +536,7 @@ bier_test_mpls_spf (void)
                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
                                     &neos_dpo_1_1_1_2);
 
-    bfmi_1_1_1_2 = bier_fmask_db_find(bti, &bfm_id_1_1_1_2);
+    bfmi_1_1_1_2 = bier_fmask_db_find(bti, &path_1_1_1_2);
     bfm_1_1_1_2 = bier_fmask_get(bfmi_1_1_1_2);
 
     BIER_TEST(!dpo_cmp(&neos_dpo_1_1_1_2,
@@ -563,12 +552,14 @@ bier_test_mpls_spf (void)
             .fmask = bfmi_1_1_1_2,
         },
     };
-    BIER_TEST(bier_test_validate_entry(bei_3, 1, &dpo_o_bfm_1_1_1_2),
-              "BP:3 stacks on fmask 1.1.1.2");
+    bier_entry_contribute_forwarding(bei_3, &dpo_bei);
+    BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_2),
+              "BP:2 stacks on fmask 1.1.1.2");
 
     /*
      * Load-balance BP:3 over both next-hops
      */
+    paths_1_1_1_1[0] = path_1_1_1_1;
     bier_table_route_add(&bt_0_0_0_256, 3, paths_1_1_1_1);
 
     BIER_TEST(bier_test_validate_entry(bei_3, 2,
@@ -589,13 +580,13 @@ bier_test_mpls_spf (void)
 
     /*
      * Withdraw one of the via FIB and thus bring down the fmask
-     * expect the bier0entry forwarding to remove this from the set
+     * expect the bier-entry forwarding to remove this from the set
      */
     fib_table_entry_delete(0, &pfx_1_1_1_2_s_32, FIB_SOURCE_API);
 
-    BIER_TEST(bier_test_validate_entry(bei_3, 1,
-                                       &dpo_o_bfm_1_1_1_1),
-              "BP:3 post 1.1.1.2 removal stacks on fmask 1.1.1.1");
+    bier_entry_contribute_forwarding(bei_3, &dpo_bei);
+    BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1),
+              "BP:3 stacks on fmask 1.1.1.1");
 
     BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[0].bier.table), 3) ==
                bfmi_1_1_1_1),
@@ -638,9 +629,10 @@ bier_test_mpls_spf (void)
      * remove the original 1.1.1.2 fmask from BP:3
      */
     bier_table_route_remove(&bt_0_0_0_256, 3, paths_1_1_1_2);
-    BIER_TEST(bier_test_validate_entry(bei_3, 1,
-                                       &dpo_o_bfm_1_1_1_1),
+    bier_entry_contribute_forwarding(bei_3, &dpo_bei);
+    BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1),
               "BP:3 stacks on fmask 1.1.1.1");
+
     /*
      * test that the ECMP choices for BP:3 have been updated
      */
@@ -659,7 +651,6 @@ bier_test_mpls_spf (void)
     bier_table_route_remove(&bt_0_0_0_256, 3, paths_1_1_1_1);
     bier_table_route_remove(&bt_0_0_0_256, 1, paths_1_1_1_1);
 
-
     /*
      * delete the table
      */
@@ -668,6 +659,7 @@ bier_test_mpls_spf (void)
     /*
      * test resources are freed
      */
+    dpo_reset(&dpo_bei);
     for (ii = 0; ii < N_BIER_ECMP_TABLES; ii++)
     {
         bier_table_ecmp_unlock(l_o_bt[ii].bier.table);
@@ -769,10 +761,6 @@ bier_test_mpls_imp (void)
 static int
 bier_test_mpls_disp (void)
 {
-    /* test_main_t *tm; */
-
-    /* tm = &test_main; */
-
     /*
      * Add the BIER Main table
      */
@@ -801,8 +789,9 @@ bier_test_mpls_disp (void)
      */
     fib_route_path_t *paths_via_disp = NULL, path_via_disp = {
         // .frp_addr = all-zeros
+        .frp_proto = DPO_PROTO_BIER,
         .frp_bier_fib_index = bdti1,
-        .frp_flags = FIB_ROUTE_PATH_BIER_FMASK,
+        .frp_sw_if_index = ~0,
     };
     vec_add1(paths_via_disp, path_via_disp);
 
@@ -811,16 +800,13 @@ bier_test_mpls_disp (void)
     /*
      * the fmask should stack on the BIER disp table
      */
-    const bier_fmask_id_t bfm_id_0_0_0_0 = {
-        .bfmi_hdr_type = BIER_HDR_O_MPLS,
-    };
     bier_fmask_t *bfm_0_0_0_0;
     index_t bfmi_0_0_0_0;
     dpo_id_t dpo_disp_tbl_1 = DPO_INVALID;
 
     bier_disp_table_contribute_forwarding(bdti1, &dpo_disp_tbl_1);
 
-    bfmi_0_0_0_0 = bier_fmask_db_find(bti, &bfm_id_0_0_0_0);
+    bfmi_0_0_0_0 = bier_fmask_db_find(bti, &path_via_disp);
     bfm_0_0_0_0 = bier_fmask_get(bfmi_0_0_0_0);
 
     BIER_TEST(!dpo_cmp(&dpo_disp_tbl_1, &bfm_0_0_0_0->bfm_dpo),
@@ -842,21 +828,13 @@ bier_test_mpls_disp (void)
                                    BIER_HDR_PROTO_IPV4, rpaths);
 
     /* which should stack on a lookup in the mfib table */
-    const dpo_id_t *dpo_disp_entry_lb;
     const dpo_id_t *dpo_disp_entry_v4;
     bier_disp_entry_t *bde_99;
     index_t bdei;
 
     bdei = bier_disp_table_lookup(bdti1, clib_host_to_net_u16(src));
     bde_99 = bier_disp_entry_get(bdei);
-    dpo_disp_entry_lb = &bde_99->bde_fwd[BIER_HDR_PROTO_IPV4].bde_dpo;
-
-    BIER_TEST(dpo_disp_entry_lb->dpoi_type == DPO_LOAD_BALANCE,
-              "BIER Disp entry stacks on LB");
-
-    load_balance_t *lb;
-    lb = load_balance_get(dpo_disp_entry_lb->dpoi_index);
-    dpo_disp_entry_v4 = load_balance_get_bucket_i(lb, 0);
+    dpo_disp_entry_v4 = &bde_99->bde_fwd[BIER_HDR_PROTO_IPV4].bde_dpo;
 
     lookup_dpo_t *lkd = lookup_dpo_get(dpo_disp_entry_v4->dpoi_index);
 
index 680182d..5c812a4 100644 (file)
@@ -160,6 +160,35 @@ bier_hdr_proto_to_dpo (bier_hdr_proto_id_t bproto)
     return (DPO_PROTO_NUM);
 }
 
+bier_bift_id_t
+bier_bift_id_encode (bier_table_set_id_t set,
+                     bier_table_sub_domain_id_t sd,
+                     bier_hdr_len_id_t bsl)
+{
+    bier_bift_id_t id;
+
+    id = bsl;
+    id = id << 8;
+    id |= sd;
+    id = id << 8;
+    id |= set;
+
+    return (id);
+}
+
+void
+bier_bift_id_decode (bier_bift_id_t id,
+                     bier_table_set_id_t *set,
+                     bier_table_sub_domain_id_t *sd,
+                     bier_hdr_len_id_t *bsl)
+{
+    *set = id & 0xff;
+    id = id >> 8;
+    *sd = id & 0xff;
+    id = id >> 8;
+    *bsl = id;
+}
+
 u8 *
 format_bier_table_id (u8 *s, va_list *ap)
 {
@@ -188,3 +217,17 @@ format_bier_hdr (u8 *s, va_list *ap)
                    format_bier_hdr_proto, bier_hdr_get_proto_id(&copy),
                    bier_hdr_get_src_id(&copy)));
 }
+
+ u8*
+ format_bier_bift_id(u8 *s, va_list *ap)
+ {
+     bier_bift_id_t id = va_arg(*ap, bier_bift_id_t);
+     bier_table_sub_domain_id_t sd;
+     bier_table_set_id_t set;
+     bier_hdr_len_id_t bsl;
+
+     bier_bift_id_decode(id, &set, &sd, &bsl);
+
+     return (format(s, "0x%x -> set:%d sd:%d hdr-len:%U",
+                    id, set, sd, format_bier_hdr_len_id, bsl));
+ }
index fa1cd42..d484ba9 100644 (file)
@@ -504,4 +504,32 @@ extern u32 bier_hdr_len_id_to_prefix_len(bier_hdr_len_id_t id);
 #define BIER_ERR_PANIC 3
 typedef int bier_rc;
 
+/**
+ * The BIER universal 'label'
+ */
+typedef u32 bier_bift_id_t;
+
+/**
+ * An invalid value for the BIFT ID
+ * all ones implies a BSL that's invalid.
+ */
+#define BIER_BIFT_ID_INVALID (~0)
+
+extern u16 bier_bfit_id_get_sub_domain(bier_bift_id_t bift_id);
+extern u16 bier_bfit_id_get_set(bier_bift_id_t bift_id);
+extern bier_hdr_proto_id_t bier_bift_id_get_bit_string_length(bier_bift_id_t bift_id);
+
+/**
+ * Encode a BIFT-ID as per draft-wijnandsxu-bier-non-mpls-bift-encoding-00.txt
+ */
+extern bier_bift_id_t bier_bift_id_encode(bier_table_set_id_t set,
+                                          bier_table_sub_domain_id_t sd,
+                                          bier_hdr_len_id_t bsl);
+extern void bier_bift_id_decode(bier_bift_id_t id,
+                                bier_table_set_id_t *set,
+                                bier_table_sub_domain_id_t *sd,
+                                bier_hdr_len_id_t *bsl);
+
+extern u8* format_bier_bift_id(u8 *s, va_list *ap);
+
 #endif /* __BIER_TYPES_H__ */
index c66090f..326f8bf 100644 (file)
@@ -32,6 +32,8 @@ vnet_bier_table_cmd (vlib_main_t * vm,
     };
     u32 is_add = 0;
 
+    local_label = MPLS_LABEL_INVALID;
+
     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
         if (unformat (input, "del")) {
             is_add = 0;
@@ -66,7 +68,7 @@ done:
 
 VLIB_CLI_COMMAND (bier_table_command) = {
   .path = "bier table",
-  .short_help = "Add/delete BIER Tables",
+  .short_help = "bier table [add|del] sd <sub-domain> set <SET> bsl <bit-string-length> [mpls <label>]",
   .function = vnet_bier_table_cmd,
 };
 
@@ -81,6 +83,7 @@ vnet_bier_route_cmd (vlib_main_t * vm,
     };
     u32 hdr_len, payload_proto;
     bier_table_id_t bti = {
+        .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
     };
     bier_bp_t bp;
     u32 add = 1;
@@ -90,6 +93,8 @@ vnet_bier_route_cmd (vlib_main_t * vm,
     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
         if (unformat (input, "del")) {
             add = 0;
+        } else if (unformat (input, "add")) {
+            add = 1;
         } else if (unformat (input, "sd %d", &bti.bti_sub_domain)) {
         } else if (unformat (input, "set %d", &bti.bti_set)) {
         } else if (unformat (input, "bsl %d", &hdr_len)) {
@@ -110,11 +115,11 @@ vnet_bier_route_cmd (vlib_main_t * vm,
 
     if (add)
     {
-        bier_table_route_add(&bti, bp, &brp);
+        bier_table_route_add(&bti, bp, brps);
     }
     else
     {
-        bier_table_route_remove(&bti, bp, &brp);
+        bier_table_route_remove(&bti, bp, brps);
     }
 
 done:
@@ -124,7 +129,7 @@ done:
 
 VLIB_CLI_COMMAND (bier_route_command) = {
   .path = "bier route",
-  .short_help = "bier route sd <sud-domain> set <set> bsl <bit-string-length> bp <bit-position> via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]",
+  .short_help = "bier route [add|del] sd <sud-domain> set <set> bsl <bit-string-length> bp <bit-position> via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]",
   .function = vnet_bier_route_cmd,
 };
 
index 50b94f7..8cb5545 100644 (file)
@@ -92,7 +92,6 @@ _(map)                                                \
 _(map_t)                                       \
 _(ip_frag)                                     \
 _(mpls)                                                \
-_(bier)                                        \
 _(tcp)
 
 /*
@@ -168,18 +167,17 @@ typedef struct
       u8 ttl;
       u8 exp;
       u8 first;
+      /*
+       * BIER - the nubmer of bytes in the header.
+       *  the len field inthe header is not authoritative. It's the
+       * value in the table that counts.
+       */
+      struct
+      {
+       u8 n_bytes;
+      } bier;
     } mpls;
 
-    /*
-     * BIER - the nubmer of bytes in the header.
-     *  the len field inthe header is not authoritative. It's the
-     * value in the table that counts.
-     */
-    struct
-    {
-      u8 n_bytes;
-    } bier;
-
     /* ip4-in-ip6 softwire termination, only valid there */
     struct
     {
index 8074555..db0ebcd 100644 (file)
@@ -198,6 +198,16 @@ load_balance_create (u32 n_buckets,
     return (load_balance_get_index(load_balance_create_i(n_buckets, lb_proto, fhc)));
 }
 
+u16
+load_balance_n_buckets (index_t lbi)
+{
+    load_balance_t *lb;
+
+    lb = load_balance_get(lbi);
+
+    return (lb->lb_n_buckets);
+}
+
 static inline void
 load_balance_set_bucket_i (load_balance_t *lb,
                            u32 bucket,
index b901c5b..d37f07d 100644 (file)
@@ -182,6 +182,7 @@ extern u8* format_load_balance(u8 * s, va_list * args);
 extern const dpo_id_t *load_balance_get_bucket(index_t lbi,
                                               u32 bucket);
 extern int load_balance_is_drop(const dpo_id_t *dpo);
+extern u16 load_balance_n_buckets(index_t lbi);
 
 extern f64 load_balance_get_multipath_tolerance(void);
 
index 214dafe..1d73af3 100644 (file)
@@ -1321,6 +1321,7 @@ fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
            fib_path_list_contribute_forwarding(
                esrc->fes_pl,
                fib_entry_get_default_chain_type(fib_entry),
+                FIB_PATH_LIST_FWD_FLAG_NONE,
                dpo);
 
            return (dpo_id_is_valid(dpo));
index c6677fb..8d738c2 100644 (file)
@@ -41,6 +41,7 @@
 #include <vnet/bier/bier_fmask.h>
 #include <vnet/bier/bier_table.h>
 #include <vnet/bier/bier_imp.h>
+#include <vnet/bier/bier_disp_table.h>
 
 /**
  * Enurmeration of path types
@@ -286,13 +287,9 @@ typedef struct fib_path_t_ {
        } recursive;
        struct {
             /**
-             * The next-hop
+             * BIER FMask ID
              */
-            ip46_address_t fp_nh;
-            /**
-             * The BIER FIB the fmask is in
-             */
-            index_t fp_bier_fib;
+            index_t fp_bier_fmask;
        } bier_fmask;
        struct {
             /**
@@ -368,14 +365,14 @@ typedef struct fib_path_t_ {
          * of the path's hash.
          */
         fib_node_index_t fp_via_fib;
-        /**
-         * the resolving bier-fmask
-         */
-        index_t fp_via_bier_fmask;
         /**
          * the resolving bier-table
          */
         index_t fp_via_bier_tbl;
+        /**
+         * the resolving bier-fmask
+         */
+        index_t fp_via_bier_fmask;
     };
 
     /**
@@ -409,8 +406,8 @@ static fib_path_t *fib_path_pool;
 {                                                              \
     u8 *_tmp = NULL;                                           \
     _tmp = fib_path_format(fib_path_get_index(_p), _tmp);      \
-    clib_warning("path:[%d:%s]:" _fmt,                         \
-                fib_path_get_index(_p), _tmp,                  \
+    clib_warning("path:[%d:%U]:" _fmt,                         \
+                fib_path_get_index(_p), format_fib_path, _p, 0,\
                 ##_args);                                      \
     vec_free(_tmp);                                            \
 }
@@ -446,12 +443,17 @@ fib_path_from_fib_node (fib_node_t *node)
 u8 *
 format_fib_path (u8 * s, va_list * args)
 {
-    fib_path_t *path = va_arg (*args, fib_path_t *);
+    fib_node_index_t path_index = va_arg (*args, fib_node_index_t);
+    u32 indent = va_arg (*args, u32);
     vnet_main_t * vnm = vnet_get_main();
     fib_path_oper_attribute_t oattr;
     fib_path_cfg_attribute_t cattr;
+    fib_path_t *path;
 
-    s = format (s, "      index:%d ", fib_path_get_index(path));
+    path = fib_path_get(path_index);
+
+    s = format (s, "%Upath:[%d] ", format_white_space, indent,
+                fib_path_get_index(path));
     s = format (s, "pl-index:%d ", path->fp_pl_index);
     s = format (s, "%U ", format_dpo_proto, path->fp_nh_proto);
     s = format (s, "weight=%d ", path->fp_weight);
@@ -473,7 +475,7 @@ format_fib_path (u8 * s, va_list * args)
            }
        }
     }
-    s = format(s, "\n       ");
+    s = format(s, "\n%U", format_white_space, indent+2);
 
     switch (path->fp_type)
     {
@@ -501,19 +503,20 @@ format_fib_path (u8 * s, va_list * args)
        }
        if (!dpo_id_is_valid(&path->fp_dpo))
        {
-           s = format(s, "\n          unresolved");
+           s = format(s, "\n%Uunresolved", format_white_space, indent+2);
        }
        else
        {
-           s = format(s, "\n          %U",
-                      format_dpo_id,
+           s = format(s, "\n%U%U",
+                      format_white_space, indent,
+                       format_dpo_id,
                       &path->fp_dpo, 13);
        }
        break;
     case FIB_PATH_TYPE_ATTACHED:
        if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_DROP)
        {
-           s = format (s, " if_index:%d", path->attached_next_hop.fp_interface);
+           s = format (s, "if_index:%d", path->attached_next_hop.fp_interface);
        }
        else
        {
@@ -551,7 +554,7 @@ format_fib_path (u8 * s, va_list * args)
 
        break;
     case FIB_PATH_TYPE_UDP_ENCAP:
-        s = format (s, " UDP-encap ID:%d", path->udp_encap.fp_udp_encap_id);
+        s = format (s, "UDP-encap ID:%d", path->udp_encap.fp_udp_encap_id);
         break;
     case FIB_PATH_TYPE_BIER_TABLE:
         s = format (s, "via bier-table:[%U}",
@@ -562,14 +565,7 @@ format_fib_path (u8 * s, va_list * args)
                     path->fp_dpo.dpoi_index);
         break;
     case FIB_PATH_TYPE_BIER_FMASK:
-        s = format (s, "via %U",
-                    format_ip46_address,
-                    &path->bier_fmask.fp_nh,
-                    IP46_TYPE_ANY);
-       s = format (s, " in BIER-fib:%d",
-                   path->bier_fmask.fp_bier_fib,
-                   path->fp_via_fib); 
-       s = format (s, " via-fmask:%d", path->fp_via_bier_fmask); 
+       s = format (s, "via-fmask:%d", path->bier_fmask.fp_bier_fmask); 
        s = format (s, " via-dpo:[%U:%d]",
                    format_dpo_type, path->fp_dpo.dpoi_type, 
                    path->fp_dpo.dpoi_index);
@@ -586,7 +582,7 @@ format_fib_path (u8 * s, va_list * args)
        if (dpo_id_is_valid(&path->fp_dpo))
        {
            s = format(s, "%U", format_dpo_id,
-                      &path->fp_dpo, 2);
+                      &path->fp_dpo, indent+2);
        }
        break;
     }
@@ -604,29 +600,6 @@ fib_path_format (fib_node_index_t pi, u8 *s)
     return (format (s, "%U", format_fib_path, path));
 }
 
-u8 *
-fib_path_adj_format (fib_node_index_t pi,
-                    u32 indent,
-                    u8 *s)
-{
-    fib_path_t *path;
-
-    path = fib_path_get(pi);
-    ASSERT(NULL != path);
-
-    if (!dpo_id_is_valid(&path->fp_dpo))
-    {
-       s = format(s, " unresolved");
-    }
-    else
-    {
-       s = format(s, "%U", format_dpo_id,
-                  &path->fp_dpo, 2);
-    }
-
-    return (s);
-}
-
 /*
  * fib_path_last_lock_gone
  *
@@ -832,7 +805,7 @@ static void
 fib_path_bier_fmask_update (fib_path_t *path,
                             dpo_id_t *dpo)
 {
-    bier_fmask_contribute_forwarding(path->fp_via_bier_fmask, dpo);
+    bier_fmask_contribute_forwarding(path->bier_fmask.fp_bier_fmask, dpo);
 
     /*
      * if we are stakcing on the drop, then the path is not resolved
@@ -893,12 +866,8 @@ fib_path_unresolve (fib_path_t *path)
        }
        break;
     case FIB_PATH_TYPE_BIER_FMASK:
-       if (FIB_NODE_INDEX_INVALID != path->fp_via_bier_fmask)
-       {
-           bier_fmask_child_remove(path->fp_via_bier_fmask,
-                                    path->fp_sibling);
-           path->fp_via_bier_fmask = FIB_NODE_INDEX_INVALID;
-       }
+        bier_fmask_child_remove(path->fp_via_bier_fmask,
+                                path->fp_sibling);
        break;
     case FIB_PATH_TYPE_BIER_IMP:
         bier_imp_unlock(path->fp_dpo.dpoi_index);
@@ -1313,8 +1282,7 @@ fib_path_create (fib_node_index_t pl_index,
     else if (rpath->frp_flags & FIB_ROUTE_PATH_BIER_FMASK)
     {
         path->fp_type = FIB_PATH_TYPE_BIER_FMASK;
-        path->bier_fmask.fp_nh = rpath->frp_addr;
-        path->bier_fmask.fp_bier_fib = rpath->frp_bier_fib_index;
+        path->bier_fmask.fp_bier_fmask = rpath->frp_bier_fmask;
     }
     else if (rpath->frp_flags & FIB_ROUTE_PATH_BIER_IMP)
     {
@@ -1549,14 +1517,8 @@ fib_path_cmp_i (const fib_path_t *path1,
            }
            break;
        case FIB_PATH_TYPE_BIER_FMASK:
-           res = ip46_address_cmp(&path1->bier_fmask.fp_nh,
-                                  &path2->bier_fmask.fp_nh);
-           if (0 == res)
-           {
-               res = (path1->bier_fmask.fp_bier_fib -
-                       path2->bier_fmask.fp_bier_fib);
-           }
+            res = (path1->bier_fmask.fp_bier_fmask -
+                   path2->bier_fmask.fp_bier_fmask);
            break;
        case FIB_PATH_TYPE_BIER_IMP:
             res = (path1->bier_imp.fp_bier_imp -
@@ -1691,13 +1653,7 @@ fib_path_cmp_w_route_path (fib_node_index_t path_index,
             }
            break;
        case FIB_PATH_TYPE_BIER_FMASK:
-            res = ip46_address_cmp(&path->bier_fmask.fp_nh,
-                                   &rpath->frp_addr);
-
-            if (0 == res)
-            {
-                res = (path->bier_fmask.fp_bier_fib - rpath->frp_bier_fib_index);
-            }
+            res = (path->bier_fmask.fp_bier_fmask - rpath->frp_bier_fmask);
            break;
        case FIB_PATH_TYPE_BIER_IMP:
             res = (path->bier_imp.fp_bier_imp - rpath->frp_bier_imp);
@@ -1943,27 +1899,15 @@ fib_path_resolve (fib_node_index_t path_index)
     }
     case FIB_PATH_TYPE_BIER_FMASK:
     {
-        /*
-         * Find the BIER f-mask to link to
-         */
-        bier_fmask_id_t fmid = {
-            .bfmi_nh = path->bier_fmask.fp_nh,
-            .bfmi_hdr_type = BIER_HDR_O_MPLS,
-        };
-
-        ASSERT(FIB_NODE_INDEX_INVALID == path->fp_via_bier_fmask);
-
-        path->fp_via_bier_fmask = bier_fmask_db_find(path->bier_fmask.fp_bier_fib,
-                                                &fmid);
-
         /*
          * become a dependent child of the entry so the path is
          * informed when the forwarding for the entry changes.
          */
-        path->fp_sibling = bier_fmask_child_add(path->fp_via_bier_fmask,
+        path->fp_sibling = bier_fmask_child_add(path->bier_fmask.fp_bier_fmask,
                                                 FIB_NODE_TYPE_PATH,
                                                 fib_path_get_index(path));
 
+        path->fp_via_bier_fmask = path->bier_fmask.fp_bier_fmask;
         fib_path_bier_fmask_update(path, &path->fp_dpo);
 
         break;
@@ -1996,27 +1940,35 @@ fib_path_resolve (fib_node_index_t path_index)
        break;
     case FIB_PATH_TYPE_DEAG:
     {
-       /*
-        * Resolve via a lookup DPO.
-         * FIXME. control plane should add routes with a table ID
-        */
-        lookup_input_t input;
-        lookup_cast_t cast;
-
-        cast = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID ?
-                LOOKUP_MULTICAST :
-                LOOKUP_UNICAST);
-        input = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DEAG_SRC ?
-                LOOKUP_INPUT_SRC_ADDR :
-                LOOKUP_INPUT_DST_ADDR);
-
-        lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id,
-                                           path->fp_nh_proto,
-                                           cast,
-                                           input,
-                                           LOOKUP_TABLE_FROM_CONFIG,
-                                           &path->fp_dpo);
-       break;
+        if (DPO_PROTO_BIER == path->fp_nh_proto)
+        {
+            bier_disp_table_contribute_forwarding(path->deag.fp_tbl_id,
+                                                  &path->fp_dpo);
+        }
+        else
+        {
+            /*
+             * Resolve via a lookup DPO.
+             * FIXME. control plane should add routes with a table ID
+             */
+            lookup_input_t input;
+            lookup_cast_t cast;
+
+            cast = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID ?
+                    LOOKUP_MULTICAST :
+                    LOOKUP_UNICAST);
+            input = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DEAG_SRC ?
+                     LOOKUP_INPUT_SRC_ADDR :
+                     LOOKUP_INPUT_DST_ADDR);
+
+            lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id,
+                                               path->fp_nh_proto,
+                                               cast,
+                                               input,
+                                               LOOKUP_TABLE_FROM_CONFIG,
+                                               &path->fp_dpo);
+        }
+        break;
     }
     case FIB_PATH_TYPE_RECEIVE:
        /*
@@ -2109,7 +2061,7 @@ fib_path_get_resolving_index (fib_node_index_t path_index)
     case FIB_PATH_TYPE_RECURSIVE:
        return (path->fp_via_fib);
     case FIB_PATH_TYPE_BIER_FMASK:
-       return (path->fp_via_bier_fmask);
+       return (path->bier_fmask.fp_bier_fmask);
    case FIB_PATH_TYPE_BIER_TABLE:
        return (path->fp_via_bier_tbl);
    case FIB_PATH_TYPE_BIER_IMP:
@@ -2623,8 +2575,7 @@ fib_path_encode (fib_node_index_t path_list_index,
         api_rpath->rpath.frp_addr = path->attached_next_hop.fp_nh;
         break;
       case FIB_PATH_TYPE_BIER_FMASK:
-        api_rpath->rpath.frp_fib_index = path->bier_fmask.fp_bier_fib;
-        api_rpath->rpath.frp_addr = path->bier_fmask.fp_nh;
+        api_rpath->rpath.frp_bier_fmask = path->bier_fmask.fp_bier_fmask;
         break;
       case FIB_PATH_TYPE_SPECIAL:
         break;
@@ -2673,7 +2624,7 @@ show_fib_path_command (vlib_main_t * vm,
        if (!pool_is_free_index(fib_path_pool, pi))
        {
            path = fib_path_get(pi);
-           u8 *s = fib_path_format(pi, NULL);
+           u8 *s = format(NULL, "%U", format_fib_path, pi, 1);
            s = format(s, "children:");
            s = fib_node_children_format(path->fp_node.fn_children, s);
            vlib_cli_output (vm, "%s", s);
index 861bda9..70b2f50 100644 (file)
@@ -128,12 +128,7 @@ typedef enum fib_path_cfg_flags_t_ {
 } __attribute__ ((packed)) fib_path_cfg_flags_t;
 
 
-extern u8 *fib_path_format(fib_node_index_t pi, u8 *s);
-extern u8 *fib_path_adj_format(fib_node_index_t pi,
-                              u32 indent,
-                              u8 *s);
-
-extern u8 * format_fib_path(u8 * s, va_list * args);
+extern u8 *format_fib_path(u8 *s, va_list *args);
 
 extern fib_node_index_t fib_path_create(fib_node_index_t pl_index,
                                        const fib_route_path_t *path);
index 597a700..5201b5a 100644 (file)
@@ -126,16 +126,21 @@ fib_path_list_get_index (fib_path_list_t *path_list)
     return (path_list - fib_path_list_pool);
 }
 
-static u8 *
+u8 *
 format_fib_path_list (u8 * s, va_list * args)
 {
+    fib_node_index_t *path_index, path_list_index;
     fib_path_list_attribute_t attr;
-    fib_node_index_t *path_index;
     fib_path_list_t *path_list;
+    u32 indent;
 
-    path_list = va_arg (*args, fib_path_list_t *);
-    
-    s = format (s, "    index:%u", fib_path_list_get_index(path_list));
+    path_list_index = va_arg (*args, fib_node_index_t);
+    indent = va_arg (*args, u32);
+    path_list = fib_path_list_get(path_list_index);
+
+    s = format (s, "%Upath-list:[%d]",
+                format_white_space, indent,
+                fib_path_list_get_index(path_list));
     s = format (s, " locks:%u", path_list->fpl_node.fn_locks);
 
     if (FIB_PATH_LIST_FLAG_NONE != path_list->fpl_flags)
@@ -153,7 +158,7 @@ format_fib_path_list (u8 * s, va_list * args)
 
     vec_foreach (path_index, path_list->fpl_paths)
     {
-       s = fib_path_format(*path_index, s);
+       s = format(s, "%U", format_fib_path, *path_index, indent+2);
        s = format(s, "\n");
     }
 
@@ -164,11 +169,7 @@ u8 *
 fib_path_list_format (fib_node_index_t path_list_index,
                      u8 * s)
 {
-    fib_path_list_t *path_list;
-
-    path_list = fib_path_list_get(path_list_index);
-
-    return (format(s, "%U", format_fib_path_list, path_list));
+    return (format(s, "%U", format_fib_path_list, path_list_index, 4));
 }
 
 static uword
@@ -353,20 +354,7 @@ fib_path_list_mk_lb (fib_path_list_t *path_list,
     load_balance_path_t *nhs;
     fib_node_index_t *path_index;
 
-    nhs  = NULL;
-
-    if (!dpo_id_is_valid(dpo))
-    {
-        /*
-         * first time create
-         */
-        dpo_set(dpo,
-                DPO_LOAD_BALANCE,
-                fib_forw_chain_type_to_dpo_proto(fct),
-                load_balance_create(0,
-                                   fib_forw_chain_type_to_dpo_proto(fct),
-                                   0 /* FIXME FLOW HASH */));
-    }
+    nhs = NULL;
 
     /*
      * We gather the DPOs from resolved paths.
@@ -382,6 +370,12 @@ fib_path_list_mk_lb (fib_path_list_t *path_list,
      * Path-list load-balances, which if used, would be shared and hence
      * never need a load-balance map.
      */
+    dpo_set(dpo,
+            DPO_LOAD_BALANCE,
+            fib_forw_chain_type_to_dpo_proto(fct),
+            load_balance_create(vec_len(nhs),
+                                fib_forw_chain_type_to_dpo_proto(fct),
+                                0 /* FIXME FLOW HASH */));
     load_balance_multipath_update(dpo, nhs, LOAD_BALANCE_FLAG_NONE);
 
     FIB_PATH_LIST_DBG(path_list, "mk lb: %d", dpo->dpoi_index);
@@ -1146,6 +1140,7 @@ fib_path_list_copy_and_path_remove (fib_node_index_t orig_path_list_index,
 void
 fib_path_list_contribute_forwarding (fib_node_index_t path_list_index,
                                     fib_forward_chain_type_t fct,
+                                     fib_path_list_fwd_flags_t flags,
                                     dpo_id_t *dpo)
 {
     fib_path_list_t *path_list;
@@ -1153,6 +1148,18 @@ fib_path_list_contribute_forwarding (fib_node_index_t path_list_index,
     path_list = fib_path_list_get(path_list_index);
 
     fib_path_list_mk_lb(path_list, fct, dpo);
+
+    ASSERT(DPO_LOAD_BALANCE == dpo->dpoi_type);
+
+    /*
+     * If there's only one bucket in the load-balance then we can
+     * squash it out.
+     */
+    if ((1 == load_balance_n_buckets(dpo->dpoi_index)) &&
+        (FIB_PATH_LIST_FWD_FLAG_COLLAPSE & flags))
+    {
+        dpo_copy(dpo, load_balance_get_bucket(dpo->dpoi_index, 0));
+    }
 }
 
 /*
index a54b79e..76870dc 100644 (file)
@@ -127,8 +127,18 @@ extern fib_node_index_t fib_path_list_path_remove (
 
 extern u32 fib_path_list_get_n_paths(fib_node_index_t pl_index);
 
+/**
+ * Flags to control how the path-list returns forwarding information
+ */
+typedef enum fib_path_list_fwd_flags_t_
+{
+    FIB_PATH_LIST_FWD_FLAG_NONE = 0,
+    FIB_PATH_LIST_FWD_FLAG_COLLAPSE = (1 << 0),
+} fib_path_list_fwd_flags_t;
+
 extern void fib_path_list_contribute_forwarding(fib_node_index_t path_list_index,
                                                fib_forward_chain_type_t type,
+                                                fib_path_list_fwd_flags_t flags,
                                                dpo_id_t *dpo);
 extern void fib_path_list_contribute_urpf(fib_node_index_t path_index,
                                          index_t urpf);
@@ -153,6 +163,8 @@ extern int fib_path_list_is_popular(fib_node_index_t path_list_index);
 extern dpo_proto_t fib_path_list_get_proto(fib_node_index_t path_list_index);
 extern u8 * fib_path_list_format(fib_node_index_t pl_index,
                                 u8 * s);
+extern u8 * format_fib_path_list(u8 * s, va_list *args);
+
 extern index_t fib_path_list_lb_map_add_or_lock(fib_node_index_t pl_index,
                                                 const fib_node_index_t *pis);
 extern u32 fib_path_list_find_rpath (fib_node_index_t path_list_index,
index be6a24e..94c9422 100644 (file)
@@ -443,6 +443,11 @@ typedef struct fib_route_path_t_ {
          * UDP encap ID
          */
         u32 frp_udp_encap_id;
+
+        /**
+         * Resolving via a BIER Fmask
+         */
+        index_t frp_bier_fmask;
     };
     /**
      * [un]equal cost path weight
index 7ed2e12..ca1e320 100644 (file)
@@ -787,6 +787,7 @@ lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
     {
       fib_path_list_contribute_forwarding (lfe->l2.path_list_index,
                                           FIB_FORW_CHAIN_TYPE_ETHERNET,
+                                          FIB_PATH_LIST_FWD_FLAG_NONE,
                                           &lfe->l2.dpo);
       dpo_copy (&dpo, &lfe->l2.dpo);
     }
@@ -1048,6 +1049,7 @@ lisp_gpe_nsh_update_fwding (lisp_gpe_fwd_entry_t * lfe)
     {
       fib_path_list_contribute_forwarding (lfe->nsh.path_list_index,
                                           FIB_FORW_CHAIN_TYPE_NSH,
+                                          FIB_PATH_LIST_FWD_FLAG_NONE,
                                           &lfe->nsh.dpo);
 
       /*
index e0874cd..0dc12b8 100644 (file)
@@ -24,9 +24,6 @@ typedef struct {
   /* Adjacency taken. */
   u32 adj_index;
   u32 flow_hash;
-
-  /* Packet data, possibly *after* rewrite. */
-  u8 packet_data[64 - 1*sizeof(u32)];
 } mpls_output_trace_t;
 
 #define foreach_mpls_output_next               \
@@ -45,16 +42,11 @@ format_mpls_output_trace (u8 * s, va_list * args)
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
   mpls_output_trace_t * t = va_arg (*args, mpls_output_trace_t *);
-  u32 indent = format_get_indent (s);
 
   s = format (s, "adj-idx %d : %U flow hash: 0x%08x",
               t->adj_index,
               format_ip_adjacency, t->adj_index, FORMAT_IP_ADJACENCY_NONE,
              t->flow_hash);
-  s = format (s, "\n%U%U",
-              format_white_space, indent,
-              format_ip_adjacency_packet_data,
-              t->adj_index, t->packet_data, sizeof (t->packet_data));
   return s;
 }
 
@@ -206,9 +198,6 @@ mpls_output_inline (vlib_main_t * vm,
                                                         p0, sizeof (*tr));
               tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX];
               tr->flow_hash = vnet_buffer(p0)->ip.flow_hash;
-              clib_memcpy (tr->packet_data,
-                           vlib_buffer_get_current (p0),
-                           sizeof (tr->packet_data));
             }
           if (PREDICT_FALSE(p1->flags & VLIB_BUFFER_IS_TRACED))
             {
@@ -216,9 +205,6 @@ mpls_output_inline (vlib_main_t * vm,
                                                         p1, sizeof (*tr));
               tr->adj_index = vnet_buffer(p1)->ip.adj_index[VLIB_TX];
               tr->flow_hash = vnet_buffer(p1)->ip.flow_hash;
-              clib_memcpy (tr->packet_data,
-                           vlib_buffer_get_current (p1),
-                           sizeof (tr->packet_data));
             }
 
           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
index 920ef96..af6c6b8 100644 (file)
@@ -72,6 +72,7 @@ _ (4342, lisp_cp6)                            \
 _ (4790, VXLAN6_GPE)                            \
 _ (6633, vpath6_3)                             \
 _ (6081, geneve6)                              \
+_ (8138, BIER)                                 \
 _ (53053, dns_reply6)
 
 typedef enum
index 2999d4a..91d730c 100644 (file)
@@ -392,6 +392,11 @@ const static char *const udp4_encap_mpls_nodes[] = {
   NULL,
 };
 
+const static char *const udp4_encap_bier_nodes[] = {
+  "udp4-encap",
+  NULL,
+};
+
 const static char *const udp6_encap_ip4_nodes[] = {
   "udp6-encap",
   NULL,
@@ -407,16 +412,23 @@ const static char *const udp6_encap_mpls_nodes[] = {
   NULL,
 };
 
+const static char *const udp6_encap_bier_nodes[] = {
+  "udp6-encap",
+  NULL,
+};
+
 const static char *const *const udp4_encap_nodes[DPO_PROTO_NUM] = {
   [DPO_PROTO_IP4] = udp4_encap_ip4_nodes,
   [DPO_PROTO_IP6] = udp4_encap_ip6_nodes,
   [DPO_PROTO_MPLS] = udp4_encap_mpls_nodes,
+  [DPO_PROTO_BIER] = udp4_encap_bier_nodes,
 };
 
 const static char *const *const udp6_encap_nodes[DPO_PROTO_NUM] = {
   [DPO_PROTO_IP4] = udp6_encap_ip4_nodes,
   [DPO_PROTO_IP6] = udp6_encap_ip6_nodes,
   [DPO_PROTO_MPLS] = udp6_encap_mpls_nodes,
+  [DPO_PROTO_BIER] = udp6_encap_bier_nodes,
 };
 
 /*
@@ -433,7 +445,6 @@ const static dpo_vft_t udp_encap_dpo_vft = {
   .dv_lock = udp_encap_dpo_lock,
   .dv_unlock = udp_encap_dpo_unlock,
   .dv_format = format_udp_encap_dpo,
-  //.dv_mem_show = replicate_mem_show,
 };
 
 clib_error_t *
index 024805d..50814d4 100644 (file)
@@ -3,7 +3,7 @@ new file mode 100644
 index 0000000..e173cdb
 --- /dev/null
 +++ b/scapy/contrib/bier.py
-@@ -0,0 +1,39 @@
+@@ -0,0 +1,53 @@
 +# http://trac.secdev.org/scapy/ticket/31
 +
 +# scapy.contrib.description = MPLS
@@ -11,7 +11,7 @@ index 0000000..e173cdb
 +
 +from scapy.packet import *
 +from scapy.fields import *
-+from scapy.layers.inet import IP
++from scapy.layers.inet import IP, UDP
 +from scapy.layers.inet6 import IPv6
 +
 +class BIERLength:
@@ -20,12 +20,25 @@ index 0000000..e173cdb
 +   BIER_LEN_256 = 2
 +
 +
-+
 +BIERnhcls = {  1: "MPLS",
 +               2: "MPLS",
 +               4: "IPv4",
 +               5: "IPv6" }
 +
++
++class BIFT(Packet):
++   name = "BIFT"
++   fields_desc =  [ BitField("bsl", 0, 4),
++                    BitField("sd", 0, 8),
++                    BitField("set", 0, 8),
++                    BitField("cos", 0, 3),
++                    BitField("s", 1, 1),
++                    ByteField("ttl", 0)  ]
++
++   def guess_payload_class(self, payload):
++      return BIER
++
++
 +class BIER(Packet):
 +   name = "BIER"
 +   fields_desc =  [ BitField("id", 5, 4),
@@ -43,3 +56,4 @@ index 0000000..e173cdb
 +
 +bind_layers(BIER, IP,   Proto=4)
 +bind_layers(BIER, IPv6, Proto=5)
++bind_layers(UDP, BIFT, dport=8138)
index 1a4567b..48d0a29 100644 (file)
@@ -8,6 +8,7 @@ from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
     VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \
     MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, DpoProto
 from vpp_bier import *
+from vpp_udp_encap import *
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether
@@ -78,6 +79,7 @@ class TestBier(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
         rx = output.get_capture(len(pkts))
+        return rx
 
     def test_bier_midpoint(self):
         """BIER midpoint"""
@@ -119,7 +121,9 @@ class TestBier(VppTestCase):
                                                       labels=[2000+i])]))
             nh_routes[-1].add_vpp_config()
 
-            bier_routes.append(VppBierRoute(self, bti, i, nh, 100+i))
+            bier_routes.append(VppBierRoute(self, bti, i,
+                                            [VppRoutePath(nh, 0xffffffff,
+                                                          labels=[100+i])]))
             bier_routes[-1].add_vpp_config()
 
         #
@@ -150,6 +154,7 @@ class TestBier(VppTestCase):
 
             blabel = olabel[MPLS].payload
             self.assertEqual(blabel.label, 100+bp)
+            self.assertEqual(blabel.ttl, 254)
 
             bier_hdr = blabel[MPLS].payload
 
@@ -203,8 +208,12 @@ class TestBier(VppTestCase):
         ip_route_1.add_vpp_config()
         ip_route_2.add_vpp_config()
 
-        bier_route_1 = VppBierRoute(self, bti, 1, nh1, 101)
-        bier_route_2 = VppBierRoute(self, bti, 2, nh2, 102)
+        bier_route_1 = VppBierRoute(self, bti, 1,
+                                    [VppRoutePath(nh1, 0xffffffff,
+                                                  labels=[101])])
+        bier_route_2 = VppBierRoute(self, bti, 2,
+                                    [VppRoutePath(nh2, 0xffffffff,
+                                                  labels=[102])])
         bier_route_1.add_vpp_config()
         bier_route_2.add_vpp_config()
 
@@ -231,7 +240,7 @@ class TestBier(VppTestCase):
         route_ing_232_1_1_1.add_vpp_config()
 
         #
-        # inject a packet an IP. We expect it to be BIER encapped,
+        # inject an IP packet. We expect it to be BIER encapped and
         # replicated.
         #
         p = (Ether(dst=self.pg0.local_mac,
@@ -245,6 +254,29 @@ class TestBier(VppTestCase):
 
         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"""
 
@@ -264,8 +296,10 @@ class TestBier(VppTestCase):
         #
         # BIER route in table that's for-us
         #
-        bier_route_1 = VppBierRoute(self, bti, 1, "0.0.0.0", 0,
-                                    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()
 
         #
@@ -344,9 +378,10 @@ class TestBier(VppTestCase):
         # BIER route in table that's for-us, resolving through
         # disp table 8.
         #
-        bier_route_1 = VppBierRoute(self, bti, 1, "0.0.0.0",
-                                    MPLS_LABEL_INVALID,
-                                    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()
 
         #
@@ -383,7 +418,155 @@ class TestBier(VppTestCase):
              IP(src="1.1.1.1", dst="232.1.1.1") /
              UDP(sport=1234, dport=1234))
 
-        self.send_and_expect(self.pg0, p*65, self.pg1)
+        rx = self.send_and_expect(self.pg0, p*65, self.pg1)
+
+        #
+        # should be IP
+        #
+        self.assertEqual(rx[0][IP].src, "1.1.1.1")
+        self.assertEqual(rx[0][IP].dst, "232.1.1.1")
+
+    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=[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 imposition object with all bit-positions set
+        #
+        bi = VppBierImp(self, bti, 333, chr(0xff) * 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 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,
+                                     "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, 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__':
index 58c4f72..328d4f0 100644 (file)
@@ -4,6 +4,7 @@
 
 import socket
 from vpp_object import VppObject
+from vpp_ip_route import MPLS_LABEL_INVALID, VppRoutePath
 
 
 class BIER_HDR_PAYLOAD:
@@ -18,7 +19,7 @@ class BIER_HDR_PAYLOAD:
 
 
 class VppBierTableID():
-    def __init__(self, set_id, sub_domain_id, hdr_len_id):
+    def __init__(self, sub_domain_id, set_id, hdr_len_id):
         self.set_id = set_id
         self.sub_domain_id = sub_domain_id
         self.hdr_len_id = hdr_len_id
@@ -113,22 +114,17 @@ class VppBierRoute(VppObject):
     BIER route
     """
 
-    def __init__(self, test, tbl_id, bp, nh, out_label,
-                 disp_table=0):
+    def __init__(self, test, tbl_id, bp, paths):
         self._test = test
         self.tbl_id = tbl_id
-        self.out_label = out_label
         self.bp = bp
-        self.disp_table = disp_table
-        self.nh = socket.inet_pton(socket.AF_INET, nh)
+        self.paths = paths
 
     def add_vpp_config(self):
         self._test.vapi.bier_route_add_del(
             self.tbl_id,
             self.bp,
-            self.nh,
-            self.out_label,
-            self.disp_table,
+            self.paths,
             is_add=1)
         self._test.registry.register(self, self._test.logger)
 
@@ -136,9 +132,7 @@ class VppBierRoute(VppObject):
         self._test.vapi.bier_route_add_del(
             self.tbl_id,
             self.bp,
-            self.nh,
-            self.out_label,
-            self.disp_table,
+            self.paths,
             is_add=0)
 
     def __str__(self):
index f8bca82..c4b1601 100644 (file)
@@ -2701,24 +2701,28 @@ class VppPapiProvider(object):
     def bier_route_add_del(self,
                            bti,
                            bp,
-                           next_hop,
-                           next_hop_label,
-                           next_hop_table_id,
-                           next_hop_is_ip4=1,
+                           paths,
                            is_add=1):
         """ BIER Route add/del """
+        br_paths = []
+        for p in paths:
+            br_paths.append({'next_hop': p.nh_addr,
+                             'weight': 1,
+                             'afi': 0,
+                             'preference': 0,
+                             'table_id': p.nh_table_id,
+                             'next_hop_id': p.next_hop_id,
+                             'is_udp_encap': p.is_udp_encap,
+                             'n_labels': len(p.nh_labels),
+                             'label_stack': p.nh_labels})
         return self.api(
             self.papi.bier_route_add_del,
             {'br_tbl_id': {"bt_set": bti.set_id,
                            "bt_sub_domain": bti.sub_domain_id,
                            "bt_hdr_len_id": bti.hdr_len_id},
              'br_bp': bp,
-             'br_n_paths': 1,
-             'br_paths': [{'next_hop': next_hop,
-                           'afi': 0,
-                           'n_labels': 1,
-                           'table_id': next_hop_table_id,
-                           'label_stack': [next_hop_label]}],
+             'br_n_paths': len(br_paths),
+             'br_paths': br_paths,
              'br_is_add': is_add})
 
     def bier_route_dump(self, bti):