/* * 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/vnet.h> #include <vlibmemory/api.h> #include <vnet/fib/fib_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 <vnet/vnet_msg_enum.h> #define vl_typedefs /* define message structures */ #include <vnet/vnet_all_api_h.h> #undef vl_typedefs #define vl_endianfun /* define message structures */ #include <vnet/vnet_all_api_h.h> #undef vl_endianfun /* instantiate all the print functions we know about */ #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) #define vl_printfun #include <vnet/vnet_all_api_h.h> #undef vl_printfun #include <vlibapi/api_helper_macros.h> int fib_path_api_parse (const vl_api_fib_path_t *in, fib_route_path_t *out) { fib_route_path_flags_t path_flags; mpls_label_t next_hop_via_label; int rv = 0, n_labels; u8 ii; 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; 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_fib_index = ntohl(in->table_id); out->frp_weight = in->weight; out->frp_preference = in->preference; /* * the special INVALID label meams 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)) { out->frp_proto = DPO_PROTO_MPLS; out->frp_local_label = next_hop_via_label; out->frp_eos = MPLS_NON_EOS; } n_labels = in->n_labels; if (n_labels == 0) ; else { 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 (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) { path_flags |= FIB_ROUTE_PATH_UDP_ENCAP; out->frp_udp_encap_id = ntohl(in->next_hop_id); } else { 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) { clib_memcpy (&out->frp_addr.ip6, in->next_hop, sizeof (out->frp_addr.ip6)); } if (ip46_address_is_zero(&out->frp_addr)) { if (DPO_PROTO_BIER == in->afi) { index_t bdti; bdti = bier_disp_table_find(ntohl(in->table_id)); if (INDEX_INVALID != bdti) { out->frp_fib_index = bdti; out->frp_proto = DPO_PROTO_BIER; } else { rv = VNET_API_ERROR_NO_SUCH_FIB; } } else if (out->frp_sw_if_index == ~0 && out->frp_fib_index != ~0) { path_flags |= FIB_ROUTE_PATH_DEAG; } } } out->frp_flags = path_flags; return (rv); } 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 (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)); } } 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 { 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; } 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)); } void fib_api_path_encode (const fib_route_path_encode_t * api_rpath, vl_api_fib_path_t *out) { int ii; 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); if (0 != api_rpath->rpath.frp_fib_index) { if ((DPO_PROTO_IP6 == api_rpath->rpath.frp_proto) || (DPO_PROTO_IP4 == api_rpath->rpath.frp_proto)) { if (api_rpath->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))); } 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))); } } } if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_DVR) { out->is_dvr = 1; } if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_UDP_ENCAP) { out->is_udp_encap = 1; out->next_hop_id = api_rpath->rpath.frp_udp_encap_id; } if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_INTF_RX) { out->is_interface_rx = 1; } if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_LOCAL) { out->is_local = 1; } if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST) { out->is_resolve_host = 1; } if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED) { out->is_resolve_attached = 1; } /* 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) { for (ii = 0; ii < vec_len(api_rpath->rpath.frp_label_stack); ii++) { out->label_stack[ii].label = htonl(api_rpath->rpath.frp_label_stack[ii].fml_value); out->label_stack[ii].ttl = api_rpath->rpath.frp_label_stack[ii].fml_ttl; out->label_stack[ii].exp = api_rpath->rpath.frp_label_stack[ii].fml_exp; } out->n_labels = ii; } } fib_protocol_t fib_proto_from_api_address_family (int af) { switch (clib_net_to_host_u32 (af)) { case ADDRESS_IP4: return (FIB_PROTOCOL_IP4); case ADDRESS_IP6: return (FIB_PROTOCOL_IP6); } ASSERT(0); return (FIB_PROTOCOL_IP4); } int fib_proto_to_api_address_family (fib_protocol_t fproto) { switch (fproto) { case FIB_PROTOCOL_IP4: return (clib_net_to_host_u32 (ADDRESS_IP4)); case FIB_PROTOCOL_IP6: return (clib_net_to_host_u32 (ADDRESS_IP6)); default: break; } ASSERT(0); return (clib_net_to_host_u32 (ADDRESS_IP4)); }