/* * Copyright (c) 2019 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 typedef struct { /* VNET_API_ERROR_FOO -> "Foo" hash table */ uword *error_string_by_error_number; } echo_common_main_t; echo_common_main_t echo_common_main; u8 * format_ip4_address (u8 * s, va_list * args) { u8 *a = va_arg (*args, u8 *); return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); } u8 * format_ip6_address (u8 * s, va_list * args) { ip6_address_t *a = va_arg (*args, ip6_address_t *); u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon; i_max_n_zero = ARRAY_LEN (a->as_u16); max_n_zeros = 0; i_first_zero = i_max_n_zero; n_zeros = 0; for (i = 0; i < ARRAY_LEN (a->as_u16); i++) { u32 is_zero = a->as_u16[i] == 0; if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16)) { i_first_zero = i; n_zeros = 0; } n_zeros += is_zero; if ((!is_zero && n_zeros > max_n_zeros) || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros)) { i_max_n_zero = i_first_zero; max_n_zeros = n_zeros; i_first_zero = ARRAY_LEN (a->as_u16); n_zeros = 0; } } last_double_colon = 0; for (i = 0; i < ARRAY_LEN (a->as_u16); i++) { if (i == i_max_n_zero && max_n_zeros > 1) { s = format (s, "::"); i += max_n_zeros - 1; last_double_colon = 1; } else { s = format (s, "%s%x", (last_double_colon || i == 0) ? "" : ":", clib_net_to_host_u16 (a->as_u16[i])); last_double_colon = 0; } } return s; } /* Format an IP46 address. */ u8 * format_ip46_address (u8 * s, va_list * args) { ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); ip46_type_t type = va_arg (*args, ip46_type_t); int is_ip4 = 1; switch (type) { case IP46_TYPE_ANY: is_ip4 = ip46_address_is_ip4 (ip46); break; case IP46_TYPE_IP4: is_ip4 = 1; break; case IP46_TYPE_IP6: is_ip4 = 0; break; } return is_ip4 ? format (s, "%U", format_ip4_address, &ip46->ip4) : format (s, "%U", format_ip6_address, &ip46->ip6); } static uword unformat_data (unformat_input_t * input, va_list * args) { u64 _a; u64 *a = va_arg (*args, u64 *); if (unformat (input, "%lluGb", &_a)) *a = _a << 30; else if (unformat (input, "%lluMb", &_a)) *a = _a << 20; else if (unformat (input, "%lluKb", &_a)) *a = _a << 10; else if (unformat (input, "%llu", a)) ; else return 0; return 1; } static u8 * format_api_error (u8 * s, va_list * args) { echo_common_main_t *ecm = &echo_common_main; i32 error = va_arg (*args, u32); uword *p; p = hash_get (ecm->error_string_by_error_number, -error); if (p) s = format (s, "%s", p[0]); else s = format (s, "%d", error); return s; } static void init_error_string_table () { echo_common_main_t *ecm = &echo_common_main; ecm->error_string_by_error_number = hash_create (0, sizeof (uword)); #define _(n,v,s) hash_set (ecm->error_string_by_error_number, -v, s); foreach_vnet_api_error; #undef _ hash_set (ecm->error_string_by_error_number, 99, "Misc"); }