X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Ffib%2Ffib_api.c;h=5aa5c4ec875962c9d499924ad851653f4494eef0;hb=097fa66b986f06281f603767d321ab13ab6c88c3;hp=12c4f0de13fe9935cc938ff383abffc5a5f184ab;hpb=39baa32186fd3e4b20d9f58afbbfe7b8daebed62;p=vpp.git diff --git a/src/vnet/fib/fib_api.c b/src/vnet/fib/fib_api.c index 12c4f0de13f..5aa5c4ec875 100644 --- a/src/vnet/fib/fib_api.c +++ b/src/vnet/fib/fib_api.c @@ -16,10 +16,11 @@ #include #include #include +#include #include #include #include -#include +#include #include @@ -40,288 +41,485 @@ #include 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) {