diff options
Diffstat (limited to 'src/plugins/sixrd/sixrd.c')
-rw-r--r-- | src/plugins/sixrd/sixrd.c | 934 |
1 files changed, 665 insertions, 269 deletions
diff --git a/src/plugins/sixrd/sixrd.c b/src/plugins/sixrd/sixrd.c index ee198f21004..66ad19b7811 100644 --- a/src/plugins/sixrd/sixrd.c +++ b/src/plugins/sixrd/sixrd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * Copyright (c) 2018 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: @@ -12,18 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#include "sixrd.h" -#include <vnet/plugin/plugin.h> - -#include <vnet/fib/fib_table.h> -#include <vnet/fib/ip6_fib.h> -#include <vnet/adj/adj.h> -#include <vpp/app/version.h> - -/* +/** * This code supports the following sixrd modes: - * + * * 32 EA bits (Complete IPv4 address is embedded): * ea_bits_len = 32 * IPv4 suffix is embedded: @@ -32,196 +23,544 @@ * ea_bits_len = 0 */ +#include "sixrd.h" +#include <vnet/plugin/plugin.h> +#include <vlibapi/api.h> +#include <vlibmemory/api.h> +#include <vnet/adj/adj.h> +#include <vnet/fib/fib_table.h> +#include <vnet/fib/ip6_fib.h> +#include <vnet/adj/adj_midchain.h> +#include <vnet/adj/adj_delegate.h> +#include <vnet/dpo/lookup_dpo.h> +#include <vpp/app/version.h> // Really needed? + +/* define message IDs */ +#include "sixrd_msg_enum.h" + +/* define message structures */ +#define vl_typedefs +#include "sixrd_all_api_h.h" +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include "sixrd_all_api_h.h" +#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 "sixrd_all_api_h.h" +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n, v) static u32 api_version = (v); +#include "sixrd_all_api_h.h" +#undef vl_api_version + +#define REPLY_MSG_ID_BASE sm->msg_id_base +#include <vlibapi/api_helper_macros.h> + +extern vlib_node_registration_t ip4_sixrd_node; + +/** + * Adj delegate data + */ +typedef struct sixrd_adj_delegate_t_ +{ + /** + * linkage to the adj + */ + u32 adj_index; + + /** + * Linnkage to the FIB node graph + */ + fib_node_t sixrd_node; + + /** + * tracking of the IPv4 next-hop + */ + fib_node_index_t sixrd_fib_entry_index; + + /** + * sibling on the fib-entry + */ + u32 sixrd_sibling; +} sixrd_adj_delegate_t; + +/** + * Pool of delegate structs + */ +static sixrd_adj_delegate_t *sixrd_adj_delegate_pool; + +/** + * Adj delegate registered type + */ +static adj_delegate_type_t sixrd_adj_delegate_type; + +/** + * FIB node registered type + */ +static fib_node_type_t sixrd_fib_node_type; + +static inline sixrd_adj_delegate_t * +sixrd_adj_from_base (adj_delegate_t * ad) +{ + if (NULL == ad) + { + return (NULL); + } + return (pool_elt_at_index (sixrd_adj_delegate_pool, ad->ad_index)); +} + +static inline const sixrd_adj_delegate_t * +sixrd_adj_from_const_base (const adj_delegate_t * ad) +{ + if (NULL == ad) + { + return (NULL); + } + return (pool_elt_at_index (sixrd_adj_delegate_pool, ad->ad_index)); +} + sixrd_main_t sixrd_main; -int -sixrd_create_domain (ip6_address_t *ip6_prefix, - u8 ip6_prefix_len, - ip4_address_t *ip4_prefix, - u8 ip4_prefix_len, - ip4_address_t *ip4_src, - u32 *sixrd_domain_index, - u16 mtu) +static void +sixrd_fixup (vlib_main_t * vm, + ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data) { - dpo_id_t dpo_v6 = DPO_INVALID, dpo_v4 = DPO_INVALID; - sixrd_main_t *mm = &sixrd_main; - fib_node_index_t fei; - sixrd_domain_t *d; - - /* Get domain index */ - pool_get_aligned(mm->domains, d, CLIB_CACHE_LINE_BYTES); - memset(d, 0, sizeof (*d)); - *sixrd_domain_index = d - mm->domains; - - /* Init domain struct */ - d->ip4_prefix.as_u32 = ip4_prefix->as_u32; - d->ip4_prefix_len = ip4_prefix_len; - d->ip6_prefix = *ip6_prefix; - d->ip6_prefix_len = ip6_prefix_len; - d->ip4_src = *ip4_src; - d->mtu = mtu; - - if (ip4_prefix_len < 32) - d->shift = 64 - ip6_prefix_len + (32 - ip4_prefix_len); - - /* Create IPv6 route/adjacency */ - fib_prefix_t pfx6 = { - .fp_proto = FIB_PROTOCOL_IP6, - .fp_len = d->ip6_prefix_len, - .fp_addr = { - .ip6 = d->ip6_prefix, - }, - }; - sixrd_dpo_create(DPO_PROTO_IP6, - *sixrd_domain_index, - &dpo_v6); - fib_table_entry_special_dpo_add(0, &pfx6, - FIB_SOURCE_SIXRD, - FIB_ENTRY_FLAG_EXCLUSIVE, - &dpo_v6); - dpo_reset (&dpo_v6); + ip4_header_t *ip4 = vlib_buffer_get_current (b0); + ip6_header_t *ip6 = vlib_buffer_get_current (b0) + sizeof (ip4_header_t); + const sixrd_tunnel_t *t = data; + + ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); + ip4->dst_address.as_u32 = + sixrd_get_addr_net (t, ip6->dst_address.as_u64[0]); + ip4->checksum = ip4_header_checksum (ip4); +} + +static void +ip6ip_fixup (vlib_main_t * vm, + ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data) +{ + const sixrd_tunnel_t *t = data; + ip4_header_t *ip4 = vlib_buffer_get_current (b0); + ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); + ip4->dst_address.as_u32 = + sixrd_get_addr_net (t, adj->sub_type.nbr.next_hop.as_u64[0]); + ip4->checksum = ip4_header_checksum (ip4); +} + +static sixrd_tunnel_t * +find_tunnel_by_sw_if_index (u32 sw_if_index) +{ + sixrd_main_t *sm = &sixrd_main; + u32 ti = sm->tunnel_index_by_sw_if_index[sw_if_index]; + if (ti == ~0) + { + clib_warning ("Not our tunnel\n"); + return (0); + } + return pool_elt_at_index (sm->tunnels, ti); +} + +static sixrd_tunnel_t * +find_tunnel (ip6_address_t * ip6_prefix) +{ + sixrd_main_t *sm = &sixrd_main; + sixrd_tunnel_t *d; + + /* *INDENT-OFF* */ + pool_foreach (d, sm->tunnels, + ({ + if (!memcmp (&d->ip6_prefix, ip6_prefix, 16)) + return d; + })); + /* *INDENT-ON* */ + return 0; +} + + +static u8 * +sixrd_build_rewrite (vnet_main_t * vnm, + u32 sw_if_index, + vnet_link_t link_type, const void *dst_address) +{ + u8 *rewrite = NULL; + sixrd_tunnel_t *t; + + t = find_tunnel_by_sw_if_index (sw_if_index); + if (!t) + { + return 0; + } + + vec_validate (rewrite, sizeof (ip4_header_t) - 1); + ip4_header_t *ip4 = (ip4_header_t *) rewrite; + ip4->ip_version_and_header_length = 0x45; + ip4->ttl = 64; + ip4->protocol = IP_PROTOCOL_IPV6; + /* fixup ip4 header length and checksum after-the-fact */ + ip4->src_address.as_u32 = t->ip4_src.as_u32; + ip4->dst_address.as_u32 = 0; + ip4->checksum = ip4_header_checksum (ip4); + + return rewrite; +} + +static void +ip6ip_tunnel_stack (adj_index_t ai, u32 fib_entry_index) +{ + sixrd_main_t *sm = &sixrd_main; + ip_adjacency_t *adj = adj_get (ai); + sixrd_tunnel_t *t; + u32 sw_if_index = adj->rewrite_header.sw_if_index; + + if ((vec_len (sm->tunnel_index_by_sw_if_index) < sw_if_index) || + (~0 == sm->tunnel_index_by_sw_if_index[sw_if_index])) + return; + + t = + pool_elt_at_index (sm->tunnels, + sm->tunnel_index_by_sw_if_index[sw_if_index]); /* - * Multiple SIXRD domains may share same source IPv4 TEP - * In this case the route will exist and be SixRD sourced. - * Find the adj (if any) already contributed and modify it + * find the adjacency that is contributed by the FIB entry + * that this tunnel resolves via, and use it as the next adj + * in the midchain */ - fib_prefix_t pfx4 = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr = { - .ip4 = d->ip4_src, - }, + if (vnet_hw_interface_get_flags (vnet_get_main (), t->hw_if_index) & + VNET_HW_INTERFACE_FLAG_LINK_UP) + { + adj_nbr_midchain_stack (ai, + fib_entry_contribute_ip_forwarding + (fib_entry_index)); + } + else + { + adj_nbr_midchain_unstack (ai); + } +} + +static void +sixrd_tunnel_stack (adj_index_t ai, u32 fib_index) +{ + dpo_id_t dpo = DPO_INVALID; + sixrd_main_t *sm = &sixrd_main; + ip_adjacency_t *adj = adj_get (ai); + u32 sw_if_index = adj->rewrite_header.sw_if_index; + + if ((vec_len (sm->tunnel_index_by_sw_if_index) < sw_if_index) || + (~0 == sm->tunnel_index_by_sw_if_index[sw_if_index])) + return; + + if ((vec_len (sm->tunnel_index_by_sw_if_index) < sw_if_index) || + (sm->tunnel_index_by_sw_if_index[sw_if_index] == ~0)) + return; + + lookup_dpo_add_or_lock_w_fib_index (fib_index, DPO_PROTO_IP4, + LOOKUP_UNICAST, LOOKUP_INPUT_DST_ADDR, + LOOKUP_TABLE_FROM_CONFIG, &dpo); + adj_nbr_midchain_stack (ai, &dpo); +} + +const static ip46_address_t sixrd_special_nh = { + .ip6 = { + .as_u64 = { + [0] = 0xffffffffffffffff, + [1] = 0xffffffffffffffff, + }, + }, +}; + +static void +sixrd_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai) +{ + ip_adjacency_t *adj = adj_get (ai); + sixrd_tunnel_t *t = find_tunnel_by_sw_if_index (sw_if_index); + + if (!memcmp (&sixrd_special_nh, + &adj->sub_type.nbr.next_hop, sizeof (sixrd_special_nh))) + { + adj_nbr_midchain_update_rewrite (ai, sixrd_fixup, t, ADJ_FLAG_NONE, + sixrd_build_rewrite (vnm, sw_if_index, + adj_get_link_type + (ai), NULL)); + sixrd_tunnel_stack (ai, t->fib_index); + } + else + { + sixrd_adj_delegate_t *sixrd_ad; + ip4_address_t da4; + + da4.as_u32 = + sixrd_get_addr_net (t, adj->sub_type.nbr.next_hop.as_u64[0]); + + fib_prefix_t pfx = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 32, + .fp_addr = {.ip4 = da4,} + , + }; + + adj_nbr_midchain_update_rewrite + (ai, ip6ip_fixup, t, + ADJ_FLAG_NONE, + sixrd_build_rewrite (vnm, sw_if_index, + adj_get_link_type (ai), NULL)); + + sixrd_ad = + sixrd_adj_from_base (adj_delegate_get (adj, sixrd_adj_delegate_type)); + if (NULL == sixrd_ad) + { + pool_get (sixrd_adj_delegate_pool, sixrd_ad); + fib_node_init (&sixrd_ad->sixrd_node, sixrd_fib_node_type); + sixrd_ad->adj_index = ai; + sixrd_ad->sixrd_fib_entry_index = + fib_table_entry_special_add (t->fib_index, &pfx, + FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE); + sixrd_ad->sixrd_sibling = + fib_entry_child_add (sixrd_ad->sixrd_fib_entry_index, + sixrd_fib_node_type, + sixrd_ad - sixrd_adj_delegate_pool); + + adj_delegate_add (adj, + sixrd_adj_delegate_type, + sixrd_ad - sixrd_adj_delegate_pool); + + ip6ip_tunnel_stack (ai, sixrd_ad->sixrd_fib_entry_index); + } + } +} + + +clib_error_t * +sixrd_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags) +{ + /* Always up */ + vnet_hw_interface_set_flags (vnm, hw_if_index, + VNET_HW_INTERFACE_FLAG_LINK_UP); + return /* no error */ 0; +} + +/* *INDENT-OFF* */ +VNET_HW_INTERFACE_CLASS (sixrd_hw_interface_class) = +{ + .name = "ip6ip-6rd", + .build_rewrite = sixrd_build_rewrite, + .update_adjacency = sixrd_update_adj, +}; + +VNET_DEVICE_CLASS (sixrd_device_class) = +{ + .name = "ip6ip-6rd", + .admin_up_down_function = sixrd_interface_admin_up_down, +#ifdef SOON + .clear counter = 0; +#endif +}; +/* *INDENT-ON* */ + +static int +sixrd_create_tunnel (ip6_address_t * ip6_prefix, u8 ip6_prefix_len, + ip4_address_t * ip4_prefix, u8 ip4_prefix_len, + ip4_address_t * ip4_src, u16 mtu, bool security_check, + u32 fib_index, u32 * sixrd_tunnel_index) +{ + sixrd_main_t *sm = &sixrd_main; + sixrd_tunnel_t *t; + + if (fib_index == ~0) + return VNET_API_ERROR_NO_SUCH_FIB; + + if ((ip6_prefix_len + 32 - ip4_prefix_len) > 64) + return VNET_API_ERROR_INVALID_VALUE; + + /* Tunnel already configured */ + if (find_tunnel (ip6_prefix)) + return VNET_API_ERROR_INVALID_VALUE; + /* Tunnel already configured for this source */ + if (find_tunnel_by_ip4_address (ip4_src)) + return VNET_API_ERROR_INVALID_VALUE; + + /* Get tunnel index */ + pool_get_aligned (sm->tunnels, t, CLIB_CACHE_LINE_BYTES); + memset (t, 0, sizeof (*t)); + t->tunnel_index = t - sm->tunnels; + + /* Init tunnel struct */ + t->ip4_prefix.as_u32 = ip4_prefix->as_u32; + t->ip4_prefix_len = ip4_prefix_len; + t->ip6_prefix = *ip6_prefix; + t->ip6_prefix_len = ip6_prefix_len; + t->ip4_src = *ip4_src; + t->mtu = mtu ? mtu : SIXRD_DEFAULT_MTU; + t->security_check = security_check; + + t->shift = (ip4_prefix_len < 32) ? + 64 - ip6_prefix_len - (32 - ip4_prefix_len) : 0; + + /* Create interface */ + u32 hw_if_index = vnet_register_interface (vnet_get_main (), + sixrd_device_class.index, + t->tunnel_index, + sixrd_hw_interface_class.index, + t->tunnel_index); + + /* Default the interface to up and enable IPv6 (payload) */ + vnet_hw_interface_t *hi = + vnet_get_hw_interface (vnet_get_main (), hw_if_index); + t->hw_if_index = hw_if_index; + t->fib_index = fib_index; + t->sw_if_index = hi->sw_if_index; + + hi->max_l3_packet_bytes[VLIB_RX] = hi->max_l3_packet_bytes[VLIB_TX] = + t->mtu; + + vec_validate_init_empty (sm->tunnel_index_by_sw_if_index, hi->sw_if_index, + ~0); + sm->tunnel_index_by_sw_if_index[hi->sw_if_index] = t->tunnel_index; + + hash_set (sm->tunnel_by_ip, ip4_src->as_u32, t->tunnel_index); + + vnet_hw_interface_set_flags (vnet_get_main (), hw_if_index, + VNET_HW_INTERFACE_FLAG_LINK_UP); + vnet_sw_interface_set_flags (vnet_get_main (), hi->sw_if_index, + VNET_SW_INTERFACE_FLAG_ADMIN_UP); + + /* Create IPv6 route/adjacency */ + fib_prefix_t pfx6 = { + .fp_proto = FIB_PROTOCOL_IP6, + .fp_len = t->ip6_prefix_len, + .fp_addr = {.ip6 = t->ip6_prefix,} + , }; - fei = fib_table_lookup_exact_match(0, &pfx4); - - if (FIB_NODE_INDEX_INVALID != fei) - { - dpo_id_t dpo = DPO_INVALID; - - if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_SIXRD, &dpo)) - { - /* - * modify the existing adj to indicate it's shared - * skip to route add. - * It is locked to pair with the unlock below. - */ - const dpo_id_t *sd_dpo; - sixrd_dpo_t *sd; - - ASSERT(DPO_LOAD_BALANCE == dpo.dpoi_type); - - sd_dpo = load_balance_get_bucket(dpo.dpoi_index, 0); - sd = sixrd_dpo_get (sd_dpo->dpoi_index); - - sd->sd_domain = ~0; - dpo_copy (&dpo_v4, sd_dpo); - dpo_reset (&dpo); - - goto route_add; - } - } - /* first time addition of the route */ - sixrd_dpo_create(DPO_PROTO_IP4, - *sixrd_domain_index, - &dpo_v4); - -route_add: - /* - * Create ip4 route. This is a reference counted add. If the prefix - * already exists and is SixRD sourced, it is now SixRD source n+1 times - * and will need to be removed n+1 times. - */ - fib_table_entry_special_dpo_add(0, &pfx4, - FIB_SOURCE_SIXRD, - FIB_ENTRY_FLAG_EXCLUSIVE, - &dpo_v4); - dpo_reset (&dpo_v4); + + fib_table_entry_update_one_path (fib_index, &pfx6, + FIB_SOURCE_CLI, FIB_ENTRY_FLAG_ATTACHED, + DPO_PROTO_IP6, &sixrd_special_nh, + hi->sw_if_index, + ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); + + *sixrd_tunnel_index = hi->sw_if_index; + + ip4_register_protocol (IP_PROTOCOL_IPV6, ip4_sixrd_node.index); return 0; } /* - * sixrd_delete_domain + * sixrd_delete_tunnel */ int -sixrd_delete_domain (u32 sixrd_domain_index) +sixrd_delete_tunnel (u32 sw_if_index) { - sixrd_main_t *mm = &sixrd_main; - sixrd_domain_t *d; - - if (pool_is_free_index(mm->domains, sixrd_domain_index)) { - clib_warning("SIXRD domain delete: domain does not exist: %d", - sixrd_domain_index); - return -1; - } - - d = pool_elt_at_index(mm->domains, sixrd_domain_index); - - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr = { - .ip4 = d->ip4_src, - }, - }; - fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_SIXRD); + sixrd_main_t *sm = &sixrd_main; + sixrd_tunnel_t *t = find_tunnel_by_sw_if_index (sw_if_index); + + if (!t) + { + clib_warning ("SIXRD tunnel delete: tunnel does not exist: %d", + sw_if_index); + return -1; + } fib_prefix_t pfx6 = { - .fp_proto = FIB_PROTOCOL_IP6, - .fp_len = d->ip6_prefix_len, - .fp_addr = { - .ip6 = d->ip6_prefix, - }, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_len = t->ip6_prefix_len, + .fp_addr = {.ip6 = t->ip6_prefix,} + , }; - fib_table_entry_special_remove(0, &pfx6, FIB_SOURCE_SIXRD); + fib_table_entry_special_remove (0, &pfx6, FIB_SOURCE_CLI); + vnet_sw_interface_set_flags (vnet_get_main (), t->sw_if_index, + 0 /* down */ ); + + sm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0; + + hash_unset (sm->tunnel_by_ip, t->ip4_src.as_u32); - pool_put(mm->domains, d); + vnet_delete_hw_interface (vnet_get_main (), t->hw_if_index); + + pool_put (sm->tunnels, t); return 0; } static clib_error_t * -sixrd_add_domain_command_fn (vlib_main_t *vm, - unformat_input_t *input, - vlib_cli_command_t *cmd) +sixrd_add_del_tunnel_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; ip4_address_t ip4_prefix; ip6_address_t ip6_prefix; ip4_address_t ip4_src; - u32 ip6_prefix_len=0, ip4_prefix_len=0, sixrd_domain_index; + u32 ip6_prefix_len = 0, ip4_prefix_len = 0, sixrd_tunnel_index; u32 num_m_args = 0; /* Optional arguments */ u32 mtu = 0; + u32 fib_index = 0; clib_error_t *error = 0; + bool is_add = true, security_check = false; /* Get a line of input. */ - if (!unformat_user(input, unformat_line_input, line_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, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix, &ip6_prefix_len)) - num_m_args++; - else if (unformat(line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix, &ip4_prefix_len)) - num_m_args++; - else if (unformat(line_input, "ip4-src %U", unformat_ip4_address, &ip4_src)) - num_m_args++; - else if (unformat(line_input, "mtu %d", &mtu)) - num_m_args++; - else { - error = clib_error_return(0, "unknown input `%U'", - format_unformat_error, line_input); - goto done; + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = false; + if (unformat (line_input, "security-check")) + security_check = true; + else + if (unformat + (line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix, + &ip6_prefix_len)) + num_m_args++; + else if (unformat (line_input, "ip4-pfx %U/%d", unformat_ip4_address, + &ip4_prefix, &ip4_prefix_len)) + num_m_args++; + else + if (unformat + (line_input, "ip4-src %U", unformat_ip4_address, &ip4_src)) + num_m_args++; + else if (unformat (line_input, "mtu %d", &mtu)) + num_m_args++; + else if (unformat (line_input, "fib-id %d", &fib_index)) + ; + else + { + error = + clib_error_return (0, "unknown input `%U'", format_unformat_error, + line_input); + goto done; + } } - } - - if (num_m_args < 3) { - error = clib_error_return(0, "mandatory argument(s) missing"); - goto done; - } - sixrd_create_domain(&ip6_prefix, ip6_prefix_len, &ip4_prefix, ip4_prefix_len, - &ip4_src, &sixrd_domain_index, mtu); + if (num_m_args < 3) + { + error = clib_error_return (0, "mandatory argument(s) missing"); + goto done; + } + if (is_add) + { + int rv = sixrd_create_tunnel (&ip6_prefix, ip6_prefix_len, &ip4_prefix, + ip4_prefix_len, &ip4_src, mtu, + security_check, + fib_index, &sixrd_tunnel_index); + if (rv) + error = clib_error_return (0, "adding tunnel failed"); + } + else + { + sixrd_tunnel_t *t = find_tunnel (&ip6_prefix); + if (t) + { + sixrd_delete_tunnel (t->sw_if_index); + } + } done: unformat_free (line_input); @@ -229,151 +568,208 @@ done: return error; } -static clib_error_t * -sixrd_del_domain_command_fn (vlib_main_t *vm, - unformat_input_t *input, - vlib_cli_command_t *cmd) +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (sixrd_add_del_tunnel_command, static) = { - unformat_input_t _line_input, *line_input = &_line_input; - u32 num_m_args = 0; - u32 sixrd_domain_index; - clib_error_t *error = 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, "index %d", &sixrd_domain_index)) - num_m_args++; - else { - error = clib_error_return(0, "unknown input `%U'", - format_unformat_error, line_input); - goto done; - } - } + .path = "create 6rd tunnel", + .short_help = "create 6rd tunnel ip6-pfx <ip6-pfx> ip4-pfx <ip4-pfx> " + "ip4-src <ip4-addr> [del]", + .function = sixrd_add_del_tunnel_command_fn, +}; +/* *INDENT-ON* */ - if (num_m_args != 1) { - error = clib_error_return(0, "mandatory argument(s) missing"); - goto done; - } +static void +vl_api_sixrd_add_tunnel_t_handler (vl_api_sixrd_add_tunnel_t * mp) +{ + sixrd_main_t *sm = &sixrd_main; + vl_api_sixrd_add_tunnel_reply_t *rmp; + u32 sixrd_tunnel_index; + + int rv = sixrd_create_tunnel ((ip6_address_t *) & mp->ip6_prefix, + mp->ip6_prefix_len, + (ip4_address_t *) & mp->ip4_prefix, + mp->ip4_prefix_len, + (ip4_address_t *) & mp->ip4_src, + ntohs (mp->mtu), + mp->security_check, ntohl (mp->fib_index), + &sixrd_tunnel_index); + + REPLY_MACRO2 (VL_API_SIXRD_ADD_TUNNEL_REPLY, ( + { + rmp->sw_if_index = + htonl (sixrd_tunnel_index); + })); +} - sixrd_delete_domain(sixrd_domain_index); +static void +vl_api_sixrd_del_tunnel_t_handler (vl_api_sixrd_del_tunnel_t * mp) +{ + sixrd_main_t *sm = &sixrd_main; + vl_api_sixrd_del_tunnel_reply_t *rmp; -done: - unformat_free (line_input); + int rv = sixrd_delete_tunnel (ntohl (mp->sw_if_index)); - return error; + REPLY_MACRO (VL_API_SIXRD_DEL_TUNNEL_REPLY); } -static u8 * -format_sixrd_domain (u8 *s, va_list *args) +/* List of message types that this plugin understands */ + +#define foreach_sixrd_plugin_api_msg \ +_(SIXRD_ADD_TUNNEL, sixrd_add_tunnel) \ +_(SIXRD_DEL_TUNNEL, sixrd_del_tunnel) + +/* *INDENT-OFF* */ +VLIB_PLUGIN_REGISTER() = { + .version = VPP_BUILD_VER, + .description = "IPv6 Rapid Deployment on IPv4 Infrastructure (RFC5969)", +}; +/* *INDENT-ON* */ + +/** + * @brief Set up the API message handling tables. + */ +static clib_error_t * +sixrd_plugin_api_hookup (vlib_main_t * vm) { - sixrd_domain_t *d = va_arg(*args, sixrd_domain_t *); - sixrd_main_t *mm = &sixrd_main; + sixrd_main_t *sm = &sixrd_main; - s = format(s, - "[%d] ip6-pfx %U/%d ip4-pfx %U/%d ip4-src %U mtu %d", - d - mm->domains, - format_ip6_address, &d->ip6_prefix, d->ip6_prefix_len, - format_ip4_address, &d->ip4_prefix, d->ip4_prefix_len, - format_ip4_address, &d->ip4_src, d->mtu); +#define _(N, n) \ + vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), #n, \ + vl_api_##n##_t_handler, vl_noop_handler, \ + vl_api_##n##_t_endian, vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_sixrd_plugin_api_msg; +#undef _ - return s; + return 0; } -static clib_error_t * -show_sixrd_domain_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) +#define vl_msg_name_crc_list +#include "sixrd_all_api_h.h" +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (sixrd_main_t * sm, api_main_t * am) { - sixrd_main_t *mm = &sixrd_main; - sixrd_domain_t *d; +#define _(id, n, crc) \ + vl_msg_api_add_msg_name_crc(am, #n "_" #crc, id + sm->msg_id_base); + foreach_vl_msg_name_crc_sixrd; +#undef _ +} - if (pool_elts(mm->domains) == 0) - vlib_cli_output(vm, "No SIXRD domains are configured..."); +static void +sixrd_adj_delegate_adj_deleted (adj_delegate_t * aed) +{ + sixrd_adj_delegate_t *sixrd_ad; - pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_sixrd_domain, d);})); + sixrd_ad = sixrd_adj_from_base (aed); - return 0; + fib_entry_child_remove (sixrd_ad->sixrd_fib_entry_index, + sixrd_ad->sixrd_sibling); + fib_table_entry_delete_index (sixrd_ad->sixrd_fib_entry_index, + FIB_SOURCE_RR); + pool_put (sixrd_adj_delegate_pool, sixrd_ad); } -static clib_error_t * -show_sixrd_stats_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) +static u8 * +sixrd_adj_delegate_format (const adj_delegate_t * aed, u8 * s) { - sixrd_main_t *mm = &sixrd_main; - sixrd_domain_t *d; - int domains = 0, domaincount = 0; - if (pool_elts (mm->domains) == 0) - vlib_cli_output (vm, "No SIXRD domains are configured..."); - - pool_foreach(d, mm->domains, ({ - domains += sizeof(*d); - domaincount++; - })); + const sixrd_adj_delegate_t *sixrd_ad; - vlib_cli_output(vm, "SIXRD domains structure: %d\n", sizeof (sixrd_domain_t)); - vlib_cli_output(vm, "SIXRD domains: %d (%d bytes)\n", domaincount, domains); + sixrd_ad = sixrd_adj_from_const_base (aed); - return 0; + s = format (s, "SIXRD:[fib-entry:%d]", sixrd_ad->sixrd_fib_entry_index); + + return (s); } -/* - * packet trace format function - */ -u8 * -format_sixrd_trace (u8 *s, va_list *args) +static void +sixrd_fib_node_last_lock_gone (fib_node_t * node) +{ + // top of the dependency tree, locks not managed here. +} + +static sixrd_adj_delegate_t * +sixrd_adj_delegate_from_fib_node (fib_node_t * node) +{ + return ((sixrd_adj_delegate_t *) (((char *) node) - + STRUCT_OFFSET_OF (sixrd_adj_delegate_t, + sixrd_node))); +} + +static fib_node_back_walk_rc_t +sixrd_fib_node_back_walk_notify (fib_node_t * node, + fib_node_back_walk_ctx_t * ctx) { - CLIB_UNUSED(vlib_main_t *vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED(vlib_node_t *node) = va_arg (*args, vlib_node_t *); - sixrd_trace_t *t = va_arg (*args, sixrd_trace_t *); - u32 sixrd_domain_index = t->sixrd_domain_index; + sixrd_adj_delegate_t *sixrd_ad; - s = format(s, "SIXRD domain index: %d", sixrd_domain_index); + sixrd_ad = sixrd_adj_delegate_from_fib_node (node); - return s; + ip6ip_tunnel_stack (sixrd_ad->adj_index, sixrd_ad->sixrd_fib_entry_index); + + return (FIB_NODE_BACK_WALK_CONTINUE); } -VLIB_CLI_COMMAND(sixrd_add_domain_command, static) = { - .path = "sixrd add domain", - .short_help = - "sixrd add domain ip6-pfx <ip6-pfx> ip4-pfx <ip4-pfx> ip4-src <ip4-addr>", - .function = sixrd_add_domain_command_fn, -}; +/** + * Function definition to get a FIB node from its index + */ +static fib_node_t * +sixrd_fib_node_get (fib_node_index_t index) +{ + sixrd_adj_delegate_t *sixrd_ad; -VLIB_CLI_COMMAND(sixrd_del_command, static) = { - .path = "sixrd del domain", - .short_help = - "sixrd del domain index <domain>", - .function = sixrd_del_domain_command_fn, -}; + sixrd_ad = pool_elt_at_index (sixrd_adj_delegate_pool, index); -VLIB_CLI_COMMAND(show_sixrd_domain_command, static) = { - .path = "show sixrd domain", - .function = show_sixrd_domain_command_fn, -}; + return (&sixrd_ad->sixrd_node); +} -VLIB_CLI_COMMAND(show_sixrd_stats_command, static) = { - .path = "show sixrd stats", - .function = show_sixrd_stats_command_fn, +/** + * VFT registered with the adjacency delegate + */ +const static adj_delegate_vft_t sixrd_adj_delegate_vft = { + .adv_adj_deleted = sixrd_adj_delegate_adj_deleted, + .adv_format = sixrd_adj_delegate_format, }; -/* *INDENT-OFF* */ -VLIB_PLUGIN_REGISTER () ={ - .version = VPP_BUILD_VER, - .description = "IPv6 Rapid Deployment on IPv4 Infrastructure (RFC5969)", +/** + * VFT registered with the FIB node for the adj delegate + */ +const static fib_node_vft_t sixrd_fib_node_vft = { + .fnv_get = sixrd_fib_node_get, + .fnv_last_lock = sixrd_fib_node_last_lock_gone, + .fnv_back_walk = sixrd_fib_node_back_walk_notify, }; -/* *INDENT-ON* */ -static clib_error_t * sixrd_init (vlib_main_t * vm) +static clib_error_t * +sixrd_init (vlib_main_t * vm) { - sixrd_main_t *mm = &sixrd_main; + sixrd_main_t *sm = &sixrd_main; + clib_error_t *error = 0; + u8 *name; + + name = format (0, "sixrd_%08x%c", api_version, 0); + + sm->msg_id_base = + vl_msg_api_get_msg_ids ((char *) name, VL_MSG_FIRST_AVAILABLE); + vec_free (name); + error = sixrd_plugin_api_hookup (vm); - mm->vnet_main = vnet_get_main(); - mm->vlib_main = vm; + setup_message_id_table (sm, &api_main); - sixrd_dpo_module_init (); + sixrd_adj_delegate_type = + adj_delegate_register_new_type (&sixrd_adj_delegate_vft); + sixrd_fib_node_type = fib_node_register_new_type (&sixrd_fib_node_vft); - return (NULL); + return error; } VLIB_INIT_FUNCTION (sixrd_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |