fib: fib api updates
[vpp.git] / src / vnet / fib / fib_api.c
index 12c4f0d..5aa5c4e 100644 (file)
 #include <vnet/vnet.h>
 #include <vlibmemory/api.h>
 #include <vnet/fib/fib_api.h>
+#include <vnet/ip/ip_types_api.h>
 #include <vnet/fib/fib_table.h>
 #include <vnet/mfib/mfib_table.h>
 #include <vnet/bier/bier_disp_table.h>
-#include <vnet/dpo/ip_null_dpo.h>
+#include <vpp/api/types.h>
 
 #include <vnet/vnet_msg_enum.h>
 
 #include <vlibapi/api_helper_macros.h>
 
 int
-fib_path_api_parse (const vl_api_fib_path_t *in,
-                    fib_route_path_t *out)
+fib_api_table_id_decode (fib_protocol_t fproto,
+                         u32 table_id,
+                         u32 *fib_index)
 {
-    fib_route_path_flags_t path_flags;
-    mpls_label_t next_hop_via_label;
-    int rv = 0, n_labels;
-    u8 ii;
+    *fib_index = fib_table_find(fproto, table_id);
 
-    path_flags = FIB_ROUTE_PATH_FLAG_NONE;
-    next_hop_via_label = ntohl (in->via_label);
-    clib_memset(out, 0, sizeof(*out));
-    out->frp_sw_if_index = ~0;
+    if (INDEX_INVALID == *fib_index)
+    {
+        return VNET_API_ERROR_NO_SUCH_FIB;
+    }
 
-    out->frp_proto = in->afi;
-    // .frp_addr = (NULL == next_hop ? zero_addr : *next_hop),
-    out->frp_sw_if_index = ntohl(in->sw_if_index);
-    out->frp_weight = in->weight;
-    out->frp_preference = in->preference;
+    return (0);
+}
 
-    if (DPO_PROTO_IP4 == out->frp_proto ||
-        DPO_PROTO_IP6 == out->frp_proto ||
-        DPO_PROTO_MPLS == out->frp_proto)
-    {
-        out->frp_fib_index = fib_table_find (dpo_proto_to_fib(out->frp_proto),
-                                             ntohl (in->table_id));
+int
+fib_api_mtable_id_decode (fib_protocol_t fproto,
+                          u32 table_id,
+                          u32 *fib_index)
+{
+    *fib_index = mfib_table_find(fproto, table_id);
 
-        if (~0 == out->frp_fib_index)
-            return (VNET_API_ERROR_NO_SUCH_FIB);
+    if (~0 == *fib_index)
+    {
+        return VNET_API_ERROR_NO_SUCH_FIB;
     }
 
-    /*
-     * the special INVALID label means we are not recursing via a
-     * label. Exp-null value is never a valid via-label so that
-     * also means it's not a via-label and means clients that set
-     * it to 0 by default get the expected behaviour
-     */
-    if ((MPLS_LABEL_INVALID != next_hop_via_label) &&
-        (0 != next_hop_via_label))
+    return (0);
+}
+
+static void
+fib_api_next_hop_decode (const vl_api_fib_path_t *in,
+                         ip46_address_t *out)
+{
+    if (in->proto == FIB_API_PATH_NH_PROTO_IP4)
+        memcpy (&out->ip4, &in->nh.address.ip4, sizeof (out->ip4));
+    else if (in->proto == FIB_API_PATH_NH_PROTO_IP6)
+        memcpy (&out->ip6, &in->nh.address.ip6, sizeof (out->ip6));
+}
+
+static vl_api_fib_path_nh_proto_t
+fib_api_path_dpo_proto_to_nh (dpo_proto_t dproto)
+{
+    switch (dproto)
     {
-        out->frp_proto = DPO_PROTO_MPLS;
-        out->frp_local_label = next_hop_via_label;
-        out->frp_eos = MPLS_NON_EOS;
+    case DPO_PROTO_IP4:
+        return (FIB_API_PATH_NH_PROTO_IP4);
+    case DPO_PROTO_IP6:
+        return (FIB_API_PATH_NH_PROTO_IP6);
+    case DPO_PROTO_MPLS:
+        return (FIB_API_PATH_NH_PROTO_MPLS);
+    case DPO_PROTO_BIER:
+        return (FIB_API_PATH_NH_PROTO_BIER);
+    case DPO_PROTO_ETHERNET:
+        return (FIB_API_PATH_NH_PROTO_ETHERNET);
+    case DPO_PROTO_NSH:
+        ASSERT(0);
+        break;
     }
+    return (FIB_API_PATH_NH_PROTO_IP4);
+}
 
-    n_labels = in->n_labels;
-    if (n_labels == 0)
-        ;
-    else
+
+static void
+fib_api_next_hop_encode (const fib_route_path_t *rpath,
+                         vl_api_fib_path_t *fp)
+{
+    fp->proto = fib_api_path_dpo_proto_to_nh(rpath->frp_proto);
+
+    if (rpath->frp_proto == DPO_PROTO_IP4)
+        memcpy (&fp->nh.address.ip4,
+                &rpath->frp_addr.ip4,
+                sizeof (rpath->frp_addr.ip4));
+    else if (rpath->frp_proto == DPO_PROTO_IP6)
+        memcpy (&fp->nh.address.ip6,
+                &rpath->frp_addr.ip6,
+                sizeof (rpath->frp_addr.ip6));
+}
+
+static int
+fib_api_path_nh_proto_to_dpo (vl_api_fib_path_nh_proto_t pp,
+                              dpo_proto_t *dproto)
+{
+    switch (pp)
     {
-        vec_validate (out->frp_label_stack, n_labels - 1);
-        for (ii = 0; ii < n_labels; ii++)
-        {
-            out->frp_label_stack[ii].fml_value =
-                ntohl(in->label_stack[ii].label);
-            out->frp_label_stack[ii].fml_ttl =
-                in->label_stack[ii].ttl;
-            out->frp_label_stack[ii].fml_exp =
-                in->label_stack[ii].exp;
-            out->frp_label_stack[ii].fml_mode =
-                (in->label_stack[ii].is_uniform ?
-                 FIB_MPLS_LSP_MODE_UNIFORM :
-                 FIB_MPLS_LSP_MODE_PIPE);
-        }
+    case FIB_API_PATH_NH_PROTO_IP4:
+        *dproto = DPO_PROTO_IP4;
+        break;
+    case FIB_API_PATH_NH_PROTO_IP6:
+        *dproto = DPO_PROTO_IP6;
+        break;
+    case FIB_API_PATH_NH_PROTO_MPLS:
+        *dproto = DPO_PROTO_MPLS;
+        break;
+    case FIB_API_PATH_NH_PROTO_BIER:
+        *dproto = DPO_PROTO_BIER;
+        break;
+    case FIB_API_PATH_NH_PROTO_ETHERNET:
+        *dproto = DPO_PROTO_ETHERNET;
+        break;
+    default:
+        return (-1);
     }
+    return (0);
+}
+
+int
+fib_api_path_decode (vl_api_fib_path_t *in,
+                     fib_route_path_t *out)
+{
+    vnet_classify_main_t *cm = &vnet_classify_main;
+    int rv = 0, n_labels;
+    vnet_main_t *vnm;
+    u8 ii;
+
+    vnm = vnet_get_main ();
+    clib_memset(&out->frp_dpo, 0, sizeof(out->frp_dpo));
+
+    /* enums are u32 */
+    in->flags = ntohl (in->flags);
+    in->type = ntohl (in->type);
+    in->proto = ntohl (in->proto);
 
-    if (in->is_dvr)
-        path_flags |= FIB_ROUTE_PATH_DVR;
-    if (in->is_resolve_host)
-        path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
-    if (in->is_resolve_attached)
-        path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
-    /* if (in->is_interface_rx) */
-    /*     path_flags |= FIB_ROUTE_PATH_INTF_RX; */
-    /* if (in->is_rpf_id) */
-    /*     path_flags |= FIB_ROUTE_PATH_RPF_ID; */
-    if (in->is_source_lookup)
-        path_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
-
-    if (in->is_udp_encap)
+    /*
+     * attributes that apply to all path types
+     */
+    out->frp_flags = 0;
+    out->frp_weight = in->weight;
+    if (0 == out->frp_weight)
     {
-        path_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
-        out->frp_udp_encap_id = ntohl(in->next_hop_id);
+        out->frp_weight = 1;
     }
-    else
+    out->frp_preference = in->preference;
+
+    rv = fib_api_path_nh_proto_to_dpo(in->proto, &out->frp_proto);
+
+    if (0 != rv)
+        return (rv);
+
+    /*
+     * convert the flags and the AFI to determine the path type
+     */
+    if (in->flags & FIB_API_PATH_FLAG_RESOLVE_VIA_HOST)
+        out->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
+    if (in->flags & FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED)
+        out->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
+
+    switch (in->type)
     {
-        if (DPO_PROTO_IP4 == in->afi)
-        {
-            clib_memcpy (&out->frp_addr.ip4,
-                         in->next_hop,
-                         sizeof (out->frp_addr.ip4));
-        }
-        else if (DPO_PROTO_IP6 == in->afi)
+    case FIB_API_PATH_TYPE_DVR:
+        out->frp_sw_if_index = ntohl(in->sw_if_index);
+        out->frp_flags |= FIB_ROUTE_PATH_DVR;
+        break;
+    case FIB_API_PATH_TYPE_INTERFACE_RX:
+        out->frp_sw_if_index = ntohl(in->sw_if_index);
+        out->frp_flags |= FIB_ROUTE_PATH_INTF_RX;
+        break;
+    case FIB_API_PATH_TYPE_DROP:
+        out->frp_flags |= FIB_ROUTE_PATH_DROP;
+        break;
+    case FIB_API_PATH_TYPE_LOCAL:
+        out->frp_flags |= FIB_ROUTE_PATH_LOCAL;
+        out->frp_sw_if_index = ntohl(in->sw_if_index);
+        break;
+    case FIB_API_PATH_TYPE_ICMP_UNREACH:
+        out->frp_flags |= FIB_ROUTE_PATH_ICMP_UNREACH;
+        break;
+    case FIB_API_PATH_TYPE_ICMP_PROHIBIT:
+        out->frp_flags |= FIB_ROUTE_PATH_ICMP_PROHIBIT;
+        break;
+    case FIB_API_PATH_TYPE_CLASSIFY:
+        out->frp_flags |= FIB_ROUTE_PATH_CLASSIFY;
+        
+        if (pool_is_free_index (cm->tables, ntohl (in->nh.classify_table_index)))
         {
-            clib_memcpy (&out->frp_addr.ip6,
-                         in->next_hop,
-                         sizeof (out->frp_addr.ip6));
+            return VNET_API_ERROR_NO_SUCH_TABLE;
         }
+        out->frp_classify_table_id = ntohl (in->nh.classify_table_index);
+        break;
+    case FIB_API_PATH_TYPE_UDP_ENCAP:
+        out->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
+        out->frp_udp_encap_id = ntohl(in->nh.obj_id);
+        break;
+    case FIB_API_PATH_TYPE_BIER_IMP:
+        out->frp_flags |= FIB_ROUTE_PATH_BIER_IMP;
+        out->frp_bier_imp = ntohl (in->nh.obj_id);
+        break;
 
-        if (ip46_address_is_zero(&out->frp_addr))
+    case FIB_API_PATH_TYPE_SOURCE_LOOKUP:
+        out->frp_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
+        /* fall through */
+    case FIB_API_PATH_TYPE_NORMAL:
+        switch (out->frp_proto)
         {
-            if (DPO_PROTO_BIER == in->afi)
+        case DPO_PROTO_IP4:
+        case DPO_PROTO_IP6:
+            fib_api_next_hop_decode(in, &out->frp_addr);
+            out->frp_sw_if_index = ntohl(in->sw_if_index);
+            out->frp_rpf_id = ntohl(in->rpf_id);
+
+            if (0 == out->frp_rpf_id)
             {
-                index_t bdti;
+                /* allow 0 to be an unset value on the API */
+                out->frp_rpf_id = ~0;
+            }
 
-                bdti = bier_disp_table_find(ntohl(in->table_id));
+            if (~0 != out->frp_rpf_id)
+            {
+                out->frp_flags |= FIB_ROUTE_PATH_RPF_ID;
+            }
 
-                if (INDEX_INVALID != bdti)
+            if (~0 == out->frp_sw_if_index)
+            {
+                /* recursive or deag, validate the next-hop FIB */
+                if (~0 != out->frp_rpf_id)
                 {
-                    out->frp_fib_index = bdti;
-                    out->frp_proto = DPO_PROTO_BIER;
+                    rv = fib_api_mtable_id_decode(
+                        dpo_proto_to_fib(out->frp_proto),
+                        ntohl(in->table_id),
+                        &out->frp_fib_index);
                 }
                 else
                 {
-                    rv = VNET_API_ERROR_NO_SUCH_FIB;
+                    rv = fib_api_table_id_decode(
+                        dpo_proto_to_fib(out->frp_proto),
+                        ntohl(in->table_id),
+                        &out->frp_fib_index);
+                }
+                if (0 != rv)
+                {
+                    return (rv);
                 }
             }
-            else if (out->frp_sw_if_index == ~0 &&
-                     out->frp_fib_index != ~0)
+            else
             {
-                path_flags |= FIB_ROUTE_PATH_DEAG;
+                if (pool_is_free_index (vnm->interface_main.sw_interfaces,
+                                        out->frp_sw_if_index))
+                {
+                    return VNET_API_ERROR_NO_MATCHING_INTERFACE;
+                }
             }
-        }
-    }
 
-    out->frp_flags = path_flags;
+            if (ip46_address_is_zero(&out->frp_addr))
+            {
+                if (~0 == out->frp_sw_if_index &&
+                    ~0 != out->frp_fib_index)
+                {
+                    out->frp_flags |= FIB_ROUTE_PATH_DEAG;
+                }
+            }
 
-    return (rv);
-}
+            break;
+        case DPO_PROTO_MPLS:
+            out->frp_local_label = ntohl (in->nh.via_label);
+            out->frp_eos = MPLS_NON_EOS;
+            out->frp_sw_if_index = ~0;
+            break;
+        case DPO_PROTO_BIER:
+            out->frp_sw_if_index = ntohl(in->sw_if_index);
+            out->frp_rpf_id = ntohl(in->rpf_id);
 
-void
-fib_prefix_to_api (const fib_prefix_t *pfx,
-                   u8 address[16],
-                   u8 *length,
-                   u8 *is_ip6)
-{
-    *length = pfx->fp_len;
-    *is_ip6 = (FIB_PROTOCOL_IP6 == pfx->fp_proto ? 1 : 0);
+            if (!(out->frp_flags & FIB_ROUTE_PATH_BIER_IMP))
+            {
+                fib_api_next_hop_decode(in, &out->frp_addr);
 
-    if (FIB_PROTOCOL_IP6 == pfx->fp_proto)
-    {
-        memcpy (address, &pfx->fp_addr.ip6, sizeof (pfx->fp_addr.ip6));
-    }
-    else
-    {
-        memcpy (address, &pfx->fp_addr.ip4, sizeof (pfx->fp_addr.ip4));
+                if (ip46_address_is_zero(&out->frp_addr))
+                {
+                    index_t bdti;
+
+                    bdti = bier_disp_table_find(ntohl(in->table_id));
+
+                    if (INDEX_INVALID != bdti)
+                    {
+                        out->frp_fib_index = bdti;
+                    }
+                    else
+                    {
+                        return (VNET_API_ERROR_NO_SUCH_FIB);
+                    }
+                }
+            }
+            break;
+        case DPO_PROTO_ETHERNET:
+            out->frp_sw_if_index = ntohl(in->sw_if_index);
+            break;
+        case DPO_PROTO_NSH:
+            break;
+        }
     }
-}
 
-static void
-fib_api_path_copy_next_hop (const fib_route_path_encode_t * api_rpath, void *fp_arg)
-{
-  int is_ip4;
-  vl_api_fib_path_t *fp = (vl_api_fib_path_t *) fp_arg;
-
-  if (api_rpath->rpath.frp_proto == DPO_PROTO_IP4)
-    fp->afi = IP46_TYPE_IP4;
-  else if (api_rpath->rpath.frp_proto == DPO_PROTO_IP6)
-    fp->afi = IP46_TYPE_IP6;
-  else
+    n_labels = in->n_labels;
+    if (n_labels != 0)
     {
-      is_ip4 = ip46_address_is_ip4 (&api_rpath->rpath.frp_addr);
-      if (is_ip4)
-       fp->afi = IP46_TYPE_IP4;
-      else
-       fp->afi = IP46_TYPE_IP6;
+        vec_validate (out->frp_label_stack, n_labels - 1);
+        for (ii = 0; ii < n_labels; ii++)
+        {
+            out->frp_label_stack[ii].fml_value =
+                ntohl(in->label_stack[ii].label);
+            out->frp_label_stack[ii].fml_ttl =
+                in->label_stack[ii].ttl;
+            out->frp_label_stack[ii].fml_exp =
+                in->label_stack[ii].exp;
+            out->frp_label_stack[ii].fml_mode =
+                (in->label_stack[ii].is_uniform ?
+                 FIB_MPLS_LSP_MODE_UNIFORM :
+                 FIB_MPLS_LSP_MODE_PIPE);
+        }
     }
-  if (fp->afi == IP46_TYPE_IP4)
-    memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip4,
-           sizeof (api_rpath->rpath.frp_addr.ip4));
-  else
-    memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip6,
-           sizeof (api_rpath->rpath.frp_addr.ip6));
+
+    return (0);
 }
 
 void
-fib_api_path_encode (const fib_route_path_encode_t * api_rpath,
+fib_api_path_encode (const fib_route_path_t * rpath,
                      vl_api_fib_path_t *out)
 {
-    int ii;
+    memset (out, 0, sizeof (*out));
 
-    clib_memset (out, 0, sizeof (*out));
-    switch (api_rpath->dpo.dpoi_type)
-    {
-    case DPO_RECEIVE:
-        out->is_local = true;
-        break;
-    case DPO_DROP:
-        out->is_drop = true;
-        break;
-    case DPO_IP_NULL:
-        switch (ip_null_dpo_get_action(api_rpath->dpo.dpoi_index))
-        {
-        case IP_NULL_ACTION_NONE:
-            out->is_drop = true;
-            break;
-        case IP_NULL_ACTION_SEND_ICMP_UNREACH:
-            out->is_unreach = true;
-            break;
-        case IP_NULL_ACTION_SEND_ICMP_PROHIBIT:
-            out->is_prohibit = true;
-            break;
-        default:
-            break;
-        }
-        break;
-    default:
-        break;
-    }
-    out->weight = api_rpath->rpath.frp_weight;
-    out->preference = api_rpath->rpath.frp_preference;
-    out->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
-    out->afi = api_rpath->rpath.frp_proto;
-    fib_api_path_copy_next_hop (api_rpath, out);
+    out->weight = rpath->frp_weight;
+    out->preference = rpath->frp_preference;
+    out->sw_if_index = htonl (rpath->frp_sw_if_index);
+    out->proto = fib_api_path_dpo_proto_to_nh(rpath->frp_proto);
+    out->rpf_id = rpath->frp_rpf_id;
+    fib_api_next_hop_encode (rpath, out);
 
-    if (0 != api_rpath->rpath.frp_fib_index)
+    if (0 != rpath->frp_fib_index)
     {
-        if ((DPO_PROTO_IP6 == api_rpath->rpath.frp_proto) ||
-            (DPO_PROTO_IP4 == api_rpath->rpath.frp_proto))
+        if ((DPO_PROTO_IP6 == rpath->frp_proto) ||
+            (DPO_PROTO_IP4 == rpath->frp_proto))
         {
-            if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_RPF_ID)
+            if (rpath->frp_flags & FIB_ROUTE_PATH_RPF_ID)
             {
-                out->table_id =
-                    htonl(mfib_table_get_table_id(
-                              api_rpath->rpath.frp_fib_index,
-                              dpo_proto_to_fib(api_rpath->rpath.frp_proto)));
+                out->table_id = htonl (mfib_table_get_table_id(
+                                           rpath->frp_fib_index,
+                                           dpo_proto_to_fib(rpath->frp_proto)));
             }
             else
             {
-                out->table_id =
-                    htonl(fib_table_get_table_id(
-                              api_rpath->rpath.frp_fib_index,
-                              dpo_proto_to_fib(api_rpath->rpath.frp_proto)));
+                out->table_id = htonl (fib_table_get_table_id(
+                                           rpath->frp_fib_index,
+                                           dpo_proto_to_fib(rpath->frp_proto)));
             }
         }
     }
 
-    if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_DVR)
+    if (rpath->frp_flags & FIB_ROUTE_PATH_DVR)
     {
-        out->is_dvr = 1;
+        out->type = FIB_API_PATH_TYPE_DVR;
     }
-    if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_UDP_ENCAP)
+    else if (rpath->frp_flags & FIB_ROUTE_PATH_ICMP_UNREACH)
     {
-        out->is_udp_encap = 1;
-        out->next_hop_id = api_rpath->rpath.frp_udp_encap_id;
+        out->type = FIB_API_PATH_TYPE_ICMP_UNREACH;
     }
-    if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_INTF_RX)
+    else if (rpath->frp_flags & FIB_ROUTE_PATH_ICMP_PROHIBIT)
     {
-        out->is_interface_rx = 1;
+        out->type = FIB_API_PATH_TYPE_ICMP_PROHIBIT;
     }
-    if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_LOCAL)
+    else if (rpath->frp_flags & FIB_ROUTE_PATH_LOCAL)
     {
-        out->is_local = 1;
+        out->type = FIB_API_PATH_TYPE_LOCAL;
     }
-    if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST)
+    else if (rpath->frp_flags & FIB_ROUTE_PATH_DROP)
     {
-        out->is_resolve_host = 1;
+        out->type = FIB_API_PATH_TYPE_DROP;
     }
-    if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED)
+    else if (rpath->frp_flags & FIB_ROUTE_PATH_UDP_ENCAP)
     {
-        out->is_resolve_attached = 1;
+        out->type = FIB_API_PATH_TYPE_UDP_ENCAP;
+        out->nh.obj_id = rpath->frp_udp_encap_id;
     }
-    /* if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_ATTACHED) { */
-    /*     out->is_attached = 1; */
-    /* } */
-    /* if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_CONNECTED) { */
-    /*     out->is_connected = 1; */
-    /* } */
-    if (api_rpath->rpath.frp_label_stack)
+    else if (rpath->frp_flags & FIB_ROUTE_PATH_BIER_IMP)
+    {
+        out->type = FIB_API_PATH_TYPE_BIER_IMP;
+        out->nh.obj_id = rpath->frp_bier_imp;
+    }
+    else
+    {
+        out->type = FIB_API_PATH_TYPE_NORMAL;
+    }
+    if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST)
+    {
+        out->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_HOST;
+    }
+    if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED)
+    {
+        out->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED;
+    }
+
+    out->flags = htonl (out->flags);
+    out->type = htonl (out->type);
+    out->proto = htonl (out->proto);
+
+    if (rpath->frp_label_stack)
     {
-        for (ii = 0; ii < vec_len(api_rpath->rpath.frp_label_stack); ii++)
+        int ii;
+
+        for (ii = 0; ii < vec_len(rpath->frp_label_stack); ii++)
         {
             out->label_stack[ii].label =
-                htonl(api_rpath->rpath.frp_label_stack[ii].fml_value);
+                htonl(rpath->frp_label_stack[ii].fml_value);
             out->label_stack[ii].ttl =
-                api_rpath->rpath.frp_label_stack[ii].fml_ttl;
+                rpath->frp_label_stack[ii].fml_ttl;
             out->label_stack[ii].exp =
-                api_rpath->rpath.frp_label_stack[ii].fml_exp;
+                rpath->frp_label_stack[ii].fml_exp;
         }
         out->n_labels = ii;
     }
 }
 
+void
+fib_api_route_add_del (u8 is_add,
+                       u8 is_multipath,
+                       u32 fib_index,
+                       const fib_prefix_t * prefix,
+                       fib_entry_flag_t entry_flags,
+                       fib_route_path_t *rpaths)
+{
+  if (is_multipath)
+    {
+      /* Iterative path add/remove */
+      if (is_add)
+       fib_table_entry_path_add2 (fib_index,
+                                  prefix,
+                                  FIB_SOURCE_API,
+                                   entry_flags,
+                                   rpaths);
+      else
+       fib_table_entry_path_remove2 (fib_index,
+                                     prefix,
+                                      FIB_SOURCE_API,
+                                      rpaths);
+    }
+  else
+    {
+      if (is_add)
+        /* path replacement */
+       fib_table_entry_update (fib_index,
+                                prefix,
+                                FIB_SOURCE_API,
+                                entry_flags,
+                                rpaths);
+      else
+        /* entry delete */
+       fib_table_entry_delete (fib_index,
+                                prefix,
+                                FIB_SOURCE_API);
+    }
+}
+
+u8*
+format_vl_api_fib_path (u8 * s, va_list * args)
+{
+    const vl_api_fib_path_t *path = va_arg (*args, vl_api_fib_path_t*);
+
+    s = format (s, "sw_if_index %d", ntohl (path->sw_if_index));
+    switch (clib_net_to_host_u32(path->proto))
+    {
+    case FIB_API_PATH_NH_PROTO_IP4:
+        s = format (s, " %U", format_vl_api_address_union,
+                    &path->nh.address, ADDRESS_IP4);
+        break;
+    case FIB_API_PATH_NH_PROTO_IP6:
+        s = format (s, " %U", format_vl_api_address_union,
+                    &path->nh.address, ADDRESS_IP6);
+        break;
+    default:
+        break;
+    }
+    s = format (s, " weight %d", path->weight);
+    s = format (s, " preference %d", path->preference);
+    s = format (s, " type %d", ntohl(path->type));
+    s = format (s, " proto %d", ntohl(path->proto));
+    s = format (s, " flags %d", ntohl(path->flags));
+    s = format (s, " n_labels %d", ntohl(path->n_labels));
+    s = format (s, " table-id %d", ntohl(path->table_id));
+    s = format (s, " rpf-id %d", ntohl(path->rpf_id));
+
+    return (s);
+}
+
 fib_protocol_t
 fib_proto_from_api_address_family (int af)
 {