diff options
Diffstat (limited to 'src/vnet/teib')
-rw-r--r-- | src/vnet/teib/teib.api | 57 | ||||
-rw-r--r-- | src/vnet/teib/teib.c | 244 | ||||
-rw-r--r-- | src/vnet/teib/teib.h | 85 | ||||
-rw-r--r-- | src/vnet/teib/teib_api.c | 138 | ||||
-rw-r--r-- | src/vnet/teib/teib_cli.c | 194 |
5 files changed, 718 insertions, 0 deletions
diff --git a/src/vnet/teib/teib.api b/src/vnet/teib/teib.api new file mode 100644 index 00000000000..8e7320837b1 --- /dev/null +++ b/src/vnet/teib/teib.api @@ -0,0 +1,57 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * 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. + */ + +option version = "1.0.0"; + +import "vnet/ip/ip_types.api"; +import "vnet/interface_types.api"; + +/** \brief TEIB Entry + @param sw_if_index +*/ +typedef teib_entry +{ + vl_api_interface_index_t sw_if_index; + vl_api_address_t peer; + vl_api_address_t nh; + u32 nh_table_id; +}; + +autoreply define teib_entry_add_del +{ + u32 client_index; + u32 context; + u8 is_add; + vl_api_teib_entry_t entry; +}; + +define teib_dump +{ + u32 client_index; + u32 context; +}; + +define teib_details +{ + u32 context; + vl_api_teib_entry_t entry; +}; + +/* + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/teib/teib.c b/src/vnet/teib/teib.c new file mode 100644 index 00000000000..e392b49e86b --- /dev/null +++ b/src/vnet/teib/teib.c @@ -0,0 +1,244 @@ +/* + * teib.h: next-hop resolution + * + * 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/teib/teib.h> +#include <vnet/fib/fib_table.h> +#include <vnet/adj/adj_midchain.h> + +typedef struct teib_key_t_ +{ + ip46_address_t tk_peer; + u32 tk_sw_if_index; +} teib_key_t; + +struct teib_entry_t_ +{ + teib_key_t *te_key; + fib_prefix_t te_nh; + u32 te_fib_index; +}; + +static uword *teib_db; +static teib_entry_t *teib_pool; +static teib_vft_t *teib_vfts; + +#define TEIB_NOTIFY(_te, _fn) { \ + teib_vft_t *_vft; \ + vec_foreach(_vft, teib_vfts) { \ + if (_vft->_fn) { \ + _vft->_fn(_te); \ + } \ + } \ +} + +u32 +teib_entry_get_sw_if_index (const teib_entry_t * te) +{ + return (te->te_key->tk_sw_if_index); +} + +u32 +teib_entry_get_fib_index (const teib_entry_t * te) +{ + return (te->te_fib_index); +} + +const ip46_address_t * +teib_entry_get_peer (const teib_entry_t * te) +{ + return (&te->te_key->tk_peer); +} + +const fib_prefix_t * +teib_entry_get_nh (const teib_entry_t * te) +{ + return (&te->te_nh); +} + +void +teib_entry_adj_stack (const teib_entry_t * te, adj_index_t ai) +{ + adj_midchain_delegate_stack (ai, te->te_fib_index, &te->te_nh); +} + +teib_entry_t * +teib_entry_get (index_t tei) +{ + return pool_elt_at_index (teib_pool, tei); +} + +teib_entry_t * +teib_entry_find (u32 sw_if_index, const ip46_address_t * peer) +{ + teib_key_t nk = { + .tk_peer = *peer, + .tk_sw_if_index = sw_if_index, + }; + uword *p; + + p = hash_get_mem (teib_db, &nk); + + if (NULL != p) + return teib_entry_get (p[0]); + + return (NULL); +} + +int +teib_entry_add (u32 sw_if_index, + const ip46_address_t * peer, + u32 nh_table_id, const ip46_address_t * nh) +{ + fib_protocol_t fproto; + teib_entry_t *te; + u32 fib_index; + index_t tei; + + fproto = (ip46_address_is_ip4 (nh) ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6); + + fib_index = fib_table_find (fproto, nh_table_id); + + if (~0 == fib_index) + { + return (VNET_API_ERROR_NO_SUCH_FIB); + } + + te = teib_entry_find (sw_if_index, peer); + + if (NULL == te) + { + teib_key_t nk = { + .tk_peer = *peer, + .tk_sw_if_index = sw_if_index, + }; + teib_entry_t *te; + + pool_get_zero (teib_pool, te); + + tei = te - teib_pool; + te->te_key = clib_mem_alloc (sizeof (*te->te_key)); + clib_memcpy (te->te_key, &nk, sizeof (*te->te_key)); + + ip46_address_copy (&te->te_nh.fp_addr, nh); + te->te_nh.fp_proto = fproto; + te->te_nh.fp_len = (te->te_nh.fp_proto == FIB_PROTOCOL_IP4 ? 32 : 128); + te->te_fib_index = fib_index; + + hash_set_mem (teib_db, te->te_key, tei); + + TEIB_NOTIFY (te, nv_added); + } + else + return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS); + + return 0; +} + +int +teib_entry_del (u32 sw_if_index, const ip46_address_t * peer) +{ + teib_entry_t *te; + + te = teib_entry_find (sw_if_index, peer); + + if (te != NULL) + { + hash_unset_mem (teib_db, te->te_key); + + TEIB_NOTIFY (te, nv_deleted); + + clib_mem_free (te->te_key); + pool_put (teib_pool, te); + } + else + return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS); + + return 0; +} + +u8 * +format_teib_entry (u8 * s, va_list * args) +{ + index_t tei = va_arg (*args, index_t); + vnet_main_t *vnm = vnet_get_main (); + teib_entry_t *te; + + te = teib_entry_get (tei); + + s = format (s, "[%d] ", tei); + s = format (s, "%U:", format_vnet_sw_if_index_name, + vnm, te->te_key->tk_sw_if_index); + s = format (s, " %U", format_ip46_address, + &te->te_key->tk_peer, IP46_TYPE_ANY); + s = format (s, " via [%d]:%U", + fib_table_get_table_id (te->te_fib_index, te->te_nh.fp_proto), + format_fib_prefix, &te->te_nh); + + return (s); +} + +void +teib_walk (teib_walk_cb_t fn, void *ctx) +{ + index_t tei; + + /* *INDENT-OFF* */ + pool_foreach_index(tei, teib_pool, + ({ + fn(tei, ctx); + })); + /* *INDENT-ON* */ +} + +void +teib_walk_itf (u32 sw_if_index, teib_walk_cb_t fn, void *ctx) +{ + index_t tei; + + /* *INDENT-OFF* */ + pool_foreach_index(tei, teib_pool, + ({ + if (sw_if_index == teib_entry_get_sw_if_index(teib_entry_get(tei))) + fn(tei, ctx); + })); + /* *INDENT-ON* */ +} + +void +teib_register (const teib_vft_t * vft) +{ + vec_add1 (teib_vfts, *vft); +} + +static clib_error_t * +teib_init (vlib_main_t * vm) +{ + teib_db = hash_create_mem (0, sizeof (teib_key_t), sizeof (u32)); + + return (NULL); +} + +VLIB_INIT_FUNCTION (teib_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/teib/teib.h b/src/vnet/teib/teib.h new file mode 100644 index 00000000000..4a03eee844f --- /dev/null +++ b/src/vnet/teib/teib.h @@ -0,0 +1,85 @@ +/* + * teib.h: next-hop resolution + * + * 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. + */ + +#ifndef __TEIB_H__ +#define __TEIB_H__ + +#include <vnet/ip/ip.h> + +/** + * Tunnel Endpoint Information Base. + * + * A TEIB entry represents the mapping between a peer on an interface in the overlay + * and a next-hop address in the underlay. + * i.e. there's a multipoint tunnel providing the overlay (henace a peer on + * that tunnel) which is reachable via 'tunnel destination' address in the + * underlay. + * + * Such overlay to underlay mappings might be providied by a protocol like NHRP + */ +typedef struct teib_entry_t_ teib_entry_t; + +/** accessors for the opaque struct */ +extern u32 teib_entry_get_sw_if_index (const teib_entry_t * ne); +extern u32 teib_entry_get_fib_index (const teib_entry_t * ne); +extern const ip46_address_t *teib_entry_get_peer (const teib_entry_t * ne); +extern const fib_prefix_t *teib_entry_get_nh (const teib_entry_t * ne); +extern u8 *format_teib_entry (u8 * s, va_list * args); + +/** + * Create a new TEIB entry + */ +extern int teib_entry_add (u32 sw_if_index, + const ip46_address_t * peer, + u32 nh_table_id, const ip46_address_t * nh); + +extern int teib_entry_del (u32 sw_if_index, const ip46_address_t * peer); + +extern teib_entry_t *teib_entry_find (u32 sw_if_index, + const ip46_address_t * peer); +extern teib_entry_t *teib_entry_get (index_t nei); + +extern void teib_entry_adj_stack (const teib_entry_t * ne, adj_index_t ai); + +typedef walk_rc_t (*teib_walk_cb_t) (index_t nei, void *ctx); + +extern void teib_walk (teib_walk_cb_t fn, void *ctx); +extern void teib_walk_itf (u32 sw_if_index, teib_walk_cb_t fn, void *ctx); + +/** + * Notifications for the creation and deletion of TEIB entries + */ +typedef void (*teib_entry_added_t) (const teib_entry_t * ne); +typedef void (*teib_entry_deleted_t) (const teib_entry_t * ne); + +typedef struct teib_vft_t_ +{ + teib_entry_added_t nv_added; + teib_entry_deleted_t nv_deleted; +} teib_vft_t; + +extern void teib_register (const teib_vft_t * vft); + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/teib/teib_api.c b/src/vnet/teib/teib_api.c new file mode 100644 index 00000000000..a51dd6d0f7f --- /dev/null +++ b/src/vnet/teib/teib_api.c @@ -0,0 +1,138 @@ +/* + *------------------------------------------------------------------ + * teib_api.c - teib api + * + * 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/api_errno.h> +#include <vnet/teib/teib.h> +#include <vnet/ip/ip_types_api.h> +#include <vnet/fib/fib_table.h> + +/* define message IDs */ +#include <vnet/format_fns.h> +#include <vnet/teib/teib.api_enum.h> +#include <vnet/teib/teib.api_types.h> + +static u32 teib_base_msg_id; +#define REPLY_MSG_ID_BASE teib_base_msg_id + +#include <vlibapi/api_helper_macros.h> + +static void +vl_api_teib_entry_add_del_t_handler (vl_api_teib_entry_add_del_t * mp) +{ + vl_api_teib_entry_add_del_reply_t *rmp; + ip46_address_t peer, nh; + int rv; + + VALIDATE_SW_IF_INDEX ((&mp->entry)); + + ip_address_decode (&mp->entry.peer, &peer); + ip_address_decode (&mp->entry.nh, &nh); + + if (mp->is_add) + rv = teib_entry_add (ntohl (mp->entry.sw_if_index), &peer, + ntohl (mp->entry.nh_table_id), &nh); + else + rv = teib_entry_del (ntohl (mp->entry.sw_if_index), &peer); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_TEIB_ENTRY_ADD_DEL_REPLY); +} + +typedef struct vl_api_teib_send_t_ +{ + vl_api_registration_t *reg; + u32 context; +} vl_api_teib_send_t; + +static walk_rc_t +vl_api_teib_send_one (index_t nei, void *arg) +{ + vl_api_teib_details_t *mp; + vl_api_teib_send_t *ctx = arg; + const teib_entry_t *ne; + const fib_prefix_t *pfx; + + mp = vl_msg_api_alloc (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_TEIB_DETAILS + REPLY_MSG_ID_BASE); + mp->context = ctx->context; + + ne = teib_entry_get (nei); + pfx = teib_entry_get_nh (ne); + + ip_address_encode (teib_entry_get_peer (ne), IP46_TYPE_ANY, + &mp->entry.peer); + ip_address_encode (&pfx->fp_addr, IP46_TYPE_ANY, &mp->entry.nh); + mp->entry.nh_table_id = + htonl (fib_table_get_table_id + (teib_entry_get_fib_index (ne), pfx->fp_proto)); + mp->entry.sw_if_index = htonl (teib_entry_get_sw_if_index (ne)); + + vl_api_send_msg (ctx->reg, (u8 *) mp); + + return (WALK_CONTINUE); +} + +static void +vl_api_teib_dump_t_handler (vl_api_teib_dump_t * mp) +{ + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + vl_api_teib_send_t ctx = { + .reg = reg, + .context = mp->context, + }; + + teib_walk (vl_api_teib_send_one, &ctx); +} + +/* + * teib_api_hookup + * Add vpe's API message handlers to the table. + * vlib has already mapped shared memory and + * added the client registration handlers. + * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() + */ +#include <vnet/teib/teib.api.c> + +static clib_error_t * +teib_api_hookup (vlib_main_t * vm) +{ + teib_base_msg_id = setup_message_id_table (); + + return (NULL); +} + +VLIB_API_INIT_FUNCTION (teib_api_hookup); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/teib/teib_cli.c b/src/vnet/teib/teib_cli.c new file mode 100644 index 00000000000..faf0d828963 --- /dev/null +++ b/src/vnet/teib/teib_cli.c @@ -0,0 +1,194 @@ +/* + * 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 <vnet/teib/teib.h> + +static clib_error_t * +teib_add (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + ip46_address_t peer = ip46_address_initializer; + ip46_address_t nh = ip46_address_initializer; + u32 sw_if_index, nh_table_id; + clib_error_t *error = NULL; + int rv; + + sw_if_index = ~0; + nh_table_id = 0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U", unformat_vnet_sw_interface, + vnet_get_main (), &sw_if_index)) + ; + else if (unformat (line_input, "peer %U", unformat_ip46_address, &peer)) + ; + else if (unformat (line_input, "nh %U", unformat_ip46_address, &nh)) + ; + else if (unformat (line_input, "nh-table-id %d", &nh_table_id)) + ; + else + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } + } + + if (~0 == sw_if_index) + { + error = clib_error_return (0, "interface required'", + format_unformat_error, line_input); + goto done; + } + if (ip46_address_is_zero (&peer)) + { + error = clib_error_return (0, "peer required'", + format_unformat_error, line_input); + goto done; + } + if (ip46_address_is_zero (&nh)) + { + error = clib_error_return (0, "next-hop required'", + format_unformat_error, line_input); + goto done; + } + + rv = teib_entry_add (sw_if_index, &peer, nh_table_id, &nh); + + if (rv) + { + error = clib_error_return_code (NULL, rv, 0, + "NRHP error", + format_unformat_error, line_input); + } + +done: + unformat_free (line_input); + + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (teib_create_command, static) = { + .path = "create teib", + .short_help = "create teib <interface> peer <addr> nh <addr> [nh-table-id <ID>]", + .function = teib_add, +}; +/* *INDENT-ON* */ + +static clib_error_t * +teib_del (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + ip46_address_t peer = ip46_address_initializer; + clib_error_t *error = NULL; + u32 sw_if_index; + int rv; + + sw_if_index = ~0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U", unformat_vnet_sw_interface, + vnet_get_main (), &sw_if_index)) + ; + else if (unformat (line_input, "peer %U", unformat_ip46_address, &peer)) + ; + else + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } + } + + if (~0 == sw_if_index) + { + error = clib_error_return (0, "interface required'", + format_unformat_error, line_input); + } + if (ip46_address_is_zero (&peer)) + { + error = clib_error_return (0, "peer required'", + format_unformat_error, line_input); + goto done; + } + + rv = teib_entry_del (sw_if_index, &peer); + + if (rv) + { + error = clib_error_return_code (NULL, rv, 0, + "NRHP error", + format_unformat_error, line_input); + } + +done: + unformat_free (line_input); + + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (teib_delete_command, static) = { + .path = "delete teib", + .short_help = "delete teib <interface> peer <addr>", + .function = teib_del, +}; +/* *INDENT-ON* */ + +static walk_rc_t +teib_show_one (index_t nei, void *ctx) +{ + vlib_cli_output (ctx, "%U", format_teib_entry, nei); + + return (WALK_CONTINUE); +} + + +static clib_error_t * +teib_show (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + teib_walk (teib_show_one, vm); + return (NULL); +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (teib_show_command, static) = { + .path = "show teib", + .short_help = "show teib", + .function = teib_show, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |