/* * 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 #include #include #include #include #include #include #include #include #include #define vl_typedefs /* define message structures */ #include #undef vl_typedefs #define vl_endianfun /* define message structures */ #include #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 #undef vl_printfun #include int fib_api_table_id_decode (fib_protocol_t fproto, u32 table_id, u32 *fib_index) { *fib_index = fib_table_find(fproto, table_id); if (INDEX_INVALID == *fib_index) { return VNET_API_ERROR_NO_SUCH_FIB; } return (0); } 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 == *fib_index) { return VNET_API_ERROR_NO_SUCH_FIB; } 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) clib_memcpy (&out->ip4, &in->nh.address.ip4, sizeof (out->ip4)); else if (in->proto == FIB_API_PATH_NH_PROTO_IP6) clib_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) { 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); } 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) clib_memcpy (&fp->nh.address.ip4, &rpath->frp_addr.ip4, sizeof (rpath->frp_addr.ip4)); else if (rpath->frp_proto == DPO_PROTO_IP6) clib_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) { 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); /* * attributes that apply to all path types */ out->frp_flags = 0; out->frp_weight = in->weight; if (0 == out->frp_weight) { out->frp_weight = 1; } 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; if (in->flags & FIB_API_PATH_FLAG_POP_PW_CW) out->frp_flags |= FIB_ROUTE_PATH_POP_PW_CW; switch (in->type) { 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))) { 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; 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) { 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) { /* allow 0 to be an unset value on the API */ out->frp_rpf_id = ~0; } if (~0 != out->frp_rpf_id) { out->frp_flags |= FIB_ROUTE_PATH_RPF_ID; } if (~0 == out->frp_sw_if_index) { /* recursive or deag, validate the next-hop FIB */ if (~0 != out->frp_rpf_id) { rv = fib_api_mtable_id_decode( dpo_proto_to_fib(out->frp_proto), ntohl(in->table_id), &out->frp_fib_index); } else { 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 (pool_is_free_index (vnm->interface_main.sw_interfaces, out->frp_sw_if_index)) { return VNET_API_ERROR_NO_MATCHING_INTERFACE; } } 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; } } 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); if (!(out->frp_flags & FIB_ROUTE_PATH_BIER_IMP)) { fib_api_next_h