diff options
Diffstat (limited to 'src/vnet/lisp-gpe/lisp_gpe_sub_interface.c')
-rw-r--r-- | src/vnet/lisp-gpe/lisp_gpe_sub_interface.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/src/vnet/lisp-gpe/lisp_gpe_sub_interface.c b/src/vnet/lisp-gpe/lisp_gpe_sub_interface.c new file mode 100644 index 00000000000..5b69bd157b8 --- /dev/null +++ b/src/vnet/lisp-gpe/lisp_gpe_sub_interface.c @@ -0,0 +1,278 @@ +/* + * 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. + */ +/** + * @file + * @brief LISP sub-interfaces. + * + */ +#include <vnet/lisp-gpe/lisp_gpe_tenant.h> +#include <vnet/lisp-gpe/lisp_gpe_sub_interface.h> +#include <vnet/fib/fib_table.h> +#include <vnet/interface.h> + +/** + * @brief Pool of all l3-sub-interfaces + */ +static lisp_gpe_sub_interface_t *lisp_gpe_sub_interface_pool; + +/** + * A DB of all LISP L3 sub-interfaces. The key is:{VNI,l-RLOC} + */ +static uword *lisp_gpe_sub_interfaces; + +/** + * A DB of all VNET L3 sub-interfaces. The key is:{VNI,l-RLOC} + * Used in the data-plane for interface lookup on decap. + */ +uword *lisp_gpe_sub_interfaces_sw_if_index; + +/** + * The next available sub-interface ID. FIXME + */ +static u32 lisp_gpe_sub_interface_id; + + +static index_t +lisp_gpe_sub_interface_db_find (const ip_address_t * lrloc, u32 vni) +{ + uword *p; + + lisp_gpe_sub_interface_key_t key = { + .local_rloc = *lrloc, + .vni = clib_host_to_net_u32 (vni), + }; + + p = hash_get_mem (lisp_gpe_sub_interfaces, &key); + + if (NULL == p) + return (INDEX_INVALID); + else + return (p[0]); +} + +static void +lisp_gpe_sub_interface_db_insert (const lisp_gpe_sub_interface_t * l3s) +{ + hash_set_mem (lisp_gpe_sub_interfaces, + &l3s->key, l3s - lisp_gpe_sub_interface_pool); + hash_set_mem (lisp_gpe_sub_interfaces_sw_if_index, + &l3s->key, l3s->sw_if_index); +} + +static void +lisp_gpe_sub_interface_db_remove (const lisp_gpe_sub_interface_t * l3s) +{ + hash_unset_mem (lisp_gpe_sub_interfaces, &l3s->key); + hash_unset_mem (lisp_gpe_sub_interfaces_sw_if_index, &l3s->key); +} + +lisp_gpe_sub_interface_t * +lisp_gpe_sub_interface_get_i (index_t l3si) +{ + return (pool_elt_at_index (lisp_gpe_sub_interface_pool, l3si)); +} + +static void +lisp_gpe_sub_interface_set_table (u32 sw_if_index, u32 table_id) +{ + fib_node_index_t fib_index; + + fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id); + ASSERT (FIB_NODE_INDEX_INVALID != fib_index); + + vec_validate (ip4_main.fib_index_by_sw_if_index, sw_if_index); + ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index; + + fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, table_id); + ASSERT (FIB_NODE_INDEX_INVALID != fib_index); + + vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index); + ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index; +} + +static void +lisp_gpe_sub_interface_unset_table (u32 sw_if_index, u32 table_id) +{ + ip4_main.fib_index_by_sw_if_index[sw_if_index] = 0; + ip4_sw_interface_enable_disable (sw_if_index, 0); + + ip6_main.fib_index_by_sw_if_index[sw_if_index] = 0; + ip6_sw_interface_enable_disable (sw_if_index, 0); +} + +index_t +lisp_gpe_sub_interface_find_or_create_and_lock (const ip_address_t * lrloc, + u32 overlay_table_id, u32 vni) +{ + lisp_gpe_sub_interface_t *l3s; + index_t l3si; + + l3si = lisp_gpe_sub_interface_db_find (lrloc, clib_host_to_net_u32 (vni)); + + if (INDEX_INVALID == l3si) + { + u32 main_sw_if_index, sub_sw_if_index; + + /* + * find the main interface from the VNI + */ + main_sw_if_index = + lisp_gpe_tenant_l3_iface_add_or_lock (vni, overlay_table_id); + + vnet_sw_interface_t sub_itf_template = { + .type = VNET_SW_INTERFACE_TYPE_SUB, + .flood_class = VNET_FLOOD_CLASS_NORMAL, + .sup_sw_if_index = main_sw_if_index, + .sub.id = lisp_gpe_sub_interface_id++, + }; + + if (NULL != vnet_create_sw_interface (vnet_get_main (), + &sub_itf_template, + &sub_sw_if_index)) + return (INDEX_INVALID); + + pool_get (lisp_gpe_sub_interface_pool, l3s); + memset (l3s, 0, sizeof (*l3s)); + l3s->key = clib_mem_alloc (sizeof (*l3s->key)); + memset (l3s->key, 0, sizeof (*l3s->key)); + + l3s->key->local_rloc = *lrloc; + l3s->key->vni = clib_host_to_net_u32 (vni); + l3s->main_sw_if_index = main_sw_if_index; + l3s->sw_if_index = sub_sw_if_index; + l3s->eid_table_id = overlay_table_id; + + l3si = (l3s - lisp_gpe_sub_interface_pool); + + // FIXME. enable When we get an adj + ip6_sw_interface_enable_disable (l3s->sw_if_index, 1); + ip4_sw_interface_enable_disable (l3s->sw_if_index, 1); + + vnet_sw_interface_set_flags (vnet_get_main (), + l3s->sw_if_index, + VNET_SW_INTERFACE_FLAG_ADMIN_UP); + + lisp_gpe_sub_interface_db_insert (l3s); + } + else + { + l3s = lisp_gpe_sub_interface_get_i (l3si); + l3s->eid_table_id = overlay_table_id; + } + + lisp_gpe_sub_interface_set_table (l3s->sw_if_index, l3s->eid_table_id); + l3s->locks++; + + return (l3si); +} + +void +lisp_gpe_sub_interface_unlock (index_t l3si) +{ + lisp_gpe_sub_interface_t *l3s; + + l3s = lisp_gpe_sub_interface_get_i (l3si); + + l3s->locks--; + + if (0 == l3s->locks) + { + lisp_gpe_sub_interface_unset_table (l3s->sw_if_index, + l3s->eid_table_id); + + lisp_gpe_tenant_l3_iface_unlock (clib_net_to_host_u32 (l3s->key->vni)); + vnet_sw_interface_set_flags (vnet_get_main (), l3s->sw_if_index, 0); + vnet_delete_sub_interface (l3s->sw_if_index); + + lisp_gpe_sub_interface_db_remove (l3s); + + clib_mem_free (l3s->key); + pool_put (lisp_gpe_sub_interface_pool, l3s); + } +} + +const lisp_gpe_sub_interface_t * +lisp_gpe_sub_interface_get (index_t l3si) +{ + return (lisp_gpe_sub_interface_get_i (l3si)); +} + +u8 * +format_lisp_gpe_sub_interface (u8 * s, va_list ap) +{ + lisp_gpe_sub_interface_t *l3s = va_arg (ap, lisp_gpe_sub_interface_t *); + vnet_main_t *vnm = vnet_get_main (); + + s = format (s, "%=16U", + format_vnet_sw_interface_name, + vnm, vnet_get_sw_interface (vnm, l3s->sw_if_index)); + s = format (s, "%=10d", clib_net_to_host_u32 (l3s->key->vni)); + s = format (s, "%=12d", l3s->sw_if_index); + s = format (s, "%U", format_ip_address, &l3s->key->local_rloc); + + return (s); +} + +/** CLI command to show LISP-GPE interfaces. */ +static clib_error_t * +lisp_gpe_sub_interface_show (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + lisp_gpe_sub_interface_t *l3s; + + vlib_cli_output (vm, "%=16s%=10s%=12s%s", "Name", "VNI", "SW IF Index", + "local RLOC"); + + /* *INDENT-OFF* */ + pool_foreach (l3s, lisp_gpe_sub_interface_pool, + ({ + vlib_cli_output (vm, "%U", format_lisp_gpe_sub_interface, l3s); + })); + /* *INDENT-ON* */ + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (lisp_gpe_sub_interface_command) = { + .path = "show lisp gpe sub-interface", + .short_help = "show lisp gpe sub-interface", + .function = lisp_gpe_sub_interface_show, +}; +/* *INDENT-ON* */ + +static clib_error_t * +lisp_gpe_sub_interface_module_init (vlib_main_t * vm) +{ + lisp_gpe_sub_interfaces = + hash_create_mem (0, + sizeof (lisp_gpe_sub_interface_key_t), sizeof (uword)); + lisp_gpe_sub_interfaces_sw_if_index = + hash_create_mem (0, + sizeof (lisp_gpe_sub_interface_key_t), sizeof (uword)); + + return (NULL); +} + +VLIB_INIT_FUNCTION (lisp_gpe_sub_interface_module_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |