diff options
author | Neale Ranns <nranns@cisco.com> | 2019-04-18 10:23:56 +0000 |
---|---|---|
committer | Ole Trøan <otroan@employees.org> | 2019-12-04 22:45:11 +0000 |
commit | 5f8f6173328f8d77feea5fd100e150c3094c11f0 (patch) | |
tree | 16849c6e7619b227a93ce9846f344da2cc96ef2d /src/vnet/nhrp | |
parent | 79619c10142e15754e2f0b2ba26c20d415e7c36f (diff) |
gre: Multi-point interfaces
Type: feature
Change-Id: I0129ad6ace44a50a8a3b26db8e445cd06b2b49e8
Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src/vnet/nhrp')
-rw-r--r-- | src/vnet/nhrp/nhrp.api | 57 | ||||
-rw-r--r-- | src/vnet/nhrp/nhrp.c | 196 | ||||
-rw-r--r-- | src/vnet/nhrp/nhrp.h | 62 | ||||
-rw-r--r-- | src/vnet/nhrp/nhrp_api.c | 134 | ||||
-rw-r--r-- | src/vnet/nhrp/nhrp_cli.c | 194 |
5 files changed, 643 insertions, 0 deletions
diff --git a/src/vnet/nhrp/nhrp.api b/src/vnet/nhrp/nhrp.api new file mode 100644 index 00000000000..de0630c9c88 --- /dev/null +++ b/src/vnet/nhrp/nhrp.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 NHRP Entry + @param sw_if_index +*/ +typedef nhrp_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 nhrp_entry_add_del +{ + u32 client_index; + u32 context; + u8 is_add; + vl_api_nhrp_entry_t entry; +}; + +define nhrp_dump +{ + u32 client_index; + u32 context; +}; + +define nhrp_details +{ + u32 context; + vl_api_nhrp_entry_t entry; +}; + +/* + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/nhrp/nhrp.c b/src/vnet/nhrp/nhrp.c new file mode 100644 index 00000000000..6a616ba273d --- /dev/null +++ b/src/vnet/nhrp/nhrp.c @@ -0,0 +1,196 @@ +/* + * nhrp.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/nhrp/nhrp.h> +#include <vnet/fib/fib_table.h> +#include <vnet/adj/adj_midchain.h> + +static uword *nhrp_db; +static nhrp_entry_t *nhrp_pool; + +void +nhrp_entry_adj_stack (const nhrp_entry_t * ne, adj_index_t ai) +{ + adj_midchain_delegate_stack (ai, ne->ne_fib_index, &ne->ne_nh); +} + +static adj_walk_rc_t +nhrp_entry_add_adj_walk (adj_index_t ai, void *ctx) +{ + nhrp_entry_adj_stack (ctx, ai); + + return (ADJ_WALK_RC_CONTINUE); +} + +static adj_walk_rc_t +nhrp_entry_del_adj_walk (adj_index_t ai, void *ctx) +{ + adj_midchain_delegate_unstack (ai); + + return (ADJ_WALK_RC_CONTINUE); +} + +nhrp_entry_t * +nhrp_entry_get (index_t nei) +{ + return pool_elt_at_index (nhrp_pool, nei); +} + +nhrp_entry_t * +nhrp_entry_find (u32 sw_if_index, const ip46_address_t * peer) +{ + nhrp_key_t nk = { + .nk_peer = *peer, + .nk_sw_if_index = sw_if_index, + }; + uword *p; + + p = hash_get_mem (nhrp_db, &nk); + + if (NULL != p) + return nhrp_entry_get (p[0]); + + return (NULL); +} + +int +nhrp_entry_add (u32 sw_if_index, + const ip46_address_t * peer, + u32 nh_table_id, const ip46_address_t * nh) +{ + fib_protocol_t fproto; + nhrp_entry_t *ne; + u32 fib_index; + index_t nei; + + 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); + } + + ne = nhrp_entry_find (sw_if_index, peer); + + if (NULL == ne) + { + nhrp_key_t nk = { + .nk_peer = *peer, + .nk_sw_if_index = sw_if_index, + }; + nhrp_entry_t *ne; + + pool_get_zero (nhrp_pool, ne); + + nei = ne - nhrp_pool; + ne->ne_key = clib_mem_alloc (sizeof (*ne->ne_key)); + clib_memcpy (ne->ne_key, &nk, sizeof (*ne->ne_key)); + + ip46_address_copy (&ne->ne_nh.fp_addr, nh); + ne->ne_nh.fp_proto = fproto; + ne->ne_nh.fp_len = (ne->ne_nh.fp_proto == FIB_PROTOCOL_IP4 ? 32 : 128); + ne->ne_fib_index = fib_index; + + hash_set_mem (nhrp_db, ne->ne_key, nei); + + adj_nbr_walk_nh (sw_if_index, + ne->ne_nh.fp_proto, + &ne->ne_key->nk_peer, nhrp_entry_add_adj_walk, ne); + } + else + return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS); + + return 0; +} + +int +nhrp_entry_del (u32 sw_if_index, const ip46_address_t * peer) +{ + nhrp_entry_t *ne; + + ne = nhrp_entry_find (sw_if_index, peer); + + if (ne != NULL) + { + hash_unset_mem (nhrp_db, ne->ne_key); + + adj_nbr_walk_nh (sw_if_index, + ne->ne_nh.fp_proto, + &ne->ne_key->nk_peer, nhrp_entry_del_adj_walk, ne); + + clib_mem_free (ne->ne_key); + pool_put (nhrp_pool, ne); + } + else + return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS); + + return 0; +} + +u8 * +format_nhrp_entry (u8 * s, va_list * args) +{ + index_t nei = va_arg (*args, index_t); + vnet_main_t *vnm = vnet_get_main (); + nhrp_entry_t *ne; + + ne = nhrp_entry_get (nei); + + s = format (s, "[%d] ", nei); + s = format (s, "%U:%U ", format_vnet_sw_if_index_name, + vnm, ne->ne_key->nk_sw_if_index, + format_ip46_address, &ne->ne_key->nk_peer, IP46_TYPE_ANY); + s = format (s, "via %d:%U", + fib_table_get_table_id (ne->ne_fib_index, ne->ne_nh.fp_proto), + format_fib_prefix, &ne->ne_nh); + + return (s); +} + +void +nhrp_walk (nhrp_walk_cb_t fn, void *ctx) +{ + index_t nei; + + /* *INDENT-OFF* */ + pool_foreach_index(nei, nhrp_pool, + ({ + fn(nei, ctx); + })); + /* *INDENT-ON* */ +} + +static clib_error_t * +nhrp_init (vlib_main_t * vm) +{ + nhrp_db = hash_create_mem (0, sizeof (nhrp_key_t), sizeof (u32)); + + return (NULL); +} + +VLIB_INIT_FUNCTION (nhrp_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/nhrp/nhrp.h b/src/vnet/nhrp/nhrp.h new file mode 100644 index 00000000000..fa842feb658 --- /dev/null +++ b/src/vnet/nhrp/nhrp.h @@ -0,0 +1,62 @@ +/* + * nhrp.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 __NHRP_H__ +#define __NHRP_H__ + +#include <vnet/ip/ip.h> + +typedef struct nhrp_key_t_ +{ + ip46_address_t nk_peer; + u32 nk_sw_if_index; +} nhrp_key_t; + +typedef struct nhrp_entry_t_ +{ + nhrp_key_t *ne_key; + fib_prefix_t ne_nh; + u32 ne_fib_index; +} nhrp_entry_t; + +extern u8 *format_nhrp_entry (u8 * s, va_list * args); + +extern int nhrp_entry_add (u32 sw_if_index, + const ip46_address_t * peer, + u32 nh_table_id, const ip46_address_t * nh); + +extern int nhrp_entry_del (u32 sw_if_index, const ip46_address_t * peer); + +extern nhrp_entry_t *nhrp_entry_find (u32 sw_if_index, + const ip46_address_t * peer); +extern nhrp_entry_t *nhrp_entry_get (index_t nei); + +extern void nhrp_entry_adj_stack (const nhrp_entry_t * ne, adj_index_t ai); + +typedef walk_rc_t (*nhrp_walk_cb_t) (index_t nei, void *ctx); + +extern void nhrp_walk (nhrp_walk_cb_t fn, void *ctx); + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/nhrp/nhrp_api.c b/src/vnet/nhrp/nhrp_api.c new file mode 100644 index 00000000000..6f07eb700e4 --- /dev/null +++ b/src/vnet/nhrp/nhrp_api.c @@ -0,0 +1,134 @@ +/* + *------------------------------------------------------------------ + * nhrp_api.c - nhrp 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/nhrp/nhrp.h> +#include <vnet/ip/ip_types_api.h> +#include <vnet/fib/fib_table.h> + +/* define message IDs */ +#include <vnet/format_fns.h> +#include <vnet/nhrp/nhrp.api_enum.h> +#include <vnet/nhrp/nhrp.api_types.h> + +static u32 nhrp_base_msg_id; +#define REPLY_MSG_ID_BASE nhrp_base_msg_id + +#include <vlibapi/api_helper_macros.h> + +static void +vl_api_nhrp_entry_add_del_t_handler (vl_api_nhrp_entry_add_del_t * mp) +{ + vl_api_nhrp_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 = nhrp_entry_add (ntohl (mp->entry.sw_if_index), &peer, + ntohl (mp->entry.nh_table_id), &nh); + else + rv = nhrp_entry_del (ntohl (mp->entry.sw_if_index), &peer); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_NHRP_ENTRY_ADD_DEL_REPLY); +} + +typedef struct vl_api_nhrp_send_t_ +{ + vl_api_registration_t *reg; + u32 context; +} vl_api_nhrp_send_t; + +static walk_rc_t +vl_api_nhrp_send_one (index_t nei, void *arg) +{ + vl_api_nhrp_details_t *mp; + vl_api_nhrp_send_t *ctx = arg; + const nhrp_entry_t *ne; + + mp = vl_msg_api_alloc (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_NHRP_DETAILS + REPLY_MSG_ID_BASE); + mp->context = ctx->context; + + ne = nhrp_entry_get (nei); + + ip_address_encode (&ne->ne_key->nk_peer, IP46_TYPE_ANY, &mp->entry.peer); + ip_address_encode (&ne->ne_nh.fp_addr, IP46_TYPE_ANY, &mp->entry.nh); + mp->entry.nh_table_id = + htonl (fib_table_get_table_id (ne->ne_fib_index, ne->ne_nh.fp_proto)); + mp->entry.sw_if_index = htonl (ne->ne_key->nk_sw_if_index); + + vl_api_send_msg (ctx->reg, (u8 *) mp); + + return (WALK_CONTINUE); +} + +static void +vl_api_nhrp_dump_t_handler (vl_api_nhrp_dump_t * mp) +{ + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + vl_api_nhrp_send_t ctx = { + .reg = reg, + .context = mp->context, + }; + + nhrp_walk (vl_api_nhrp_send_one, &ctx); +} + +/* + * nhrp_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/nhrp/nhrp.api.c> + +static clib_error_t * +nhrp_api_hookup (vlib_main_t * vm) +{ + nhrp_base_msg_id = setup_message_id_table (); + + return (NULL); +} + +VLIB_API_INIT_FUNCTION (nhrp_api_hookup); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/nhrp/nhrp_cli.c b/src/vnet/nhrp/nhrp_cli.c new file mode 100644 index 00000000000..654c750197e --- /dev/null +++ b/src/vnet/nhrp/nhrp_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/nhrp/nhrp.h> + +static clib_error_t * +nhrp_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 = nhrp_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 (nhrp_create_command, static) = { + .path = "create nhrp", + .short_help = "create nhrp <interface> peer <addr> nh <addr> [nh-table-id <ID>]", + .function = nhrp_add, +}; +/* *INDENT-ON* */ + +static clib_error_t * +nhrp_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 = nhrp_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 (nhrp_delete_command, static) = { + .path = "delete nhrp", + .short_help = "delete nhrp <interface> peer <addr>", + .function = nhrp_del, +}; +/* *INDENT-ON* */ + +static walk_rc_t +nhrp_show_one (index_t nei, void *ctx) +{ + vlib_cli_output (ctx, "%U", format_nhrp_entry, nei); + + return (WALK_CONTINUE); +} + + +static clib_error_t * +nhrp_show (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + nhrp_walk (nhrp_show_one, vm); + return (NULL); +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (nhrp_show_command, static) = { + .path = "show nhrp", + .short_help = "show nhrp", + .function = nhrp_show, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |