diff options
-rw-r--r-- | vnet/Makefile.am | 23 | ||||
-rw-r--r-- | vnet/vnet/ip/udp.h | 99 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/control.c | 1362 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/control.h | 157 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/gid_dictionary.c | 347 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/gid_dictionary.h | 72 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/lisp_cp_messages.h | 433 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/lisp_msg_serdes.c | 270 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/lisp_msg_serdes.h | 46 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/lisp_types.c | 475 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/lisp_types.h | 163 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/packets.c | 248 | ||||
-rw-r--r-- | vnet/vnet/lisp-cp/packets.h | 72 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/decap.c | 316 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/encap.c | 319 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe.c | 1302 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe.h | 122 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe_error.def | 3 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe_packet.h | 12 |
19 files changed, 5136 insertions, 705 deletions
diff --git a/vnet/Makefile.am b/vnet/Makefile.am index b254d80ad48..52b5a6d0779 100644 --- a/vnet/Makefile.am +++ b/vnet/Makefile.am @@ -425,18 +425,37 @@ nobase_include_HEADERS += \ vnet/nsh-vxlan-gpe/nsh_vxlan_gpe_error.def ######################################## +# LISP control plane: lisp-cp +######################################## + +libvnet_la_SOURCES += \ + vnet/lisp-cp/lisp_types.c \ + vnet/lisp-cp/control.c \ + vnet/lisp-cp/gid_dictionary.c \ + vnet/lisp-cp/lisp_msg_serdes.c \ + vnet/lisp-cp/packets.c + +nobase_include_HEADERS += \ + vnet/lisp-cp/lisp_types.h \ + vnet/lisp-cp/packets.h \ + vnet/lisp-cp/gid_dictionary.h \ + vnet/lisp-cp/lisp_cp_messages.h \ + vnet/lisp-cp/lisp_msg_serdes.h \ + vnet/lisp-cp/control.h + +######################################## # Tunnel protocol: lisp-gpe ######################################## libvnet_la_SOURCES += \ vnet/lisp-gpe/lisp_gpe.c \ vnet/lisp-gpe/encap.c \ - vnet/lisp-gpe/decap.c + vnet/lisp-gpe/decap.c nobase_include_HEADERS += \ vnet/lisp-gpe/lisp_gpe.h \ vnet/lisp-gpe/lisp_gpe_packet.h \ - vnet/lisp-gpe/lisp_gpe_error.def + vnet/lisp-gpe/lisp_gpe_error.def ######################################## # DHCP client diff --git a/vnet/vnet/ip/udp.h b/vnet/vnet/ip/udp.h index 65eef29cb10..e9ee1e32faa 100644 --- a/vnet/vnet/ip/udp.h +++ b/vnet/vnet/ip/udp.h @@ -38,6 +38,7 @@ _ (67, dhcp_to_server) \ _ (68, dhcp_to_client) \ _ (500, ikev2) \ _ (4341, lisp_gpe) \ +_ (4342, lisp_cp) \ _ (4739, ipfix) \ _ (4789, vxlan) \ _ (4790, vxlan_gpe) \ @@ -47,6 +48,7 @@ _ (6633, vpath_3) #define foreach_udp6_dst_port \ _ (547, dhcpv6_to_server) \ _ (546, dhcpv6_to_client) \ +_ (4342, lisp_cp6) \ _ (6633, vpath6_3) typedef enum { @@ -109,5 +111,100 @@ void udp_register_dst_port (vlib_main_t * vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4); -#endif /* included_udp_h */ +always_inline void +ip4_udp_encap_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 * ec0, u32 ec_len) +{ + ip4_header_t * ip0; + ip_csum_t sum0; + u16 old_l0 = 0; + u16 new_l0; + udp_header_t * udp0; + + vlib_buffer_advance (b0, - ec_len); + ip0 = vlib_buffer_get_current(b0); + + /* Apply the encap string. */ +#if DPDK + rte_memcpy(ip0, ec0, ec_len); +#else + memcpy(ip0, ec0, ec_len); +#endif + + /* fix the <bleep>ing outer-IP checksum */ + sum0 = ip0->checksum; + /* old_l0 always 0, see the rewrite setup */ + new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); + + sum0 = ip_csum_update(sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + ip0->length = new_l0; + + /* Fix UDP length */ + udp0 = (udp_header_t *)(ip0+1); + new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) + - sizeof (*ip0)); + + udp0->length = new_l0; +} +always_inline void +ip4_udp_encap_two (vlib_main_t * vm, vlib_buffer_t * b0, vlib_buffer_t * b1, + u8 * ec0, u8 * ec1, u32 ec_len) +{ + ip4_header_t * ip0, *ip1; + ip_csum_t sum0, sum1; + u16 old_l0 = 0, old_l1 = 0; + u16 new_l0, new_l1; + udp_header_t * udp0, *udp1; + + ASSERT(_vec_len(ec0) == _vec_len(ec1)); + + vlib_buffer_advance (b0, -ec_len); + vlib_buffer_advance (b1, -ec_len); + + ip0 = vlib_buffer_get_current (b0); + ip1 = vlib_buffer_get_current (b1); + + /* Apply the encap string */ +#ifdef DPDK + rte_memcpy (ip0, ec0, ec_len); + rte_memcpy (ip1, ec1, ec_len); +#else + memcpy (ip0, ec0, ec_len); + memcpy (ip1, ec1, ec_len); +#endif + + /* fix the <bleep>ing outer-IP checksum */ + sum0 = ip0->checksum; + sum1 = ip1->checksum; + + /* old_l0 always 0, see the rewrite setup */ + new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); + new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1)); + + sum0 = ip_csum_update(sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */); + sum1 = ip_csum_update(sum1, old_l1, new_l1, ip4_header_t, + length /* changed member */); + + ip0->checksum = ip_csum_fold (sum0); + ip1->checksum = ip_csum_fold (sum1); + + ip0->length = new_l0; + ip1->length = new_l1; + + /* Fix UDP length */ + udp0 = (udp_header_t *) (ip0 + 1); + udp1 = (udp_header_t *) (ip1 + 1); + + new_l0 = clib_host_to_net_u16 ( + vlib_buffer_length_in_chain (vm, b0) - sizeof(*ip0)); + new_l1 = clib_host_to_net_u16 ( + vlib_buffer_length_in_chain (vm, b1) - sizeof(*ip1)); + udp0->length = new_l0; + udp1->length = new_l1; + return; +} + +#endif /* included_udp_h */ diff --git a/vnet/vnet/lisp-cp/control.c b/vnet/vnet/lisp-cp/control.c new file mode 100644 index 00000000000..f4cb16fa016 --- /dev/null +++ b/vnet/vnet/lisp-cp/control.c @@ -0,0 +1,1362 @@ +/* + * 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/lisp-cp/control.h> +#include <vnet/lisp-cp/packets.h> +#include <vnet/lisp-cp/lisp_msg_serdes.h> +#include <vnet/lisp-gpe/lisp_gpe.h> + +/* Adds mapping to map-cache but does NOT program LISP forwarding */ +int +vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a, + u32 * map_index_result) +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + u32 mi, * map_indexp, map_index, i; + mapping_t * m; + u32 ** eid_indexes; + + mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->deid); + if (a->is_add) + { + /* TODO check if overwriting and take appropriate actions */ + if (mi != GID_LOOKUP_MISS) { + clib_warning("eid %U found in the eid-table", format_ip_address, + &a->deid); + return -1; + } + + pool_get(lcm->mapping_pool, m); + m->eid = a->deid; + m->locator_set_index = a->locator_set_index; + m->ttl = a->ttl; + m->local = a->local; + + map_index = m - lcm->mapping_pool; + gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->deid, map_index, + 1); + + if (pool_is_free_index(lcm->locator_set_pool, a->locator_set_index)) + { + clib_warning("Locator set with index %d doesn't exist", + a->locator_set_index); + return -1; + } + + /* add eid to list of eids supported by locator-set */ + vec_validate (lcm->locator_set_to_eids, a->locator_set_index); + eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids, + a->locator_set_index); + vec_add1(eid_indexes[0], map_index); + + if (a->local) + { + /* mark as local */ + vec_add1(lcm->local_mappings_indexes, map_index); + + /* XXX do something else? */ + } + map_index_result[0] = map_index; + } + else + { + if (mi != ~0) { + clib_warning("eid %U not found in the eid-table", format_ip_address, + &a->deid); + return -1; + } + + /* clear locator-set to eids binding */ + eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids, + a->locator_set_index); + for (i = 0; i < vec_len(eid_indexes[0]); i++) + { + map_indexp = vec_elt_at_index(eid_indexes[0], i); + if (map_indexp[0] == mi) + break; + } + vec_del1(eid_indexes[0], i); + + /* remove local mark if needed */ + m = pool_elt_at_index(lcm->mapping_pool, mi); + if (m->local) + { + u32 k, * lm_indexp; + for (k = 0; k < vec_len(lcm->local_mappings_indexes); k++) + { + lm_indexp = vec_elt_at_index(lcm->local_mappings_indexes, k); + if (lm_indexp[0] == mi) + break; + } + vec_del1(lcm->local_mappings_indexes, k); + } + else + { + /* remove tunnel ??? */ + } + + /* remove mapping from dictionary */ + gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->deid, 0, 0); + pool_put_index (lcm->mapping_pool, mi); + } + + return 0; +} + +static clib_error_t * +lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + unformat_input_t _line_input, * line_input = &_line_input; + u8 is_add = 1; + gid_address_t eid; + ip_prefix_t * prefp = &gid_address_ippref(&eid); + gid_address_t * eids = 0; + clib_error_t * error = 0; + u8 * locator_set_name; + u32 locator_set_index = 0, map_index = 0; + uword * p; + vnet_lisp_add_del_mapping_args_t _a, * a = &_a; + + gid_address_type (&eid) = IP_PREFIX; + + /* 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, "add")) + is_add = 1; + else if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "eid %U", unformat_ip_prefix, prefp)) + { + vec_add1(eids, eid); + } + else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name)) + { + p = hash_get_mem(lcm->locator_set_index_by_name, locator_set_name); + if (!p) + { + error = clib_error_return(0, "locator-set %s doesn't exist", + locator_set_name); + goto done; + } + locator_set_index = p[0]; + } + else + { + error = unformat_parse_error(line_input); + goto done; + } + } + + /* XXX treat batch configuration */ + a->deid = eid; + a->is_add = is_add; + a->locator_set_index = locator_set_index; + a->local = 1; + + vnet_lisp_add_del_mapping (a, &map_index); + done: + vec_free(eids); + return error; +} + +VLIB_CLI_COMMAND (lisp_add_del_local_eid_command) = { + .path = "lisp eid-table", + .short_help = "lisp eid-table add/del eid <eid> locator-set <locator-set>", + .function = lisp_add_del_local_eid_command_fn, +}; + +static clib_error_t * +lisp_show_local_eid_table_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + mapping_t * mapit; + + vlib_cli_output (vm, "%=20s%=16s", "EID", "Locator"); + pool_foreach (mapit, lcm->mapping_pool, + ({ + u8 * msg = 0; + locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool, + mapit->locator_set_index); + vlib_cli_output (vm, "%-16U%16v", format_gid_address, &mapit->eid, + ls->name); + vec_free (msg); + })); + + return 0; +} + +VLIB_CLI_COMMAND (lisp_cp_show_local_eid_table_command) = { + .path = "show lisp eid-table", + .short_help = "Shows local EID table", + .function = lisp_show_local_eid_table_command_fn, +}; + +/* cleans locator to locator-set data and removes locators not part of + * any locator-set */ +static void +clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi) +{ + u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes; + locator_set_t * ls = pool_elt_at_index(lcm->locator_set_pool, lsi); + for (i = 0; i < vec_len(ls->locator_indices); i++) + { + loc_indexp = vec_elt_at_index(ls->locator_indices, i); + ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets, + loc_indexp[0]); + for (j = 0; j < vec_len(ls_indexes[0]); j++) + { + ls_indexp = vec_elt_at_index(ls_indexes[0], j); + if (ls_indexp[0] == lsi) + break; + } + + /* delete index for removed locator-set*/ + vec_del1(ls_indexes[0], j); + + /* delete locator if it's part of no locator-set */ + if (vec_len (ls_indexes[0]) == 0) + pool_put_index(lcm->locator_pool, loc_indexp[0]); + + /* remove from local locator-set vector */ + if (ls->local) + { + u32 k, *llocp; + for (k = 0; k < vec_len(lcm->local_locator_set_indexes); k++) + { + llocp = vec_elt_at_index(lcm->local_locator_set_indexes, k); + if (llocp[0] == lsi) + break; + } + vec_del1(lcm->local_locator_set_indexes, k); + } + } +} +int +vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a, + u32 * ls_result) +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + locator_set_t * ls; + locator_t * loc, * itloc; + uword _p = (u32)~0, * p = &_p; + u32 loc_index, ls_index, ** ls_indexes; + + if (a->is_add) + { + /* check if overwrite */ + if (a->local) + p = hash_get_mem(lcm->locator_set_index_by_name, a->name); + else + *p = a->index; + + /* overwrite */ + if (p && p[0] != (u32)~0) + { + ls = pool_elt_at_index(lcm->locator_set_pool, p[0]); + if (!ls) + { + clib_warning("locator-set %d to be overwritten doesn't exist!", + p[0]); + return -1; + } + + /* clean locator to locator-set vectors and remove locators if + * they're not part of another locator-set */ + clean_locator_to_locator_set (lcm, p[0]); + + /* remove locator indices from locator set */ + vec_free(ls->locator_indices); + + ls_index = p[0]; + + if (ls_result) + ls_result[0] = p[0]; + } + /* new locator-set */ + else + { + pool_get(lcm->locator_set_pool, ls); + ls_index = ls - lcm->locator_set_pool; + + if (a->local) + { + ls->name = vec_dup(a->name); + + if (!lcm->locator_set_index_by_name) + lcm->locator_set_index_by_name = hash_create_vec( + /* size */0, sizeof(ls->name[0]), sizeof(uword)); + hash_set_mem(lcm->locator_set_index_by_name, ls->name, ls_index); + + /* mark as local locator-set */ + vec_add1(lcm->local_locator_set_indexes, ls_index); + } + ls->local = a->local; + if (ls_result) + ls_result[0] = ls_index; + } + + /* allocate locators */ + vec_foreach (itloc, a->locators) + { + pool_get(lcm->locator_pool, loc); + loc[0] = itloc[0]; + loc_index = loc - lcm->locator_pool; + + vec_add1(ls->locator_indices, loc_index); + + vec_validate (lcm->locator_to_locator_sets, loc_index); + ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets, + loc_index); + vec_add1(ls_indexes[0], ls_index); + } + } + else + { + /* find locator-set */ + if (a->local) + { + p = hash_get_mem(lcm->locator_set_index_by_name, a->name); + if (!p) + { + clib_warning("locator-set %v doesn't exists", a->name); + return -1; + } + } + else + *p = a->index; + + ls = pool_elt_at_index(lcm->locator_set_pool, p[0]); + if (!ls) + { + clib_warning("locator-set with index %d doesn't exists", p[0]); + return -1; + } +// /* XXX what happens when a mapping is configured to use the loc-set ? */ +// if (vec_len (vec_elt_at_index(lcm->locator_set_to_eids, p[0])) != 0) +// { +// clib_warning ("Can't delete a locator that supports a mapping!"); +// return -1; +// } + + /* clean locator to locator-sets data */ + clean_locator_to_locator_set (lcm, p[0]); + + if (ls->local) + { + u32 it, lsi; + + vec_foreach_index(it, lcm->local_locator_set_indexes) + { + lsi = vec_elt(lcm->local_locator_set_indexes, it); + if (lsi == p[0]) + { + vec_del1(lcm->local_locator_set_indexes, it); + break; + } + } + hash_unset_mem(lcm->locator_set_index_by_name, ls->name); + vec_free(ls->name); + } + pool_put(lcm->locator_set_pool, ls); + } + return 0; +} + +static clib_error_t * +lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + lisp_gpe_main_t * lgm = &lisp_gpe_main; + vnet_main_t * vnm = lgm->vnet_main; + unformat_input_t _line_input, * line_input = &_line_input; + u8 is_add = 1; + clib_error_t * error = 0; + u8 * locator_set_name = 0; + locator_t locator, * locators = 0; + vnet_lisp_add_del_locator_set_args_t _a, * a = &_a; + u32 ls_index = 0; + + memset(&locator, 0, sizeof(locator)); + memset(a, 0, sizeof(a[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, "add %_%v%_", &locator_set_name)) + is_add = 1; + else if (unformat (line_input, "del %_%v%_", &locator_set_name)) + is_add = 0; + else if (unformat (line_input, "iface %U p %d w %d", + unformat_vnet_sw_interface, vnm, &locator.sw_if_index, + &locator.priority, &locator.weight)) + { + locator.local = 1; + vec_add1(locators, locator); + } + else + { + error = unformat_parse_error(line_input); + goto done; + } + } + + a->name = locator_set_name; + a->locators = locators; + a->is_add = is_add; + a->local = 1; + + vnet_lisp_add_del_locator_set(a, &ls_index); + + done: + vec_free(locators); + vec_free(locator_set_name); + return error; +} + +VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = { + .path = "lisp locator-set", + .short_help = "lisp locator-set add/del <name> <iface-name> <priority> <weight>", + .function = lisp_add_del_locator_set_command_fn, +}; + +static clib_error_t * +lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + locator_set_t * lsit; + locator_t * loc; + u32 * locit; + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + + vlib_cli_output (vm, "%=20s%=16s%=16s%=16s", "Locator-set", "Locator", + "Priority", "Weight"); + pool_foreach (lsit, lcm->locator_set_pool, + ({ + u8 * msg = 0; + msg = format (msg, "%-16v", lsit->name); + vec_foreach (locit, lsit->locator_indices) + { + loc = pool_elt_at_index (lcm->locator_pool, locit[0]); + if (loc->local) + msg = format (msg, "%16d%16d%16d", loc->sw_if_index, loc->priority, + loc->weight); + else + msg = format (msg, "%16U%16d%16d", format_gid_address, &loc->address, + loc->priority, loc->weight); + } + vlib_cli_output (vm, "%v", msg); + vec_free (msg); + })); + return 0; +} + +VLIB_CLI_COMMAND (lisp_cp_show_locator_sets_command) = { + .path = "show lisp locator-set", + .short_help = "Shows locator-sets", + .function = lisp_cp_show_locator_sets_command_fn, +}; + +int +vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a) +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + ip_address_t * addr; + u32 i; + + if (a->is_add) + { + vec_foreach(addr, lcm->map_resolvers) + { + if (!ip_address_cmp (addr, &a->address)) + { + clib_warning("map-resolver %U already exists!", format_ip_address, + &a->address); + return -1; + } + } + vec_add1(lcm->map_resolvers, a->address); + } + else + { + for (i = 0; i < vec_len(lcm->map_resolvers); i++) + { + addr = vec_elt_at_index(lcm->map_resolvers, i); + if (!ip_address_cmp (addr, &a->address)) + { + vec_delete(lcm->map_resolvers, 1, i); + break; + } + } + } + return 0; +} + +static clib_error_t * +lisp_add_del_map_resolver_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, * line_input = &_line_input; + u8 is_add = 1; + ip_address_t ip_addr; + clib_error_t * error = 0; + vnet_lisp_add_del_map_resolver_args_t _a, * a = &_a; + + /* 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, "add")) + is_add = 1; + else if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr)) + ; + else + { + error = unformat_parse_error(line_input); + goto done; + } + } + a->is_add = is_add; + a->address = ip_addr; + vnet_lisp_add_del_map_resolver (a); + + done: + return error; +} + +VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = { + .path = "lisp map-resolver", + .short_help = "lisp map-resolver add/del <ip_address>", + .function = lisp_add_del_map_resolver_command_fn, +}; + +/* Statistics (not really errors) */ +#define foreach_lisp_cp_lookup_error \ +_(DROP, "drop") \ +_(MAP_REQUESTS_SENT, "map-request sent") + +static char * lisp_cp_lookup_error_strings[] = { +#define _(sym,string) string, + foreach_lisp_cp_lookup_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym, + foreach_lisp_cp_lookup_error +#undef _ + LISP_CP_LOOKUP_N_ERROR, +} lisp_cp_lookup_error_t; + +typedef enum +{ + LISP_CP_LOOKUP_NEXT_DROP, + LISP_CP_LOOKUP_NEXT_IP4_LOOKUP, + LISP_CP_LOOKUP_NEXT_IP6_LOOKUP, + LISP_CP_LOOKUP_N_NEXT, +} lisp_cp_lookup_next_t; + +typedef struct +{ + gid_address_t dst_eid; + ip4_address_t map_resolver_ip; +} lisp_cp_lookup_trace_t; + +u8 * +format_lisp_cp_lookup_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + lisp_cp_lookup_trace_t * t = va_arg (*args, lisp_cp_lookup_trace_t *); + + s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U", + format_ip4_address, &t->map_resolver_ip, format_gid_address, + &t->dst_eid); + return s; +} + +static u32 +ip_fib_lookup_with_table (lisp_cp_main_t * lcm, u32 fib_index, + ip_address_t * dst) +{ + if (ip_addr_version (dst) == IP4) + return ip4_fib_lookup_with_table (lcm->im4, fib_index, &ip_addr_v4(dst), + 0); + else + return ip6_fib_lookup_with_table (lcm->im6, fib_index, &ip_addr_v6(dst)); +} + +void +get_local_iface_ip_for_dst (lisp_cp_main_t *lcm, ip_address_t * dst, + ip_address_t * sloc) +{ + u32 adj_index; + ip_adjacency_t * adj; + ip_interface_address_t * ia = 0; + ip_lookup_main_t * lm = &lcm->im4->lookup_main; + ip4_address_t * l4 = 0; + ip6_address_t * l6 = 0; + + adj_index = ip_fib_lookup_with_table (lcm, 0, dst); + adj = ip_get_adjacency (lm, adj_index); + + if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP) + { + ia = pool_elt_at_index(lm->if_address_pool, adj->if_address_index); + if (ip_addr_version(dst) == IP4) + { + l4 = ip_interface_address_get_address (lm, ia); + } + else + { + l6 = ip_interface_address_get_address (lm, ia); + } + } + else if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE) + { + /* find sw_if_index in rewrite header */ + u32 sw_if_index = adj->rewrite_header.sw_if_index; + + /* find suitable address */ + if (ip_addr_version(dst) == IP4) + { + /* find the first ip address */ + foreach_ip_interface_address (&lcm->im4->lookup_main, ia, + sw_if_index, 1 /* unnumbered */, + ({ + l4 = ip_interface_address_get_address (&lcm->im4->lookup_main, ia); + break; + })); + } + else + { + /* find the first ip address */ + foreach_ip_interface_address (&lcm->im6->lookup_main, ia, + sw_if_index, 1 /* unnumbered */, + ({ + l6 = ip_interface_address_get_address (&lcm->im6->lookup_main, ia); + break; + })); + } + } + else + { + clib_warning("Can't find local local interface ip for dst %U", + format_ip_address, dst); + return; + } + + if (l4) + { + ip_addr_v4(sloc).as_u32 = l4->as_u32; + ip_addr_version(sloc) = IP4; + } + else if (l6) + { + memcpy (&ip_addr_v6(sloc), l6, sizeof(*l6)); + ip_addr_version(sloc) = IP6; + } + else + { + clib_warning("Can't find local interface addr for dst %U", + format_ip_address, dst); + } +} + +static vlib_buffer_t * +build_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm, + gid_address_t * seid, gid_address_t * deid, + locator_set_t * loc_set, u8 is_smr_invoked, + u64 *nonce_res, u32 * bi_res) +{ + vlib_buffer_t * b; + u32 bi; + ip_address_t * mr_ip, sloc; + + if (vlib_buffer_alloc (vm, &bi, 1) != 1) + { + clib_warning ("Can't allocate buffer for Map-Request!"); + return 0; + } + + b = vlib_get_buffer (vm, bi); + + /* leave some space for the encap headers */ + vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN); + + /* put lisp msg */ + lisp_msg_put_mreq (lcm, b, seid, deid, loc_set, is_smr_invoked, nonce_res); + + /* push ecm: udp-ip-lisp */ + lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid); + + /* get map-resolver ip XXX use first*/ + mr_ip = vec_elt_at_index(lcm->map_resolvers, 0); + + /* get local iface ip to use in map-request XXX fib 0 for now*/ + get_local_iface_ip_for_dst (lcm, mr_ip, &sloc); + + /* push outer ip header */ + pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, &sloc, + mr_ip); + + bi_res[0] = bi; + return b; +} + +static void +send_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm, + gid_address_t * seid, gid_address_t * deid, + u8 is_smr_invoked) +{ + u32 next_index, bi = 0, * to_next, map_index; + vlib_buffer_t * b; + vlib_frame_t * f; + u64 nonce = 0; + locator_set_t * loc_set; + mapping_t * map; + pending_map_request_t * pmr; + + /* get locator-set for seid */ + map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid); + if (map_index == ~0) + { + clib_warning("No local mapping found in eid-table for %U!", + format_gid_address, seid); + return; + } + + map = pool_elt_at_index (lcm->mapping_pool, map_index); + + if (!map->local) + { + clib_warning("Mapping found for src eid %U is not marked as local!", + format_gid_address, seid); + return; + } + loc_set = pool_elt_at_index (lcm->locator_set_pool, map->locator_set_index); + + /* build the encapsulated map request */ + b = build_encapsulated_map_request (vm, lcm, seid, deid, loc_set, + is_smr_invoked, &nonce, &bi); + + if (!b) + return; + + vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0; + next_index = (ip_prefix_version(&gid_address_ippref(seid)) == IP4) ? + ip4_lookup_node.index : ip6_lookup_node.index; + + f = vlib_get_frame_to_node (vm, next_index); + + /* Enqueue the packet */ + to_next = vlib_frame_vector_args (f); + to_next[0] = bi; + f->n_vectors = 1; + vlib_put_frame_to_node (vm, next_index, f); + + /* add map-request to pending requests table */ + pool_get(lcm->pending_map_requests_pool, pmr); + gid_address_copy (&pmr->src, seid); + gid_address_copy (&pmr->dst, deid); + pmr->src_mapping_index = map_index; + hash_set(lcm->pending_map_requests_by_nonce, nonce, + pmr - lcm->pending_map_requests_pool); +} + +static void +get_src_and_dst (void *hdr, ip_address_t * src, ip_address_t *dst) +{ + ip4_header_t * ip4 = hdr; + ip6_header_t * ip6; + + if ((ip4->ip_version_and_header_length & 0xF0) == 0x40) + { + ip_addr_v4(src).as_u32 = ip4->src_address.as_u32; + ip_addr_version(src) = IP4; + ip_addr_v4(dst).as_u32 = ip4->dst_address.as_u32; + ip_addr_version(dst) = IP4; + } + else + { + ip6 = hdr; + memcpy (&ip_addr_v6(src), &ip6->src_address, sizeof(ip6->src_address)); + ip_addr_version(src) = IP6; + memcpy (&ip_addr_v6(dst), &ip6->dst_address, sizeof(ip6->dst_address)); + ip_addr_version(dst) = IP6; + } +} + +static uword +lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 * from, * to_next_drop; + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main(); + u32 pkts_mapped = 0; + uword n_left_from, n_left_to_next_drop; + + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + + while (n_left_from > 0) + { + vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, + to_next_drop, n_left_to_next_drop); + + while (n_left_from > 0 && n_left_to_next_drop > 0) + { + u32 pi0; + vlib_buffer_t * p0; + ip4_header_t * ip0; + gid_address_t src, dst; + ip_prefix_t * spref, * dpref; + + gid_address_type (&src) = IP_PREFIX; + spref = &gid_address_ippref(&src); + gid_address_type (&dst) = IP_PREFIX; + dpref = &gid_address_ippref(&dst); + + pi0 = from[0]; + from += 1; + n_left_from -= 1; + to_next_drop[0] = pi0; + to_next_drop += 1; + n_left_to_next_drop -= 1; + + p0 = vlib_get_buffer (vm, pi0); + p0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; + + /* src/dst eid pair */ + ip0 = vlib_buffer_get_current (p0); + get_src_and_dst (ip0, &ip_prefix_addr(spref), &ip_prefix_addr(dpref)); + ip_prefix_len(spref) = ip_address_max_len (ip_prefix_version(spref)); + ip_prefix_len(dpref) = ip_address_max_len (ip_prefix_version(dpref)); + + /* send map-request */ + send_encapsulated_map_request (vm, lcm, &src, &dst, 0); + + pkts_mapped++; + + if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) + { + lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, p0, + sizeof(*tr)); + gid_address_copy (&tr->dst_eid, &dst); + memcpy (&tr->map_resolver_ip, + vec_elt_at_index(lcm->map_resolvers, 0), + sizeof(ip_address_t)); + } + } + + vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, n_left_to_next_drop); + } + vlib_node_increment_counter (vm, node->node_index, + LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT, + pkts_mapped); + return from_frame->n_vectors; +} + +VLIB_REGISTER_NODE (lisp_cp_lookup_node) = { + .function = lisp_cp_lookup, + .name = "lisp-cp-lookup", + .vector_size = sizeof (u32), + .format_trace = format_lisp_cp_lookup_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = LISP_CP_LOOKUP_N_ERROR, + .error_strings = lisp_cp_lookup_error_strings, + + .n_next_nodes = LISP_CP_LOOKUP_N_NEXT, + + .next_nodes = { + [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + [LISP_CP_LOOKUP_NEXT_IP4_LOOKUP] = "ip4-lookup", + [LISP_CP_LOOKUP_NEXT_IP6_LOOKUP] = "ip6-lookup", + }, +}; + +/* lisp_cp_input statistics */ +#define foreach_lisp_cp_input_error \ +_(DROP, "drop") \ +_(MAP_REPLIES_RECEIVED, "map-replies received") + +static char * lisp_cp_input_error_strings[] = { +#define _(sym,string) string, + foreach_lisp_cp_input_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) LISP_CP_INPUT_ERROR_##sym, + foreach_lisp_cp_input_error +#undef _ + LISP_CP_INPUT_N_ERROR, +} lisp_cp_input_error_t; + +typedef enum +{ + LISP_CP_INPUT_NEXT_DROP, + LISP_CP_INPUT_N_NEXT, +} lisp_cp_input_next_t; + +typedef struct +{ + gid_address_t dst_eid; + ip4_address_t map_resolver_ip; +} lisp_cp_input_trace_t; + +u8 * +format_lisp_cp_input_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + CLIB_UNUSED(lisp_cp_input_trace_t * t) = va_arg (*args, lisp_cp_input_trace_t *); + + s = format (s, "LISP-CP-INPUT: TODO"); + return s; +} + +ip_interface_address_t * +ip_interface_get_first_interface_address (ip_lookup_main_t *lm, u32 sw_if_index, + u8 loop) +{ + vnet_main_t *vnm = vnet_get_main (); + vnet_sw_interface_t * swif = vnet_get_sw_interface (vnm, sw_if_index); + if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; + u32 ia = + (vec_len((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ? + vec_elt((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) : + (u32) ~0; + return pool_elt_at_index((lm)->if_address_pool, ia); +} + +void * +ip_interface_get_first_ip_addres (ip_lookup_main_t *lm, u32 sw_if_index, + u8 loop) +{ + ip_interface_address_t * ia = ip_interface_get_first_interface_address ( + lm, sw_if_index, loop); + return ip_interface_address_get_address (lm, ia); +} + +void +del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, + u32 dst_map_index) +{ + vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a; + fwd_entry_t * fe = 0; + uword * feip = 0; + memset(a, 0, sizeof(*a)); + + feip = hash_get(lcm->fwd_entry_by_mapping_index, dst_map_index); + if (!feip) + return; + + fe = pool_elt_at_index(lcm->fwd_entry_pool, feip[0]); + + /* delete dp fwd entry */ + u32 sw_if_index; + a->is_add = 0; + a->dlocator = fe->dst_loc; + a->slocator = fe->src_loc; + a->iid = 0; // XXX should be part of mapping/eid + gid_address_copy(&a->deid, &fe->deid); + + vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index); + + /* delete entry in fwd table */ + hash_unset(lcm->fwd_entry_by_mapping_index, dst_map_index); + pool_put(lcm->fwd_entry_pool, fe); +} + +void +add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index) +{ + mapping_t * src_map, * dst_map; + locator_set_t * dst_ls, * src_ls; + u32 i, minp = ~0; + locator_t * dl = 0; + uword * feip = 0; + vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a; + memset (a, 0, sizeof(*a)); + + /* remove entry if it already exists */ + feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index); + if (feip) + del_fwd_entry (lcm, src_map_index, dst_map_index); + + src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index); + dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index); + + /* XXX simple forwarding policy: first lowest (value) priority locator */ + dst_ls = pool_elt_at_index (lcm->locator_set_pool, + dst_map->locator_set_index); + for (i = 0; i < vec_len (dst_ls->locator_indices); i++) + { + u32 li = vec_elt (dst_ls->locator_indices, i); + locator_t * l = pool_elt_at_index (lcm->locator_pool, li); + if (l->priority < minp && gid_address_type(&l->address) == IP_PREFIX) + { + minp = l->priority; + dl = l; + } + } + if (dl) + { + src_ls = pool_elt_at_index (lcm->locator_set_pool, + src_map->locator_set_index); + for (i = 0; i < vec_len (src_ls->locator_indices); i++) + { + u32 li = vec_elt (src_ls->locator_indices, i); + locator_t * sl = pool_elt_at_index (lcm->locator_pool, li); + + if (ip_addr_version(&gid_address_ip(&dl->address)) == IP4) + { + ip4_address_t * l4; + l4 = ip_interface_get_first_ip_addres (&lcm->im4->lookup_main, + sl->sw_if_index, + 1 /* unnumbered */); + ip_addr_v4(&a->slocator) = *l4; + ip_addr_version(&a->slocator) = IP4; + } + else + { + ip6_address_t * l6; + l6 = ip_interface_get_first_ip_addres (&lcm->im6->lookup_main, + sl->sw_if_index, + 1 /* unnumbered */); + ip_addr_v6(&a->slocator) = *l6; + ip_addr_version(&a->slocator) = IP6; + } + } + } + /* insert data plane forwarding entry */ + u32 sw_if_index; + a->is_add = 1; + if (dl) + a->dlocator = gid_address_ip(&dl->address); + else + { + a->is_negative = 1; + a->action = dst_map->action; + } + + gid_address_copy (&a->deid, &dst_map->eid); + a->iid = 0; // XXX should be part of mapping/eid + u8 ipver = ip_prefix_version(&gid_address_ippref(&a->deid)); + a->decap_next_index = (ipver == IP4) ? + LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT; + /* XXX tunnels work only with IP4 now */ + vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index); + + /* add tunnel to fwd entry table XXX check return value from DP insertion */ + fwd_entry_t* fe; + pool_get (lcm->fwd_entry_pool, fe); + fe->dst_loc = a->dlocator; + fe->src_loc = a->slocator; + gid_address_copy (&fe->deid, &a->deid); + hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index, + fe - lcm->fwd_entry_pool); +} + +/* return 0 if the two locator sets are identical 1 otherwise */ +static u8 +compare_locators (lisp_cp_main_t *lcm, u32 * old_ls_indexes, + locator_t * new_locators) +{ + u32 i, old_li; + locator_t * old_loc, * new_loc; + + if (vec_len (old_ls_indexes) != vec_len(new_locators)) + return 1; + + for (i = 0; i < vec_len(new_locators); i++) + { + old_li = vec_elt(old_ls_indexes, i); + old_loc = pool_elt_at_index(lcm->locator_pool, old_li); + + new_loc = vec_elt_at_index(new_locators, i); + + if (locator_cmp (old_loc, new_loc)) + return 1; + } + return 0; +} + +void +process_map_reply (lisp_cp_main_t * lcm, vlib_buffer_t * b) +{ + u32 len = 0, i, ls_index = 0; + void * h; + vnet_lisp_add_del_locator_set_args_t _ls_arg, * ls_arg = &_ls_arg; + vnet_lisp_add_del_mapping_args_t _m_args, * m_args = &_m_args; + pending_map_request_t * pmr; + locator_t probed; + map_reply_hdr_t * mrep_hdr; + u64 nonce; + u32 dst_map_index, mi; + uword * pmr_index; + + mrep_hdr = vlib_buffer_get_current (b); + + /* Check pending requests table and nonce */ + nonce = MREP_NONCE(mrep_hdr); + pmr_index = hash_get(lcm->pending_map_requests_by_nonce, nonce); + if (!pmr_index) + { + clib_warning("No pending map-request entry with nonce %lu!", nonce); + return; + } + pmr = pool_elt_at_index(lcm->pending_map_requests_pool, pmr_index[0]); + + vlib_buffer_pull (b, sizeof(*mrep_hdr)); + + for (i = 0; i < MREP_REC_COUNT(mrep_hdr); i++) + { + memset (ls_arg, 0, sizeof(*ls_arg)); + memset (m_args, 0, sizeof(*m_args)); + + h = vlib_buffer_get_current (b); + m_args->ttl = clib_net_to_host_u32 (MAP_REC_TTL(h)); + m_args->action = MAP_REC_ACTION(h); + m_args->authoritative = MAP_REC_AUTH(h); + + len = lisp_msg_parse_mapping_record (b, &m_args->deid, &ls_arg->locators, + &probed); + if (len == ~0) + { + clib_warning ("Failed to parse mapping record!"); + vec_free(ls_arg->locators); + return; + } + + mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &m_args->deid); + + /* if mapping already exists, decide if locators (and forwarding) should + * be updated and be done */ + if (mi != ~0) + { + mapping_t * old_map; + locator_set_t * old_ls; + old_map = pool_elt_at_index(lcm->mapping_pool, mi); + + /* update mapping attributes */ + old_map->action = m_args->action; + old_map->authoritative = m_args->authoritative; + old_map->ttl = m_args->ttl; + + old_ls = pool_elt_at_index(lcm->locator_set_pool, + old_map->locator_set_index); + /* if the two locators are not equal, update them and forwarding + * otherwise there's nothing to be done */ + if (compare_locators (lcm, old_ls->locator_indices, ls_arg->locators)) + { + /* set locator-set index to overwrite */ + ls_arg->is_add = 1; + ls_arg->index = old_map->locator_set_index; + vnet_lisp_add_del_locator_set (ls_arg, 0); + add_fwd_entry (lcm, pmr->src_mapping_index, mi); + } + } + /* new mapping */ + else + { + /* add locator-set */ + ls_arg->is_add = 1; + ls_arg->index = ~0; + vnet_lisp_add_del_locator_set (ls_arg, &ls_index); + + /* add mapping */ + m_args->is_add = 1; + m_args->locator_set_index = ls_index; + vnet_lisp_add_del_mapping (m_args, &dst_map_index); + + /* add forwarding tunnel */ + add_fwd_entry (lcm, pmr->src_mapping_index, dst_map_index); + } + vec_free(ls_arg->locators); + } + + /* remove pending map request entry */ + hash_unset(lcm->pending_map_requests_by_nonce, nonce); + pool_put(lcm->pending_map_requests_pool, pmr); +} + +void +process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm, vlib_buffer_t * b) +{ + map_request_hdr_t * mreq_hdr; + gid_address_t src, dst; +// u64 nonce; + u32 i, len = 0; + gid_address_t * itr_rlocs = 0; + + mreq_hdr = vlib_buffer_get_current (b); + vlib_buffer_pull (b, sizeof(*mreq_hdr)); + +// nonce = MREQ_NONCE(mreq_hdr); + + if (!MREQ_SMR(mreq_hdr)) { + clib_warning("Only SMR Map-Requests supported for now!"); + return; + } + + /* parse src eid */ + len = lisp_msg_parse_addr (b, &src); + if (len == ~0) + return; + + /* for now we don't do anything with the itr's rlocs */ + len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs, MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1); + if (len == ~0) + return; + + /* parse eid records and send SMR-invoked map-requests */ + for (i = 0; i < MREQ_REC_COUNT(mreq_hdr); i++) + { + memset(&dst, 0, sizeof(dst)); + len = lisp_msg_parse_eid_rec (b, &dst); + if (len == ~0) + { + clib_warning("Can't parse map-request EID-record"); + return; + } + /* send SMR-invoked map-requests */ + send_encapsulated_map_request (vm, lcm, &dst, &src, /* invoked */ 1); + } +} + +static uword +lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, * from, * to_next_drop; + lisp_msg_type_e type; + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + + + while (n_left_from > 0) + { + u32 n_left_to_next_drop; + + vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP, + to_next_drop, n_left_to_next_drop); + while (n_left_from > 0 && n_left_to_next_drop > 0) + { + u32 bi0; + vlib_buffer_t * b0; + + bi0 = from[0]; + from += 1; + n_left_from -= 1; + to_next_drop[0] = bi0; + to_next_drop += 1; + n_left_to_next_drop -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + type = lisp_msg_type(vlib_buffer_get_current (b0)); + switch (type) + { + case LISP_MAP_REPLY: + process_map_reply (lcm, b0); + break; + case LISP_MAP_REQUEST: + process_map_request(vm, lcm, b0); + break; + default: + clib_warning("Unsupported LISP message type %d", type); + break; + } + + b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP]; + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + + } + } + + vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP, n_left_to_next_drop); + } + return from_frame->n_vectors; +} + +VLIB_REGISTER_NODE (lisp_cp_input_node) = { + .function = lisp_cp_input, + .name = "lisp-cp-input", + .vector_size = sizeof (u32), + .format_trace = format_lisp_cp_input_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = LISP_CP_INPUT_N_ERROR, + .error_strings = lisp_cp_input_error_strings, + + .n_next_nodes = LISP_CP_INPUT_N_NEXT, + + .next_nodes = { + [LISP_CP_INPUT_NEXT_DROP] = "error-drop", + }, +}; + +clib_error_t * +lisp_cp_init (vlib_main_t *vm) +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + clib_error_t * error = 0; + + if ((error = vlib_call_init_function (vm, lisp_gpe_init))) + return error; + + lcm->im4 = &ip4_main; + lcm->im6 = &ip6_main; + lcm->vlib_main = vm; + lcm->vnet_main = vnet_get_main(); + + gid_dictionary_init (&lcm->mapping_index_by_gid); + gid_dictionary_init (&lcm->mapping_index_by_gid); + + udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp, + lisp_cp_input_node.index, 1 /* is_ip4 */); + udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6, + lisp_cp_input_node.index, 0 /* is_ip4 */); + + return 0; +} + +VLIB_INIT_FUNCTION(lisp_cp_init); diff --git a/vnet/vnet/lisp-cp/control.h b/vnet/vnet/lisp-cp/control.h new file mode 100644 index 00000000000..713dce6a5b8 --- /dev/null +++ b/vnet/vnet/lisp-cp/control.h @@ -0,0 +1,157 @@ +/* + * 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 VNET_CONTROL_H_ +#define VNET_CONTROL_H_ + +#include <vnet/vnet.h> +#include <vnet/lisp-cp/gid_dictionary.h> +#include <vnet/lisp-cp/lisp_types.h> + +typedef struct +{ + gid_address_t src; + gid_address_t dst; + u32 src_mapping_index; +} pending_map_request_t; + +typedef struct +{ + gid_address_t seid; + gid_address_t deid; + ip_address_t src_loc; + ip_address_t dst_loc; +} fwd_entry_t; + +typedef enum +{ + IP4_MISS_PACKET, + IP6_MISS_PACKET +} miss_packet_type_t; + +typedef struct +{ + /* headers */ + u8 data[100]; + u32 length; + miss_packet_type_t type; +} miss_packet_t; + +typedef struct +{ + /* eid table */ + gid_dictionary_t mapping_index_by_gid; + + /* pool of mappings */ + mapping_t * mapping_pool; + + /* pool of locators */ + locator_t * locator_pool; + + /* pool of locator-sets */ + locator_set_t * locator_set_pool; + + /* vector of locator-set vectors composed of and indexed by locator index */ + u32 ** locator_to_locator_sets; + + /* hash map of locators by name */ + uword * locator_set_index_by_name; + + /* vector of eid index vectors supported and indexed by locator-set index */ + u32 ** locator_set_to_eids; + + /* vectors of indexes for local locator-sets and mappings */ + u32 * local_mappings_indexes; + u32 * local_locator_set_indexes; + + /* hash map of forwarding entries by mapping index */ + u32 * fwd_entry_by_mapping_index; + + /* forwarding entries pool */ + fwd_entry_t * fwd_entry_pool; + + /* hash map keyed by nonce of pending map-requests */ + uword * pending_map_requests_by_nonce; + + /* pool of pending map requests */ + pending_map_request_t * pending_map_requests_pool; + + /* vector of map-resolver addresses */ + ip_address_t * map_resolvers; + + /* commodity */ + ip4_main_t * im4; + ip6_main_t * im6; + vlib_main_t * vlib_main; + vnet_main_t * vnet_main; +} lisp_cp_main_t; + +/* lisp-gpe control plane */ +lisp_cp_main_t lisp_control_main; + +extern vlib_node_registration_t lisp_cp_input_node; +extern vlib_node_registration_t lisp_cp_lookup_node; + +clib_error_t * +lisp_cp_init (); + +typedef struct +{ + u8 is_add; + union + { + u8 * name; + u32 index; + }; + locator_t * locators; + u8 local; +} vnet_lisp_add_del_locator_set_args_t; + +int +vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a, + u32 * ls_index); + +typedef struct +{ + u8 is_add; + gid_address_t deid; + u32 locator_set_index; + + u32 ttl; + u8 action; + u8 authoritative; + + u8 local; +} vnet_lisp_add_del_mapping_args_t; + +int +vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t *a, + u32 * map_index); + +typedef struct +{ + u8 is_add; + ip_address_t address; +} vnet_lisp_add_del_map_resolver_args_t; + +int +vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a); + +always_inline lisp_cp_main_t * +vnet_lisp_cp_get_main() { + return &lisp_control_main; +} + +#endif /* VNET_CONTROL_H_ */ diff --git a/vnet/vnet/lisp-cp/gid_dictionary.c b/vnet/vnet/lisp-cp/gid_dictionary.c new file mode 100644 index 00000000000..dd10856c5ec --- /dev/null +++ b/vnet/vnet/lisp-cp/gid_dictionary.c @@ -0,0 +1,347 @@ +/* + * 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/lisp-cp/gid_dictionary.h> + +static u32 +ip4_lookup (gid_dictionary_t * db, u32 vni, ip_prefix_t *key) +{ + int i, len; + int rv; + BVT(clib_bihash_kv) kv, value; + + len = vec_len (db->ip4_prefix_lengths_in_search_order); + + for (i = 0; i < len; i++) + { + int dst_address_length = db->ip4_prefix_lengths_in_search_order[i]; + ip4_address_t * mask; + + ASSERT(dst_address_length >= 0 && dst_address_length <= 32); + + mask = &db->ip4_fib_masks[dst_address_length]; + + kv.key[0] = ((u64) vni << 32) | (ip_prefix_v4(key).as_u32 & mask->as_u32); + kv.key[1] = 0; + kv.key[2] = 0; + + rv = BV(clib_bihash_search_inline_2)(&db->ip4_lookup_table, &kv, &value); + if (rv == 0) + return value.value; + } + + return GID_LOOKUP_MISS; +} + +static u32 +ip6_lookup (gid_dictionary_t * db, u32 vni, ip_prefix_t *key) +{ + int i, len; + int rv; + BVT(clib_bihash_kv) kv, value; + + len = vec_len (db->ip6_prefix_lengths_in_search_order); + + for (i = 0; i < len; i++) + { + int dst_address_length = db->ip6_prefix_lengths_in_search_order[i]; + ip6_address_t * mask; + + ASSERT(dst_address_length >= 0 && dst_address_length <= 128); + + mask = &db->ip6_fib_masks[dst_address_length]; + + kv.key[0] = ip_prefix_v6(key).as_u64[0] & mask->as_u64[0]; + kv.key[1] = ip_prefix_v6(key).as_u64[1] & mask->as_u64[1]; + kv.key[2] = (u64)vni; + + rv = BV(clib_bihash_search_inline_2)(&db->ip6_lookup_table, &kv, &value); + if (rv == 0) + return value.value; + } + + return GID_LOOKUP_MISS; +} + +static u32 +ip_lookup (gid_dictionary_t * db, u32 vni, ip_prefix_t *key) +{ + /* XXX for now this only works with ip-prefixes, no lcafs */ + switch (ip_prefix_version (key)) + { + case IP4: + return ip4_lookup (db, vni, key); + break; + case IP6: + return ip6_lookup (db, vni, key); + break; + default: + clib_warning ("address type %d not supported!", ip_prefix_version(key)); + break; + } + return ~0; +} + +u32 +gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) +{ + /* XXX for now this only works with ip-prefixes, no lcafs */ + switch (gid_address_type (key)) + { + case IP_PREFIX: + return ip_lookup (db, 0, &gid_address_ippref(key)); + break; + default: + clib_warning ("address type %d not supported!", gid_address_type(key)); + break; + } + return ~0; +} + +static void +ip4_compute_prefix_lengths_in_search_order (gid_dictionary_t * db) +{ + int i; + vec_reset_length (db->ip4_prefix_lengths_in_search_order); + /* Note: bitmap reversed so this is in fact a longest prefix match */ + clib_bitmap_foreach (i, db->ip4_non_empty_dst_address_length_bitmap, + ({ + int dst_address_length = 32 - i; + vec_add1 (db->ip4_prefix_lengths_in_search_order, dst_address_length); + })); +} + +static u32 +add_del_ip4_key (gid_dictionary_t *db, u32 vni, ip_prefix_t * pref, u32 val, + u8 is_add) +{ + BVT(clib_bihash_kv) kv, value; + u32 old_val = ~0; + ip4_address_t key; + u8 plen = ip_prefix_len (pref); + + memcpy (&key, &ip_prefix_v4(pref), sizeof(key)); + key.as_u32 &= db->ip4_fib_masks[plen].as_u32; + if (is_add) + { + db->ip4_non_empty_dst_address_length_bitmap = clib_bitmap_set ( + db->ip4_non_empty_dst_address_length_bitmap, 32 - plen, + 1); + ip4_compute_prefix_lengths_in_search_order (db); + + db->ip4_prefix_len_refcount[plen]++; + } + else + { + ASSERT(db->ip4_prefix_len_refcount[plen] != 0); + + db->ip4_prefix_len_refcount[plen]--; + + if (db->ip4_prefix_len_refcount[plen] == 0) + { + db->ip4_non_empty_dst_address_length_bitmap = clib_bitmap_set ( + db->ip4_non_empty_dst_address_length_bitmap, 32 - plen, + 0); + ip4_compute_prefix_lengths_in_search_order (db); + } + } + + kv.key[0] = ((u64) vni << 32) | key.as_u32; + kv.key[1] = 0; + kv.key[2] = 0; + + if (BV(clib_bihash_search)(&db->ip4_lookup_table, &kv, &value) == 0) + old_val = value.value; + + if (!is_add) + BV(clib_bihash_add_del) (&db->ip4_lookup_table, &kv, 0 /* is_add */); + else + { + kv.value = val; + BV(clib_bihash_add_del) (&db->ip4_lookup_table, &kv, 1 /* is_add */); + } + return old_val; +} + +static void +ip6_compute_prefix_lengths_in_search_order (gid_dictionary_t * db) +{ + int i; + vec_reset_length (db->ip6_prefix_lengths_in_search_order); + /* Note: bitmap reversed so this is in fact a longest prefix match */ + clib_bitmap_foreach (i, db->ip6_non_empty_dst_address_length_bitmap, + ({ + int dst_address_length = 128 - i; + vec_add1 (db->ip6_prefix_lengths_in_search_order, dst_address_length); + })); +} + +static u32 +add_del_ip6_key (gid_dictionary_t *db, u32 vni, ip_prefix_t *pref, u32 val, + u8 is_add) +{ + BVT(clib_bihash_kv) kv, value; + u32 old_val = ~0; + ip6_address_t key; + u8 plen = ip_prefix_len (pref); + + memcpy (&key, &ip_prefix_v6(pref), sizeof(key)); + ip6_address_mask (&key, &db->ip6_fib_masks[plen]); + if (is_add) + { + db->ip6_non_empty_dst_address_length_bitmap = clib_bitmap_set ( + db->ip6_non_empty_dst_address_length_bitmap, 128 - plen, 1); + ip6_compute_prefix_lengths_in_search_order (db); + db->ip6_prefix_len_refcount[plen]++; + } + else + { + ASSERT(db->ip6_prefix_len_refcount[plen] != 0); + + db->ip6_prefix_len_refcount[plen]--; + + if (db->ip6_prefix_len_refcount[plen] == 0) + { + db->ip6_non_empty_dst_address_length_bitmap = clib_bitmap_set ( + db->ip6_non_empty_dst_address_length_bitmap, 128 - plen, 0); + ip6_compute_prefix_lengths_in_search_order (db); + } + } + + kv.key[0] = key.as_u64[0]; + kv.key[1] = key.as_u64[1]; + kv.key[2] = (u64) vni; +// kv.key[2] = ((u64)((fib - im->fibs))<<32) | ip_prefix_len(key); + + if (BV(clib_bihash_search)(&db->ip6_lookup_table, &kv, &value) == 0) + old_val = value.value; + + if (!is_add) + BV(clib_bihash_add_del) (&db->ip6_lookup_table, &kv, 0 /* is_add */); + else + { + kv.value = val; + BV(clib_bihash_add_del) (&db->ip6_lookup_table, &kv, 1 /* is_add */); + } + return old_val; +} + +static u32 +gid_dictionary_add_del_ip (gid_dictionary_t *db, u32 iid, ip_prefix_t *key, + u32 value, u8 is_add) +{ + switch (ip_prefix_version (key)) + { + case IP4: + return add_del_ip4_key (db, iid, key, value, is_add); + break; + case IP6: + return add_del_ip6_key (db, iid, key, value, is_add); + break; + default: + clib_warning("address type %d not supported!", ip_prefix_version (key)); + break; + } + return ~0; +} + +u32 +gid_dictionary_add_del (gid_dictionary_t *db, gid_address_t *key, u32 value, + u8 is_add) +{ + /* XXX for now this only works with ip-prefixes, no lcafs */ + switch (gid_address_type (key)) + { + case IP_PREFIX: + return gid_dictionary_add_del_ip (db, 0, &gid_address_ippref(key), value, + is_add); + break; + default: + clib_warning ("address type %d not supported!", gid_address_type (key)); + break; + } + return ~0; +} + +static void +ip4_lookup_init (gid_dictionary_t * db) +{ + uword i; + + memset(db->ip4_prefix_len_refcount, 0, sizeof(db->ip4_prefix_len_refcount)); + + for (i = 0; i < ARRAY_LEN (db->ip4_fib_masks); i++) + { + u32 m; + + if (i < 32) + m = pow2_mask (i) << (32 - i); + else + m = ~0; + db->ip4_fib_masks[i].as_u32 = clib_host_to_net_u32 (m); + } + if (db->ip4_lookup_table_nbuckets == 0) + db->ip4_lookup_table_nbuckets = IP4_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; + + db->ip4_lookup_table_nbuckets = 1 << max_log2 (db->ip4_lookup_table_nbuckets); + + if (db->ip4_lookup_table_size == 0) + db->ip4_lookup_table_size = IP4_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; + + BV(clib_bihash_init) (&db->ip4_lookup_table, "ip4 lookup table", + db->ip4_lookup_table_nbuckets, db->ip4_lookup_table_size); +} + +static void +ip6_lookup_init (gid_dictionary_t * db) +{ + uword i; + + memset(db->ip6_prefix_len_refcount, 0, sizeof(db->ip6_prefix_len_refcount)); + + for (i = 0; i < ARRAY_LEN(db->ip6_fib_masks); i++) + { + u32 j, i0, i1; + + i0 = i / 32; + i1 = i % 32; + + for (j = 0; j < i0; j++) + db->ip6_fib_masks[i].as_u32[j] = ~0; + + if (i1) + db->ip6_fib_masks[i].as_u32[i0] = clib_host_to_net_u32 ( + pow2_mask (i1) << (32 - i1)); + } + + if (db->ip6_lookup_table_nbuckets == 0) + db->ip6_lookup_table_nbuckets = IP6_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; + + db->ip6_lookup_table_nbuckets = 1 << max_log2 (db->ip6_lookup_table_nbuckets); + + if (db->ip6_lookup_table_size == 0) + db->ip6_lookup_table_size = IP6_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; + + BV(clib_bihash_init) (&db->ip6_lookup_table, "ip6 lookup table", + db->ip6_lookup_table_nbuckets, db->ip6_lookup_table_size); +} + +void +gid_dictionary_init (gid_dictionary_t * db) +{ + ip4_lookup_init (db); + ip6_lookup_init (db); +} + diff --git a/vnet/vnet/lisp-cp/gid_dictionary.h b/vnet/vnet/lisp-cp/gid_dictionary.h new file mode 100644 index 00000000000..5b1a59b0161 --- /dev/null +++ b/vnet/vnet/lisp-cp/gid_dictionary.h @@ -0,0 +1,72 @@ +/* + * 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 VNET_LISP_GPE_GID_DICTIONARY_H_ +#define VNET_LISP_GPE_GID_DICTIONARY_H_ + +#include <vnet/vnet.h> +#include <vnet/lisp-cp/lisp_types.h> +#include <vppinfra/bihash_24_8.h> +#include <vppinfra/bihash_template.h> + +#define GID_LOOKUP_MISS ((u32)~0) + +/* Default size of the ip4 hash table */ +#define IP4_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define IP4_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) + +/* Default size of the ip6 hash table */ +#define IP6_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define IP6_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) + +typedef struct +{ + BVT(clib_bihash) ip4_lookup_table; + + /* bitmap/vector of mask widths to search */ + uword * ip4_non_empty_dst_address_length_bitmap; + u8 * ip4_prefix_lengths_in_search_order; + ip4_address_t ip4_fib_masks[33]; + u32 ip4_prefix_len_refcount[33]; + + /* ip4 lookup table config parameters */ + u32 ip4_lookup_table_nbuckets; + uword ip4_lookup_table_size; + + BVT(clib_bihash) ip6_lookup_table; + + /* bitmap/vector of mask widths to search */ + uword * ip6_non_empty_dst_address_length_bitmap; + u8 * ip6_prefix_lengths_in_search_order; + ip6_address_t ip6_fib_masks[129]; + u64 ip6_prefix_len_refcount[129]; + + /* ip6 lookup table config parameters */ + u32 ip6_lookup_table_nbuckets; + uword ip6_lookup_table_size; + +} gid_dictionary_t; + +u32 +gid_dictionary_add_del (gid_dictionary_t *db, gid_address_t *key, u32 value, + u8 is_add); + +u32 +gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t *key); + +void +gid_dictionary_init (gid_dictionary_t * db); + +#endif /* VNET_LISP_GPE_GID_DICTIONARY_H_ */ diff --git a/vnet/vnet/lisp-cp/lisp_cp_messages.h b/vnet/vnet/lisp-cp/lisp_cp_messages.h new file mode 100644 index 00000000000..6142a0479d3 --- /dev/null +++ b/vnet/vnet/lisp-cp/lisp_cp_messages.h @@ -0,0 +1,433 @@ +/* + * 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 VNET_LISP_GPE_LISP_CP_MESSAGES_H_ +#define VNET_LISP_GPE_LISP_CP_MESSAGES_H_ + +#include <vnet/vnet.h> + +#define MAX_IP_PKT_LEN 4096 +#define MAX_IP_HDR_LEN 40 /* without options or IPv6 hdr extensions */ +#define UDP_HDR_LEN 8 +#define LISP_DATA_HDR_LEN 8 +#define LISP_ECM_HDR_LEN 4 +#define MAX_LISP_MSG_ENCAP_LEN 2*(MAX_IP_HDR_LEN + UDP_HDR_LEN)+ LISP_ECM_HDR_LEN +#define MAX_LISP_PKT_ENCAP_LEN MAX_IP_HDR_LEN + UDP_HDR_LEN + LISP_DATA_HDR_LEN + +#define LISP_CONTROL_PORT 4342 + +/* + * EID RECORD FIELD + */ + +/* + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / | Reserved | EID mask-len | EID-prefix-AFI | + * Rec +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ | EID-prefix ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + +typedef struct _eid_prefix_record_hdr { + u8 reserved; + u8 eid_prefix_length; +} __attribute__ ((__packed__)) eid_record_hdr_t; + +void eid_rec_hdr_init(eid_record_hdr_t *ptr); + +#define EID_REC_CAST(h_) ((eid_record_hdr_t *)(h_)) +#define EID_REC_MLEN(h_) EID_REC_CAST((h_))->eid_prefix_length +#define EID_REC_ADDR(h) (u8 *)(h) + sizeof(eid_record_hdr_t) + +/* LISP Types */ +typedef enum +{ + NOT_LISP_MSG, + LISP_MAP_REQUEST = 1, + LISP_MAP_REPLY, + LISP_MAP_REGISTER, + LISP_MAP_NOTIFY, + LISP_INFO_NAT = 7, + LISP_ENCAP_CONTROL_TYPE = 8, + LISP_MSG_TYPES +} lisp_msg_type_e; + +/* + * ENCAPSULATED CONTROL MESSAGE + */ + +/* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / | IPv4 or IPv6 Header | + * OH | (uses RLOC addresses) | + * \ | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / | Source Port = xxxx | Dest Port = 4342 | + * UDP +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ | UDP Length | UDP Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * LH |Type=8 |S| Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / | IPv4 or IPv6 Header | + * IH | (uses RLOC or EID addresses) | + * \ | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / | Source Port = xxxx | Dest Port = yyyy | + * UDP +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ | UDP Length | UDP Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * LCM | LISP Control Message | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + +/* + * Encapsulated control message header. This is followed by the IP + * header of the encapsulated LISP control message. + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Type=8 |S| Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +typedef struct +{ +#if CLIB_ARCH_IS_LITTLE_ENDIAN + u8 reserved:3; + u8 s_bit:1; + u8 type:4; +#else + u8 type:4; + u8 s_bit:1; + u8 reserved:3; +#endif + u8 reserved2[3]; +} ecm_hdr_t; + +char *ecm_hdr_to_char(ecm_hdr_t *h); + +#define ECM_TYPE(h_) ((ecm_hdr_t *)(h_))->type + +/* + * MAP-REQUEST MESSAGE + */ + +/* + * Map-Request Message Format + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Type=1 |A|M|P|S|p|s| Reserved | IRC | Record Count | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Nonce . . . | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | . . . Nonce | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source-EID-AFI | Source EID Address ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ITR-RLOC-AFI 1 | ITR-RLOC Address 1 ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ITR-RLOC-AFI n | ITR-RLOC Address n ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / | Reserved | EID mask-len | EID-prefix-AFI | + * Rec +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ | EID-prefix ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Map-Reply Record ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Mapping Protocol Data | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + +/* + * Fixed size portion of the map request. Variable size source EID + * address, originating ITR RLOC AFIs and addresses and then map + * request records follow. + */ +typedef struct +{ +#if CLIB_ARCH_IS_LITTLE_ENDIAN + u8 solicit_map_request:1; + u8 rloc_probe:1; + u8 map_data_present:1; + u8 authoritative:1; + u8 type:4; +#else + u8 type:4; + u8 authoritative:1; + u8 map_data_present:1; + u8 rloc_probe:1; + u8 solicit_map_request:1; +#endif +#if CLIB_ARCH_IS_LITTLE_ENDIAN + u8 reserved1:6; + u8 smr_invoked:1; + u8 pitr:1; +#else + u8 pitr:1; + u8 smr_invoked:1; + u8 reserved1:6; +#endif +#if CLIB_ARCH_IS_LITTLE_ENDIAN + u8 additional_itr_rloc_count:5; + u8 reserved2:3; +#else + u8 reserved2:3; + u8 additional_itr_rloc_count:5; +#endif + u8 record_count; + u64 nonce; +}__attribute__ ((__packed__)) map_request_hdr_t; + +void map_request_hdr_init(void *ptr); +char *map_request_hdr_to_char(map_request_hdr_t *h); + +#define MREQ_TYPE(h_) (h_)->type +#define MREQ_HDR_CAST(h_) ((map_request_hdr_t *)(h_)) +#define MREQ_REC_COUNT(h_) (MREQ_HDR_CAST(h_))->record_count +#define MREQ_RLOC_PROBE(h_) (MREQ_HDR_CAST(h_))->rloc_probe +#define MREQ_ITR_RLOC_COUNT(h_) (MREQ_HDR_CAST(h_))->additional_itr_rloc_count +#define MREQ_NONCE(h_) (MREQ_HDR_CAST(h_))->nonce +#define MREQ_SMR(h_) (MREQ_HDR_CAST(h_))->solicit_map_request +#define MREQ_SMR_INVOKED(h_) (MREQ_HDR_CAST(h_))->smr_invoked + +/* + * MAP-REPLY MESSAGE + */ + + /* Map Reply action codes */ + #define LISP_ACTION_NO_ACTION 0 + #define LISP_ACTION_FORWARD 1 + #define LISP_ACTION_DROP 2 + #define LISP_ACTION_SEND_MAP_REQUEST 3 + + /* + * Map-Reply Message Format + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Type=2 |P|E|S| Reserved | Record Count | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Nonce . . . | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | . . . Nonce | + * +-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | Record TTL | + * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * R | Locator Count | EID mask-len | ACT |A| Reserved | + * e +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * c | Rsvd | Map-Version Number | EID-AFI | + * o +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * r | EID-prefix | + * d +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | /| Priority | Weight | M Priority | M Weight | + * | L +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | o | Unused Flags |L|p|R| Loc-AFI | + * | c +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | \| Locator | + * +-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Mapping Protocol Data | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + /* + * Fixed size portion of the map reply. + */ +typedef struct +{ +#if CLIB_ARCH_IS_LITTLE_ENDIAN + u8 reserved1:1; + u8 security:1; + u8 echo_nonce:1; + u8 rloc_probe:1; + u8 type:4; +#else + u8 type:4; + u8 rloc_probe:1; + u8 echo_nonce:1; + u8 security:1; + u8 reserved1:1; +#endif + u8 reserved2; + u8 reserved3; + u8 record_count; + u64 nonce; +} __attribute__ ((__packed__)) map_reply_hdr_t; + + void map_reply_hdr_init(void *ptr); + char *map_reply_hdr_to_char(map_reply_hdr_t *h); + +#define MREP_HDR_CAST(h_) ((map_reply_hdr_t *)(h_)) +#define MREP_REC_COUNT(h_) MREP_HDR_CAST(h_)->record_count +#define MREP_RLOC_PROBE(h_) MREP_HDR_CAST(h_)->rloc_probe +#define MREP_NONCE(h_) MREP_HDR_CAST(h_)->nonce + + +always_inline lisp_msg_type_e +lisp_msg_type (void * b) +{ + ecm_hdr_t * hdr = b; + if (!hdr) + { + return (NOT_LISP_MSG); + } + return (hdr->type); +} + +always_inline void +increment_record_count (void * b) +{ + switch (lisp_msg_type (b)) + { + case LISP_MAP_REQUEST: + MREQ_REC_COUNT(b) += 1; + break; + case LISP_MAP_REPLY: + MREP_REC_COUNT(b) += 1; + break; + default: + return; + } +} + + +/* + * LOCATOR FIELD + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * /| Priority | Weight | M Priority | M Weight | + * L +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * o | Unused Flags |L|p|R| Loc-AFI | + * c +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \| Locator | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Fixed portion of the mapping record locator. Variable length + * locator address follows. + */ +typedef struct _locator_hdr { + u8 priority; + u8 weight; + u8 mpriority; + u8 mweight; + u8 unused1; +#ifdef CLIB_ARCH_IS_LITTLE_ENDIAN + u8 reachable:1; + u8 probed:1; + u8 local:1; + u8 unused2:5; +#else + u8 unused2:5; + u8 local:1; + u8 probed:1; + u8 reachable:1; +#endif +} __attribute__ ((__packed__)) locator_hdr_t; + +#define LOC_CAST(h_) ((locator_hdr_t *)(h_)) +#define LOC_PROBED(h_) LOC_CAST(h_)->probed +#define LOC_PRIORITY(h_) LOC_CAST(h_)->priority +#define LOC_WEIGHT(h_) LOC_CAST(h_)->weight +#define LOC_MPRIORITY(h_) LOC_CAST(h_)->mpriority +#define LOC_MWEIGHT(h_) LOC_CAST(h_)->mweight +#define LOC_REACHABLE(h_) LOC_CAST(h_)->reachable +#define LOC_LOCAL(h_) LOC_CAST(h_)->local +#define LOC_ADDR(h_) ((u8 *)(h_) + sizeof(locator_hdr_t)) + +/* + * MAPPING RECORD + * + * Mapping record used in all LISP control messages. + * + * +---> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | Record TTL | + * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * R | Locator Count | EID mask-len | ACT |A| Reserved | + * e +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * c | Rsvd | Map-Version Number | EID-AFI | + * o +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * r | EID-prefix | + * d +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | /| Priority | Weight | M Priority | M Weight | + * | / +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Loc | Unused Flags |L|p|R| Loc-AFI | + * | \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | \| Locator | + * +---> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +/* + * Fixed portion of the mapping record. EID prefix address and + * locators follow. + */ + +typedef struct _mapping_record_hdr_t +{ + u32 ttl; + u8 locator_count; + u8 eid_prefix_length; +#ifdef CLIB_ARCH_IS_LITTLE_ENDIAN + u8 reserved1:4; + u8 authoritative:1; + u8 action:3; +#else + u8 action :3; + u8 authoritative :1; + u8 reserved1 :4; +#endif + u8 reserved2; +#ifdef CLIB_ARCH_IS_LITTLE_ENDIAN + u8 version_hi:4; + u8 reserved3:4; +#else + u8 reserved3 :4; + u8 version_hi :4; +#endif + u8 version_low; +}__attribute__ ((__packed__)) mapping_record_hdr_t; + +void mapping_record_init_hdr(mapping_record_hdr_t *h); + +#define MAP_REC_EID_PLEN(h) ((mapping_record_hdr_t *)(h))->eid_prefix_length +#define MAP_REC_LOC_COUNT(h) ((mapping_record_hdr_t *)(h))->locator_count +#define MAP_REC_ACTION(h) ((mapping_record_hdr_t *)(h))->action +#define MAP_REC_AUTH(h) ((mapping_record_hdr_t *)(h))->authoritative +#define MAP_REC_TTL(h) ((mapping_record_hdr_t *)(h))->ttl +#define MAP_REC_EID(h) (u8 *)(h)+sizeof(mapping_record_hdr_t) +#define MAP_REC_VERSION(h) (h)->version_hi << 8 | (h)->version_low + +typedef enum lisp_actions +{ + ACT_NO_ACTION = 0, + ACT_NATIVE_FWD, + ACT_SEND_MREQ, + ACT_DROP +} lisp_action_e; + +typedef enum lisp_authoritative +{ + A_NO_AUTHORITATIVE = 0, + A_AUTHORITATIVE +} lisp_authoritative_e; + +#endif /* VNET_LISP_GPE_LISP_CP_MESSAGES_H_ */ diff --git a/vnet/vnet/lisp-cp/lisp_msg_serdes.c b/vnet/vnet/lisp-cp/lisp_msg_serdes.c new file mode 100644 index 00000000000..0e5ba73d0db --- /dev/null +++ b/vnet/vnet/lisp-cp/lisp_msg_serdes.c @@ -0,0 +1,270 @@ +/* + * 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/lisp-cp/lisp_msg_serdes.h> +#include <vnet/lisp-cp/packets.h> +#include <vppinfra/time.h> + +void * +lisp_msg_put_gid (vlib_buffer_t * b, gid_address_t * gid) +{ + u8 * p = vlib_buffer_put_uninit (b, gid_address_size_to_put (gid)); + gid_address_put (p, gid); + return p; +} + +void * +lisp_msg_put_itr_rlocs (lisp_cp_main_t * lcm, vlib_buffer_t * b, + locator_set_t * loc_set, u8 * locs_put) +{ + ip_interface_address_t * ia = 0; + ip4_address_t * l4; + ip6_address_t * l6; + u32 * loc_indexp; + locator_t * loc; + u32 i; + u8 * p, * bp, count = 0; + + bp = vlib_buffer_get_current(b); + for (i = 0; i < vec_len(loc_set->locator_indices); i++) + { + loc_indexp = vec_elt_at_index(loc_set->locator_indices, i); + loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]); + + /* Add ipv4 locators first TODO sort them */ + foreach_ip_interface_address (&lcm->im4->lookup_main, ia, + loc->sw_if_index, 1 /* unnumbered */, + ({ + l4 = ip_interface_address_get_address (&lcm->im4->lookup_main, ia); + p = vlib_buffer_put_uninit (b, ip4_address_size_to_put()); + ip4_address_put (p, l4); + count++; + })); + + /* Add ipv6 locators */ + foreach_ip_interface_address (&lcm->im6->lookup_main, ia, + loc->sw_if_index, 1 /* unnumbered */, + ({ + l6 = ip_interface_address_get_address (&lcm->im6->lookup_main, ia); + p = vlib_buffer_put_uninit (b, ip6_address_size_to_put()); + ip6_address_put (p, l6); + count++; + })); + } + *locs_put = count-1; + return bp; +} + +void * +lisp_msg_put_eid_rec (vlib_buffer_t * b, gid_address_t * eid) +{ + eid_record_hdr_t * h = vlib_buffer_put_uninit (b, sizeof (*h)); + + memset(h, 0, sizeof (*h)); + EID_REC_MLEN (h) = gid_address_len (eid); + lisp_msg_put_gid (b, eid); + return h; +} + +u64 +nonce_build (u32 seed) +{ + u64 nonce; + u32 nonce_lower; + u32 nonce_upper; + struct timespec ts; + + /* Put nanosecond clock in lower 32-bits and put an XOR of the nanosecond + * clock with the seond clock in the upper 32-bits. */ + syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts); + nonce_lower = ts.tv_nsec; + nonce_upper = ts.tv_sec ^ clib_host_to_net_u32(nonce_lower); + + /* OR in a caller provided seed to the low-order 32-bits. */ + nonce_lower |= seed; + + /* Return 64-bit nonce. */ + nonce = nonce_upper; + nonce = (nonce << 32) | nonce_lower; + return nonce; +} + +void * +lisp_msg_put_mreq (lisp_cp_main_t * lcm, vlib_buffer_t * b, + gid_address_t * seid, gid_address_t * deid, + locator_set_t * loc_set, u8 is_smr_invoked, u64 * nonce) +{ + u8 loc_count = 0; + + /* Basic header init */ + map_request_hdr_t * h = vlib_buffer_put_uninit (b, sizeof(h[0])); + + memset(h, 0, sizeof(h[0])); + MREQ_TYPE(h) = LISP_MAP_REQUEST; + MREQ_NONCE(h) = nonce_build(0); + MREQ_SMR_INVOKED(h) = is_smr_invoked ? 1 : 0; + + /* We're adding one eid record */ + increment_record_count (h); + + /* Fill source eid */ + lisp_msg_put_gid (b, seid); + + /* Put itr rlocs */ + lisp_msg_put_itr_rlocs(lcm, b, loc_set, &loc_count); + MREQ_ITR_RLOC_COUNT(h) = loc_count; + + /* Put eid record */ + lisp_msg_put_eid_rec(b, deid); + + nonce[0] = MREQ_NONCE(h); + return h; +} + +void * +lisp_msg_push_ecm (vlib_main_t * vm, vlib_buffer_t *b, int lp, int rp, + gid_address_t *la, gid_address_t *ra) +{ + ecm_hdr_t *h; + ASSERT(gid_address_type(la) == IP_PREFIX); + + /* Push inner ip and udp */ + pkt_push_udp_and_ip (vm, b, lp, rp, &gid_address_ip(la), + &gid_address_ip(ra)); + + /* Push lisp ecm hdr */ + h = pkt_push_ecm_hdr (b); + + return h; +} + +static u32 +msg_type_to_hdr_len (lisp_msg_type_e type) +{ + switch (type) + { + case LISP_MAP_REQUEST: + return (sizeof(map_request_hdr_t)); + case LISP_MAP_REPLY: + return (sizeof(map_reply_hdr_t)); + default: + return (0); + } +} + +void * +lisp_msg_pull_hdr (vlib_buffer_t * b, lisp_msg_type_e type) +{ + return vlib_buffer_pull (b, msg_type_to_hdr_len (type)); +} + +u32 +lisp_msg_parse_addr (vlib_buffer_t * b, gid_address_t * eid) +{ + u32 len = gid_address_parse (vlib_buffer_get_current (b), eid); + if (len != ~0) + vlib_buffer_pull (b, len); + return len; +} + +u32 +lisp_msg_parse_eid_rec (vlib_buffer_t * b, gid_address_t * eid) +{ + eid_record_hdr_t * h = vlib_buffer_get_current (b); + u32 len = gid_address_parse (EID_REC_ADDR(h), eid); + if (len == ~0) + return len; + + gid_address_ippref_len(eid) = EID_REC_MLEN(h); + vlib_buffer_pull (b, len + sizeof(eid_record_hdr_t)); + + return len + sizeof(eid_record_hdr_t); +} + +u32 +lisp_msg_parse_itr_rlocs (vlib_buffer_t * b, gid_address_t ** rlocs, + u8 rloc_count) +{ + gid_address_t tloc; + u32 i, len = 0, tlen = 0; + + //MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1 + for (i = 0; i < rloc_count; i++) + { + len = lisp_msg_parse_addr (b, &tloc); + if (len == ~0) + return len; + vec_add1(*rlocs, tloc); + tlen += len; + } + return tlen; +} + +u32 +lisp_msg_parse_loc (vlib_buffer_t * b, locator_t * loc) +{ + int len; + + len = locator_parse (vlib_buffer_get_current (b), loc); + if (len == ~0) + return ~0; + + vlib_buffer_pull (b, len); + + return len; +} + +u32 +lisp_msg_parse_mapping_record (vlib_buffer_t * b, gid_address_t * eid, + locator_t ** locs, locator_t * probed_) +{ + void * h = 0, * loc_hdr = 0; + locator_t loc, * probed = 0; + int i = 0, len = 0, llen = 0; + + h = vlib_buffer_get_current (b); + vlib_buffer_pull (b, sizeof(mapping_record_hdr_t)); + + len = gid_address_parse (vlib_buffer_get_current (b), eid); + if (len == ~0) + return len; + + vlib_buffer_pull (b, len); + gid_address_ippref_len(eid) = MAP_REC_EID_PLEN(h); + + for (i = 0; i < MAP_REC_LOC_COUNT(h); i++) + { + loc_hdr = vlib_buffer_get_current (b); + + llen = lisp_msg_parse_loc (b, &loc); + if (llen == ~0) + return llen; + vec_add1(*locs, loc); + len += llen; + + if (LOC_PROBED(loc_hdr)) + { + if (probed != 0) + clib_warning("Multiple locators probed! Probing only the first!"); + else + probed = &loc; + } + } + /* XXX */ + if (probed_ != 0 && probed) + *probed_ = *probed; + + return len + sizeof(map_reply_hdr_t); +} diff --git a/vnet/vnet/lisp-cp/lisp_msg_serdes.h b/vnet/vnet/lisp-cp/lisp_msg_serdes.h new file mode 100644 index 00000000000..dddae0747ba --- /dev/null +++ b/vnet/vnet/lisp-cp/lisp_msg_serdes.h @@ -0,0 +1,46 @@ +/* + * 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 VNET_LISP_GPE_LISP_MSG_BUILDER_H_ +#define VNET_LISP_GPE_LISP_MSG_BUILDER_H_ + +#include <vnet/vnet.h> +#include <vnet/lisp-cp/lisp_cp_messages.h> +#include <vnet/lisp-cp/control.h> + +void * +lisp_msg_put_mreq (lisp_cp_main_t * lcm, vlib_buffer_t * b, + gid_address_t * seid, gid_address_t * deid, + locator_set_t * loc_set, u8 is_smr_invoked, u64 * nonce); + +void * +lisp_msg_push_ecm (vlib_main_t * vm, vlib_buffer_t *b, int lp, int rp, + gid_address_t *la, gid_address_t *ra); + +u32 +lisp_msg_parse_mapping_record (vlib_buffer_t * b, gid_address_t * eid, + locator_t ** locs, locator_t * probed_); + +u32 +lisp_msg_parse_addr (vlib_buffer_t * b, gid_address_t * eid); + +u32 +lisp_msg_parse_eid_rec (vlib_buffer_t *b, gid_address_t * eid); + +u32 +lisp_msg_parse_itr_rlocs (vlib_buffer_t * b, gid_address_t ** rlocs, + u8 rloc_count); + +#endif /* VNET_LISP_GPE_LISP_MSG_BUILDER_H_ */ diff --git a/vnet/vnet/lisp-cp/lisp_types.c b/vnet/vnet/lisp-cp/lisp_types.c new file mode 100644 index 00000000000..a04d36ff8d0 --- /dev/null +++ b/vnet/vnet/lisp-cp/lisp_types.c @@ -0,0 +1,475 @@ +/* + * 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/lisp-cp/lisp_types.h> + +typedef u16 (*size_to_write_fct)(void *); +typedef void * (*cast_fct)(gid_address_t *); +typedef u16 (*write_fct)(u8 *, void *); +typedef u8 (*addr_len_fct)(void *); +typedef void (*copy_fct)(void *, void *); + +size_to_write_fct size_to_write_fcts[GID_ADDR_TYPES] = + { ip_prefix_size_to_write }; +write_fct write_fcts[GID_ADDR_TYPES] = + { ip_prefix_write }; +cast_fct cast_fcts[GID_ADDR_TYPES] = + { ip_prefix_cast }; +addr_len_fct addr_len_fcts[GID_ADDR_TYPES] = + { ip_prefix_length }; +copy_fct copy_fcts[GID_ADDR_TYPES] = + { ip_prefix_copy }; + +u8 * +format_ip_address (u8 * s, va_list * args) +{ + ip_address_t * a = va_arg (*args, ip_address_t *); + u8 ver = ip_addr_version(a); + if (ver == IP4) + { + return format (s, "%U", format_ip4_address, &ip_addr_v4(a)); + } + else if (ver == IP6) + { + return format (s, "%U", format_ip6_address, &ip_addr_v6(a)); + } + else + { + clib_warning ("Can't format IP version %d!", ver); + return 0; + } +} + +uword +unformat_ip_address (unformat_input_t * input, va_list * args) +{ + ip_address_t * a = va_arg(*args, ip_address_t *); + if (unformat(input, "%U", unformat_ip4_address, &ip_addr_v4(a))) + ip_addr_version(a) = IP4; + else if (unformat_user (input, unformat_ip6_address, &ip_addr_v6(a))) + ip_addr_version(a) = IP6; + else + return 0; + return 1; +} + +u8 * +format_ip_prefix (u8 * s, va_list * args) +{ + ip_prefix_t * a = va_arg (*args, ip_prefix_t *); + return format (s, "%U/%d", format_ip_address, &ip_prefix_addr(a), ip_prefix_len(a)); +} + +uword +unformat_ip_prefix (unformat_input_t * input, va_list * args) +{ + ip_prefix_t * a = va_arg(*args, ip_prefix_t *); + return unformat (input, "%U/%d", unformat_ip_address, &ip_prefix_addr(a), + &ip_prefix_len(a)); +} + +u8 * +format_gid_address (u8 * s, va_list * args) +{ + gid_address_t * a = va_arg(*args, gid_address_t *); + u8 type = gid_address_type(a); + switch (type) + { + case IP_PREFIX: + return format (s, "%U", format_ip_prefix, &gid_address_ippref(a)); + default: + clib_warning("Can't format gid type %d", type); + return 0; + } +} + +uword +unformat_gid_address (unformat_input_t * input, va_list * args) +{ + gid_address_t * a = va_arg(*args, gid_address_t *); + if (unformat (input, "%U", unformat_ip_prefix, &gid_address_ippref(a))) + gid_address_type(a) = IP_PREFIX; + else + return 0; + return 1; +} + +u16 +ip_address_size (ip_address_t * a) +{ + switch (ip_addr_version (a)) + { + case IP4: + return sizeof(ip4_address_t); + break; + case IP6: + return sizeof(ip6_address_t); + break; + } + return 0; +} + +u16 +ip_version_to_size (u8 ver) +{ + switch (ver) + { + case IP4: + return sizeof(ip4_address_t); + break; + case IP6: + return sizeof(ip6_address_t); + break; + } + return 0; +} + +u8 +ip_version_to_max_plen (u8 ver) +{ + switch (ver) + { + case IP4: + return 32; + break; + case IP6: + return 128; + break; + } + return 0; +} + +always_inline lisp_afi_e +ip_version_to_iana_afi (u16 version) +{ + switch (version) + { + case IP4: + return LISP_AFI_IP; + case IP6: + return LISP_AFI_IP6; + default: + return 0; + } + return 0; +} + +always_inline u8 +ip_iana_afi_to_version (lisp_afi_e afi) +{ + switch (afi) + { + case LISP_AFI_IP: + return IP4; + case LISP_AFI_IP6: + return IP6; + default: + return 0; + } + return 0; +} + +u16 +ip_address_size_to_write (ip_address_t * a) +{ + return ip_address_size (a) + sizeof (u16); +} + +u16 +ip_address_iana_afi(ip_address_t *a) +{ + return ip_version_to_iana_afi(ip_addr_version(a)); +} + +u8 +ip_address_max_len (u8 version) +{ + return version == IP4 ? 32 : 128; +} + +u16 +ip4_address_size_to_put () +{ + // return sizeof(u16) + sizeof (ip4_address_t); + return 6; +} + +u16 +ip6_address_size_to_put () +{ + //return sizeof(u16) + sizeof (ip6_address_t); + return 18; +} + +u32 +ip4_address_put (u8 * b, ip4_address_t * a) +{ + *(u16 *)b = clib_host_to_net_u16(ip_version_to_iana_afi(IP4)); + u8 *p = b + sizeof (u16); + memcpy (p, a, sizeof(*a)); + return ip4_address_size_to_put(); +} + +u32 +ip6_address_put (u8 * b, ip6_address_t * a) +{ + *(u16 *)b = clib_host_to_net_u16(ip_version_to_iana_afi(IP6)); + u8 *p = b + sizeof (u16); + memcpy (p, a, sizeof(*a)); + return ip6_address_size_to_put(); +} + +u32 +ip_address_put (u8 * b, ip_address_t * a) +{ + u32 len = ip_address_size (a); + *(u16 *) b = clib_host_to_net_u16(ip_address_iana_afi (a)); + u8 * p = b + sizeof (u16); + memcpy (p, &ip_addr_addr (a), len); + return (len + sizeof (u16)); +} + +u32 +ip_address_parse(void * offset, u16 iana_afi, ip_address_t *dst) +{ + ip_addr_version(dst) = ip_iana_afi_to_version (iana_afi); + u8 size = ip_version_to_size (ip_addr_version(dst)); + memcpy (&ip_addr_addr(dst), offset + sizeof(u16), size); + return(sizeof(u16) + size); +} + +int +ip_address_cmp (ip_address_t * ip1, ip_address_t * ip2) +{ + int res = 0; + if (ip_addr_version (ip1) != ip_addr_version(ip2)) + return -1; + res = memcmp (&ip_addr_addr(ip1), &ip_addr_addr(ip2), ip_address_size (ip1)); + + if (res < 0) + res = 2; + else if (res > 0) + res = 1; + + return res; +} + +void * +ip_prefix_cast (gid_address_t * a) +{ + return &gid_address_ippref(a); +} + +u16 +ip_prefix_size_to_write (void * pref) +{ + ip_prefix_t *a = (ip_prefix_t *) pref; + return ip_address_size_to_write (&ip_prefix_addr (a)); +} + +u16 +ip_prefix_write (u8 * p, void * pref) +{ + ip_prefix_t *a = (ip_prefix_t *) pref; + switch (ip_prefix_version (a)) + { + case IP4: + return ip4_address_put (p, &ip_prefix_v4 (a)); + break; + case IP6: + return ip6_address_put (p, &ip_prefix_v6 (a)); + break; + } + return 0; +} + +u8 +ip_prefix_length (void *a) +{ + return ip_prefix_len((ip_prefix_t *) a); +} + +void +ip_prefix_copy (void * dst , void * src) +{ + memcpy (dst, src, sizeof (ip_prefix_t)); +} + +int +ip_prefix_cmp(ip_prefix_t * p1, ip_prefix_t * p2) +{ + int cmp = 0; + cmp = ip_address_cmp (&ip_prefix_addr(p1), &ip_prefix_addr(p2)); + if (cmp == 0) + cmp = ip_prefix_len(p1) < ip_prefix_len(p2) ? 1 : 2; /* XXX ? */ + return cmp; +} + +u8 +gid_address_len (gid_address_t *a) +{ + gid_address_type_t type = gid_address_type (a); + return (*addr_len_fcts[type])((*cast_fcts[type])(a)); +} + +u16 +gid_address_put (u8 * b, gid_address_t * gid) +{ + gid_address_type_t type = gid_address_type (gid); + return (*write_fcts[type])(b, (*cast_fcts[type])(gid)); +} + +u16 +gid_address_size_to_put (gid_address_t * gid) +{ + gid_address_type_t type = gid_address_type (gid); + return (*size_to_write_fcts[type])((*cast_fcts[type])(gid)); +} + +void * +gid_address_cast (gid_address_t * gid, gid_address_type_t type) +{ + return (*cast_fcts[type])(gid); +} + +void +gid_address_copy(gid_address_t * dst, gid_address_t * src) +{ + gid_address_type_t type = gid_address_type(src); + (*copy_fcts[type])((*cast_fcts[type])(dst), (*cast_fcts[type])(src)); + gid_address_type(dst) = type; +} + +u32 +gid_address_parse (u8 * offset, gid_address_t *a) +{ + lisp_afi_e afi; + int len = 0; + + if (!a) + return 0; + + afi = clib_net_to_host_u16 (*((u16 *) offset)); + + switch (afi) + { + case LISP_AFI_NO_ADDR: + len = sizeof(u16); + gid_address_type(a) = NO_ADDRESS; + break; + case LISP_AFI_IP: + len = ip_address_parse (offset, afi, &gid_address_ip(a)); + gid_address_type(a) = IP_PREFIX; + /* this should be modified outside if needed*/ + gid_address_ippref_len(a) = 32; + break; + case LISP_AFI_IP6: + len = ip_address_parse (offset, afi, &gid_address_ip(a)); + gid_address_type(a) = IP_PREFIX; + /* this should be modified outside if needed*/ + gid_address_ippref_len(a) = 128; + break; + case LISP_AFI_LCAF: + default: + clib_warning("LISP AFI %d not supported!", afi); + return ~0; + } + return len; +} + +/* Compare two gid_address_t. + * Returns: + * -1: If they are from different afi + * 0: Both address are the same + * 1: Addr1 is bigger than addr2 + * 2: Addr2 is bigger than addr1 + */ +int +gid_address_cmp (gid_address_t * a1, gid_address_t * a2) +{ + int cmp = -1; + if (!a1 || !a2) + return -1; + if (gid_address_type(a1) != gid_address_type(a2)) + return -1; + + switch (gid_address_type(a1)) + { + case NO_ADDRESS: + if (a1 == a2) + cmp = 0; + else + cmp = 2; + break; + case IP_PREFIX: + cmp = ip_prefix_cmp (&gid_address_ippref(a1), &gid_address_ippref(a2)); + break; + default: + break; + } + + return cmp; +} + + +u32 +locator_parse (void * b, locator_t * loc) +{ + locator_hdr_t * h; + u8 status = 1; /* locator up */ + int len; + + h = b; + if (!LOC_REACHABLE(h) && LOC_LOCAL(h)) + status = 0; + + len = gid_address_parse (LOC_ADDR(h), &loc->address); + if (len == ~0) + return len; + + loc->state = status; + loc->local = 0; + loc->priority = LOC_PRIORITY(h); + loc->weight = LOC_WEIGHT(h); + loc->mpriority = LOC_MPRIORITY(h); + loc->mweight = LOC_MWEIGHT(h); + + return sizeof(locator_hdr_t) + len; +} + +void +locator_copy (locator_t * dst, locator_t * src) +{ + /* TODO if gid become more complex, this will need to be changed! */ + memcpy (dst, src, sizeof(*dst)); +} + +u32 +locator_cmp (locator_t * l1, locator_t * l2) +{ + u32 ret = 0; + if ((ret = gid_address_cmp (&l1->address, &l2->address)) != 0) + return 1; + + if (l1->priority != l2->priority) + return 1; + if (l1->weight != l2->weight) + return 1; + if (l1->mpriority != l2->mpriority) + return 1; + if (l1->mweight != l2->mweight) + return 1; + return 0; +} diff --git a/vnet/vnet/lisp-cp/lisp_types.h b/vnet/vnet/lisp-cp/lisp_types.h new file mode 100644 index 00000000000..9602387fd9b --- /dev/null +++ b/vnet/vnet/lisp-cp/lisp_types.h @@ -0,0 +1,163 @@ +/* + * 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 VNET_LISP_GPE_LISP_TYPES_H_ +#define VNET_LISP_GPE_LISP_TYPES_H_ + +#include <vnet/ip/ip.h> +#include <vnet/lisp-cp/lisp_cp_messages.h> + +typedef enum +{ + IP4, + IP6 +} ip_address_type_t; + +typedef struct +{ + union + { + ip4_address_t v4; + ip6_address_t v6; + } ip; + ip_address_type_t version; +} ip_address_t; + +typedef struct +{ + ip_address_t addr; + u8 len; +} ip_prefix_t; + +#define ip_addr_addr(_a) (_a)->ip +#define ip_addr_v4(_a) (_a)->ip.v4 +#define ip_addr_v6(_a) (_a)->ip.v6 +#define ip_addr_version(_a) (_a)->version + +#define ip_prefix_addr(_a) (_a)->addr +#define ip_prefix_version(_a) ip_addr_version(&ip_prefix_addr(_a)) +#define ip_prefix_len(_a) (_a)->len +#define ip_prefix_v4(_a) ip_addr_v4(&ip_prefix_addr(_a)) +#define ip_prefix_v6(_a) ip_addr_v6(&ip_prefix_addr(_a)) + +typedef enum +{ + /* NOTE: ip addresses are left out on purpose. Use max masked ip-prefixes + * instead */ + IP_PREFIX, + NO_ADDRESS, + GID_ADDR_TYPES +} gid_address_type_t; + +/* might want to expand this in the future :) */ +typedef struct +{ + union + { + ip_prefix_t ippref; + }; + u8 type; +} gid_address_t; + +u8 * format_ip_address (u8 * s, va_list * args); +uword unformat_ip_address (unformat_input_t * input, va_list * args); +u8 * format_ip_prefix (u8 * s, va_list * args); +uword unformat_ip_prefix (unformat_input_t * input, va_list * args); + +u16 ip4_address_size_to_put (); +u16 ip6_address_size_to_put (); +u32 ip4_address_put (u8 * b, ip4_address_t * a); +u32 ip6_address_put (u8 * b, ip6_address_t * a); + +u16 ip_address_size_to_write (ip_address_t * a); +u16 ip_address_iana_afi(ip_address_t *a); +u8 ip_address_max_len (u8 ver); +u32 ip_address_put (u8 * b, ip_address_t * a); + +/* LISP AFI codes */ +typedef enum { + LISP_AFI_NO_ADDR, + LISP_AFI_IP, + LISP_AFI_IP6, + LISP_AFI_LCAF = 16387 +} lisp_afi_e; + +u8 *format_gid_address (u8 * s, va_list * args); +uword unformat_gid_address (unformat_input_t * input, va_list * args); + +u16 gid_address_size_to_put (gid_address_t * a); +u16 gid_address_put (u8 * b, gid_address_t * gid); +u8 gid_address_len (gid_address_t *a); +void * gid_address_cast (gid_address_t * gid, gid_address_type_t type); +void gid_address_copy(gid_address_t * dst, gid_address_t * src); +u32 gid_address_parse (u8 * offset, gid_address_t *a); + +#define gid_address_type(_a) (_a)->type +#define gid_address_ippref(_a) (_a)->ippref +#define gid_address_ippref_len(_a) (_a)->ippref.len +#define gid_address_ip(_a) ip_prefix_addr(&gid_address_ippref(_a)) + +/* 'sub'address functions */ +int ip_address_cmp (ip_address_t * ip1, ip_address_t * ip2); +u16 ip_prefix_size_to_write (void * pref); +u16 ip_prefix_write (u8 * p, void * pref); +u8 ip_prefix_length (void *a); +void *ip_prefix_cast (gid_address_t * a); +void ip_prefix_copy (void * dst , void * src); + +typedef struct +{ + /* mark locator as local as opposed to remote */ + u8 local; + u8 state; + union { + u32 sw_if_index; + gid_address_t address; + }; + u8 priority; + u8 weight; + u8 mpriority; + u8 mweight; +} locator_t; + +u32 locator_parse (void * ptr, locator_t * loc); +void locator_copy (locator_t * dst, locator_t * src); +u32 locator_cmp (locator_t * l1, locator_t * l2); + +typedef struct +{ + /* locator-set name */ + u8 * name; + + /* vector of locator indices */ + u32 * locator_indices; + u8 local; +} locator_set_t; + +typedef struct +{ + gid_address_t eid; + + /* index of local locator set */ + u32 locator_set_index; + + u32 ttl; + u8 action; + u8 authoritative; + + u8 local; +} mapping_t; + +#endif /* VNET_LISP_GPE_LISP_TYPES_H_ */ diff --git a/vnet/vnet/lisp-cp/packets.c b/vnet/vnet/lisp-cp/packets.c new file mode 100644 index 00000000000..e3e006b3ef7 --- /dev/null +++ b/vnet/vnet/lisp-cp/packets.c @@ -0,0 +1,248 @@ +/* + * 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/lisp-cp/packets.h> +#include <vnet/lisp-cp/lisp_cp_messages.h> +#include <vnet/ip/udp_packet.h> + +///* Returns IP ID for the packet */ +//static u16 ip_id = 0; +//static inline u16 +//get_IP_ID() +//{ +// ip_id++; +// return (ip_id); +//} + +u16 +udp_ip4_checksum (const void *b, u32 len, u8 *src, u8 *dst) +{ + const u16 *buf = b; + u16 *ip_src = (u16 *) src; + u16 *ip_dst = (u16 *) dst; + u32 length = len; + u32 sum = 0; + + while (len > 1) + { + sum += *buf++; + if (sum & 0x80000000) + sum = (sum & 0xFFFF) + (sum >> 16); + len -= 2; + } + + /* Add the padding if the packet length is odd */ + if (len & 1) + sum += *((u8 *) buf); + + /* Add the pseudo-header */ + sum += *(ip_src++); + sum += *ip_src; + + sum += *(ip_dst++); + sum += *ip_dst; + + sum += clib_host_to_net_u16 (IP_PROTOCOL_UDP); + sum += clib_host_to_net_u16 (length); + + /* Add the carries */ + while (sum >> 16) + sum = (sum & 0xFFFF) + (sum >> 16); + + /* Return the one's complement of sum */ + return ((u16) (~sum)); +} + +u16 +udp_ip6_checksum (ip6_header_t *ip6, udp_header_t *up, u32 len) +{ + size_t i; + register const u16 *sp; + u32 sum; + union + { + struct + { + ip6_address_t ph_src; + ip6_address_t ph_dst; + u32 ph_len; + u8 ph_zero[3]; + u8 ph_nxt; + } ph; + u16 pa[20]; + } phu; + + /* pseudo-header */ + memset (&phu, 0, sizeof(phu)); + phu.ph.ph_src = ip6->src_address; + phu.ph.ph_dst = ip6->dst_address; + phu.ph.ph_len = clib_host_to_net_u32 (len); + phu.ph.ph_nxt = IP_PROTOCOL_UDP; + + sum = 0; + for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) + sum += phu.pa[i]; + + sp = (const u16 *) up; + + for (i = 0; i < (len & ~1); i += 2) + sum += *sp++; + + if (len & 1) + sum += clib_host_to_net_u16 ((*(const u8 *) sp) << 8); + + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum = ~sum & 0xffff; + + return (sum); +} + +u16 +udp_checksum (udp_header_t *uh, u32 udp_len, void *ih, u8 version) +{ + switch (version) + { + case IP4: + return (udp_ip4_checksum (uh, udp_len, + ((ip4_header_t *) ih)->src_address.as_u8, + ((ip4_header_t *) ih)->dst_address.as_u8)); + case IP6: + return (udp_ip6_checksum (ih, uh, udp_len)); + default: + return ~0; + } +} + +void * +pkt_push_udp (vlib_main_t * vm, vlib_buffer_t *b, u16 sp, u16 dp) +{ + udp_header_t * uh; + u16 udp_len = sizeof(udp_header_t) + vlib_buffer_length_in_chain (vm, b); + + uh = vlib_buffer_push_uninit (b, sizeof(*uh)); + + uh->src_port = clib_host_to_net_u16 (sp); + uh->dst_port = clib_host_to_net_u16 (dp); + uh->length = clib_host_to_net_u16 (udp_len); + uh->checksum = 0; + return uh; +} + +void * +pkt_push_ipv4 (vlib_main_t * vm, vlib_buffer_t *b, ip4_address_t *src, + ip4_address_t *dst, int proto) +{ + ip4_header_t * ih; + + /* make some room */ + ih = vlib_buffer_push_uninit(b, sizeof(ip4_header_t)); + + ih->ip_version_and_header_length = 0x45; + ih->tos = 0; + ih->length = clib_host_to_net_u16(vlib_buffer_length_in_chain (vm, b)); + + // iph->fragment_id = clib_host_to_net_u16(get_IP_ID ()); + + /* TODO: decide if we allow fragments in case of control */ + ih->flags_and_fragment_offset = clib_host_to_net_u16(IP_DF); + ih->ttl = 255; + ih->protocol = proto; + ih->src_address.as_u32 = src->as_u32; + ih->dst_address.as_u32 = dst->as_u32; + + ih->checksum = ip4_header_checksum (ih); + return ih; +} + +void * +pkt_push_ipv6 (vlib_main_t * vm, vlib_buffer_t *b, ip6_address_t *src, + ip6_address_t *dst, int proto) +{ + return 0; +// struct ip6_hdr *ip6h; +// int len; +// +// len = lbuf_size(b); +// ip6h = lbuf_push_uninit(b, sizeof(struct ip6_hdr)); +// +// ip6h->ip6_hops = 255; +// ip6h->ip6_vfc = (IP6VERSION << 4); +// ip6h->ip6_nxt = proto; +// ip6h->ip6_plen = clib_host_to_net_u16(len); +// memcpy(ip6h->ip6_src.s6_addr, src->s6_addr, sizeof(struct in6_addr)); +// memcpy(ip6h->ip6_dst.s6_addr, dst->s6_addr, sizeof(struct in6_addr)); +// return(ip6h); +} + +void * +pkt_push_ip (vlib_main_t * vm, vlib_buffer_t *b, ip_address_t *src, + ip_address_t *dst, u32 proto) +{ + if (ip_addr_version (src) != ip_addr_version(dst)) + { + clib_warning("src %s and dst %s IP have different AFI! Discarding!", + format_ip_address, src, format_ip_address, dst); + return 0; + } + + switch (ip_addr_version(src)) + { + case IP4: + return pkt_push_ipv4 (vm, b, &ip_addr_v4(src), &ip_addr_v4(dst), proto); + break; + case IP6: + return pkt_push_ipv6 (vm, b, &ip_addr_v6(src), &ip_addr_v6(dst), proto); + break; + } + + return 0; +} + +void * +pkt_push_udp_and_ip (vlib_main_t * vm, vlib_buffer_t *b, u16 sp, u16 dp, + ip_address_t *sip, ip_address_t *dip) +{ + u16 udpsum; + udp_header_t * uh; + void * ih; + + uh = pkt_push_udp (vm, b, sp, dp); + + ih = pkt_push_ip (vm, b, sip, dip, IP_PROTOCOL_UDP); + + udpsum = udp_checksum (uh, clib_net_to_host_u16 (uh->length), ih, + ip_addr_version(sip)); + if (udpsum == -1) + { + clib_warning("Failed UDP checksum! Discarding"); + return 0; + } + uh->checksum = udpsum; + return ih; +} + +void * +pkt_push_ecm_hdr (vlib_buffer_t *b) +{ + ecm_hdr_t * h; + h = vlib_buffer_push_uninit (b, sizeof (h[0])); + + memset(h, 0, sizeof(h[0])); + h->type = LISP_ENCAP_CONTROL_TYPE; + memset (h->reserved2, 0, sizeof(h->reserved2)); + + return h; +} diff --git a/vnet/vnet/lisp-cp/packets.h b/vnet/vnet/lisp-cp/packets.h new file mode 100644 index 00000000000..a9f9a109958 --- /dev/null +++ b/vnet/vnet/lisp-cp/packets.h @@ -0,0 +1,72 @@ +/* + * 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 <vnet/lisp-cp/lisp_types.h> + +#define IP_DF 0x4000 /* don't fragment */ + +void * +pkt_push_ip (vlib_main_t * vm, vlib_buffer_t *b, ip_address_t *src, + ip_address_t *dst, u32 proto); + +void * +pkt_push_udp_and_ip (vlib_main_t * vm, vlib_buffer_t *b, u16 sp, u16 dp, + ip_address_t *sip, ip_address_t *dip); + +void * +pkt_push_ecm_hdr (vlib_buffer_t *b); + +always_inline u8 * +vlib_buffer_get_tail (vlib_buffer_t *b) +{ + return b->data + b->current_data + b->current_length; +} + +always_inline void * +vlib_buffer_put_uninit (vlib_buffer_t *b, u8 size) +{ + /* XXX should make sure there's enough space! */ + void * p = vlib_buffer_get_tail (b); + b->current_length += size; + return p; +} + +always_inline void * +vlib_buffer_push_uninit (vlib_buffer_t *b, u8 size) +{ + /* XXX should make sure there's enough space! */ + ASSERT (b->current_data > size); + b->current_data -= size; + b->current_length += size; + + return vlib_buffer_get_current(b); +} + +always_inline void * +vlib_buffer_make_headroom (vlib_buffer_t *b, u8 size) +{ + /* XXX should make sure there's enough space! */ + b->current_data += size; + return vlib_buffer_get_current (b); +} + +always_inline void * +vlib_buffer_pull (vlib_buffer_t * b, u8 size) +{ + void * data = vlib_buffer_get_current (b); + vlib_buffer_advance (b, size); + return data; +} diff --git a/vnet/vnet/lisp-gpe/decap.c b/vnet/vnet/lisp-gpe/decap.c index e10f1f2e399..356dbf2e858 100644 --- a/vnet/vnet/lisp-gpe/decap.c +++ b/vnet/vnet/lisp-gpe/decap.c @@ -1,7 +1,5 @@ /* - * decap.c: lisp-gpe decap processing - * - * Copyright (c) 2014 Cisco and/or its affiliates. + * 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: @@ -19,14 +17,16 @@ #include <vnet/pg/pg.h> #include <vnet/lisp-gpe/lisp_gpe.h> -typedef struct { +typedef struct +{ u32 next_index; u32 tunnel_index; u32 error; lisp_gpe_header_t h; } lisp_gpe_rx_trace_t; -static u8 * format_lisp_gpe_rx_trace (u8 * s, va_list * args) +static u8 * +format_lisp_gpe_rx_trace (u8 * s, va_list * args) { CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); @@ -34,27 +34,55 @@ static u8 * format_lisp_gpe_rx_trace (u8 * s, va_list * args) if (t->tunnel_index != ~0) { - s = format (s, "NSH-VXLAN: tunnel %d next %d error %d", t->tunnel_index, - t->next_index, t->error); + s = format (s, "LISP-GPE: tunnel %d next %d error %d", t->tunnel_index, + t->next_index, t->error); } else { - s = format (s, "NSH-VXLAN: no tunnel next %d error %d\n", t->next_index, - t->error); + s = format (s, "LISP-GPE: no tunnel next %d error %d\n", t->next_index, + t->error); } - s = format (s, "\n %U", format_lisp_gpe_header_with_length, &t->h, - (u32) sizeof (t->h) /* max size */); + s = format (s, "\n %U", format_lisp_gpe_header_with_length, &t->h, + (u32) sizeof (t->h) /* max size */); return s; } +static u32 +next_proto_to_next_index[LISP_GPE_NEXT_PROTOS] ={ + LISP_GPE_INPUT_NEXT_DROP, + LISP_GPE_INPUT_NEXT_IP4_INPUT, + LISP_GPE_INPUT_NEXT_IP6_INPUT, + LISP_GPE_INPUT_NEXT_DROP, + LISP_GPE_INPUT_NEXT_DROP +}; + +static u32 +next_protocol_to_next_index (lisp_gpe_header_t * lgh, u8 * next_header) +{ + /* legay lisp router */ + if (PREDICT_FALSE((lgh->flags & LISP_GPE_FLAGS_P) == 0)) + { + ip4_header_t * iph = (ip4_header_t *) next_header; + if ((iph->ip_version_and_header_length & 0xF0) == 0x40) + return LISP_GPE_INPUT_NEXT_IP4_INPUT; + else if ((iph->ip_version_and_header_length & 0xF0) == 0x60) + return LISP_GPE_INPUT_NEXT_IP6_INPUT; + else + return LISP_GPE_INPUT_NEXT_DROP; + } + /* lisp-gpe router */ + else if ((lgh->flags & LISP_GPE_FLAGS_P) + && lgh->next_protocol < LISP_GPE_NEXT_PROTOS) + return next_proto_to_next_index[lgh->next_protocol]; + else + return LISP_GPE_INPUT_NEXT_DROP; +} + static uword -lisp_gpe_input (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) +lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * from_frame) { u32 n_left_from, next_index, * from, * to_next; - lisp_gpe_main_t * ngm = &lisp_gpe_main; - u32 last_tunnel_index = ~0; lisp_gpe_tunnel_key_t last_key; u32 pkts_decapsulated = 0; @@ -69,182 +97,143 @@ lisp_gpe_input (vlib_main_t * vm, { u32 n_left_to_next; - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); + vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); -#if 0 while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t * b0, * b1; - nsh_unicast_header_t * h0, * h1; - u32 label0, label1; - u32 next0, next1; - uword * p0, * p1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t * p2, * p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); - } - - bi0 = from[0]; - bi1 = from[1]; - to_next[0] = bi0; - to_next[1] = bi1; - from += 2; - to_next += 2; - n_left_to_next -= 2; - n_left_from -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - h0 = vlib_buffer_get_current (b0); - h1 = vlib_buffer_get_current (b1); - + { + u32 bi0, bi1; + vlib_buffer_t * b0, * b1; + ip4_udp_lisp_gpe_header_t * iul0, * iul1; + u32 error0, error1; + u32 next0, next1; + next0 = next1 = LISP_GPE_INPUT_NEXT_IP4_INPUT; - label0 = clib_net_to_host_u32 (h0->label_exp_s_ttl); - label1 = clib_net_to_host_u32 (h1->label_exp_s_ttl); + /* Prefetch next iteration. */ + { + vlib_buffer_t * p2, * p3; - /* - * Translate label contents into a fib index. - * This is a decent sanity check, and guarantees - * a sane FIB for the downstream lookup - */ - label0 = vnet_nsh_uc_get_label (label0); - label1 = vnet_nsh_uc_get_label (label1); + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); - /* If 2xlabels match, and match the 1-wide cache, use it */ - if (label0 == label1 && rt->last_label == label0) - { - vnet_buffer(b0)->sw_if_index[VLIB_TX] = rt->last_fib_index; - vnet_buffer(b1)->sw_if_index[VLIB_TX] = rt->last_fib_index; - } - else - { - p0 = hash_get (rt->mm->fib_index_by_nsh_label, label0); - if (PREDICT_FALSE (p0 == 0)) - { - next0 = LISP_GPE_INPUT_NEXT_DROP; - b0->error = node->errors[NSH_ERROR_BAD_LABEL]; - } - else - vnet_buffer(b0)->sw_if_index[VLIB_TX] = p0[0]; - - p1 = hash_get (rt->mm->fib_index_by_nsh_label, label1); - if (PREDICT_FALSE (p1 == 0)) - { - next1 = LISP_GPE_INPUT_NEXT_DROP; - b1->error = node->errors[NSH_ERROR_BAD_LABEL]; - } - else - { - vnet_buffer(b1)->sw_if_index[VLIB_TX] = p1[0]; - rt->last_fib_index = p1[0]; - rt->last_label = label1; - } - } + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); + } + + bi0 = from[0]; + bi1 = from[1]; + to_next[0] = bi0; + to_next[1] = bi1; + from += 2; + to_next += 2; + n_left_to_next -= 2; + n_left_from -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + /* udp leaves current_data pointing at the lisp header */ + vlib_buffer_advance (b0, - IP_UDP_HDR_LEN); + vlib_buffer_advance (b1, - IP_UDP_HDR_LEN); + + iul0 = vlib_buffer_get_current (b0); + iul1 = vlib_buffer_get_current (b1); + + /* pop (ip, udp, lisp-gpe) */ + vlib_buffer_advance (b0, sizeof (*iul0)); + vlib_buffer_advance (b1, sizeof (*iul1)); + + /* determine next_index from lisp-gpe header */ + next0 = next_protocol_to_next_index (&iul0->lisp, + vlib_buffer_get_current (b0)); + next1 = next_protocol_to_next_index (&iul1->lisp, + vlib_buffer_get_current (b1)); + + /* Required to make the l2 tag push / pop code work on l2 subifs */ + vnet_update_l2_len (b0); + vnet_update_l2_len (b1); + + /* TODO hash to map iid to fib */ + vnet_buffer(b0)->sw_if_index[VLIB_TX] = iul0->lisp.iid; + vnet_buffer(b1)->sw_if_index[VLIB_TX] = iul1->lisp.iid; + + pkts_decapsulated += 2; + + /* TODO error handling if security is implemented */ + error0 = error1 = 0; + b0->error = error0 ? node->errors[error0] : 0; + b1->error = error1 ? node->errors[error1] : 0; + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { - nsh_rx_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->label_exp_s_ttl = label0; + lisp_gpe_rx_trace_t *tr = vlib_add_trace (vm, node, b0, + sizeof(*tr)); + tr->next_index = next0; + tr->error = error0; + tr->h = iul0->lisp; } - if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) + + if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) { - nsh_rx_trace_t *tr = vlib_add_trace (vm, node, - b1, sizeof (*tr)); - tr->label_exp_s_ttl = label1; + lisp_gpe_rx_trace_t *tr = vlib_add_trace (vm, node, b1, + sizeof(*tr)); + tr->next_index = next1; + tr->error = error1; + tr->h = iul1->lisp; } - vlib_buffer_advance (b0, sizeof (*h0)); - vlib_buffer_advance (b1, sizeof (*h1)); - - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } -#endif + vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, + n_left_to_next, bi0, bi1, next0, + next1); + } while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0; + { + u32 bi0; + vlib_buffer_t * b0; + u32 next0; ip4_udp_lisp_gpe_header_t * iul0; - uword * p0; - u32 tunnel_index0; - lisp_gpe_tunnel_t * t0; - lisp_gpe_tunnel_key_t key0; u32 error0; - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; - b0 = vlib_get_buffer (vm, bi0); + b0 = vlib_get_buffer (vm, bi0); /* udp leaves current_data pointing at the lisp header */ - vlib_buffer_advance - (b0, -(word)(sizeof(udp_header_t)+sizeof(ip4_header_t))); + vlib_buffer_advance (b0, - IP_UDP_HDR_LEN); iul0 = vlib_buffer_get_current (b0); /* pop (ip, udp, lisp-gpe) */ vlib_buffer_advance (b0, sizeof (*iul0)); - tunnel_index0 = ~0; - error0 = 0; - next0 = LISP_GPE_INPUT_NEXT_DROP; - - key0.src = iul0->ip4.src_address.as_u32; - key0.iid = iul0->lisp.iid; - - if (PREDICT_FALSE ((key0.as_u64[0] != last_key.as_u64[0]))) - { - p0 = hash_get_mem (ngm->lisp_gpe_tunnel_by_key, &key0); - - if (p0 == 0) - { - error0 = LISP_GPE_ERROR_NO_SUCH_TUNNEL; - goto trace0; - } - - last_key.as_u64[0] = key0.as_u64[0]; - tunnel_index0 = last_tunnel_index = p0[0]; - } - else - tunnel_index0 = last_tunnel_index; - - t0 = pool_elt_at_index (ngm->tunnels, tunnel_index0); + /* TODO if security is to be implemented, something similar to RPF, + * probably we'd like to check that the peer is allowed to send us + * packets. For this, we should use the tunnel table OR check that + * we have a mapping for the source eid and that the outer source of + * the packet is one of its locators */ - next0 = t0->decap_next_index; + /* determine next_index from lisp-gpe header */ + next0 = next_protocol_to_next_index (&iul0->lisp, + vlib_buffer_get_current (b0)); /* Required to make the l2 tag push / pop code work on l2 subifs */ vnet_update_l2_len (b0); - /* - * ip[46] lookup in the configured FIB - * lisp-gpe-encap, here's the encap tunnel sw_if_index - */ - vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->decap_fib_index; + /* TODO hash to map iid to fib */ + vnet_buffer(b0)->sw_if_index[VLIB_TX] = iul0->lisp.iid; pkts_decapsulated ++; - trace0: + /* TODO error handling if security is implemented */ + error0 = 0; b0->error = error0 ? node->errors[error0] : 0; if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) @@ -253,13 +242,12 @@ lisp_gpe_input (vlib_main_t * vm, = vlib_add_trace (vm, node, b0, sizeof (*tr)); tr->next_index = next0; tr->error = error0; - tr->tunnel_index = tunnel_index0; tr->h = iul0->lisp; } - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } + + vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } diff --git a/vnet/vnet/lisp-gpe/encap.c b/vnet/vnet/lisp-gpe/encap.c index b3a52c464be..a8158782d8c 100644 --- a/vnet/vnet/lisp-gpe/encap.c +++ b/vnet/vnet/lisp-gpe/encap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * 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: @@ -12,10 +12,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include <vppinfra/error.h> #include <vppinfra/hash.h> #include <vnet/vnet.h> #include <vnet/ip/ip.h> +#include <vnet/ip/udp.h> #include <vnet/ethernet/ethernet.h> #include <vnet/lisp-gpe/lisp_gpe.h> @@ -31,45 +33,41 @@ static char * lisp_gpe_encap_error_strings[] = { typedef enum { #define _(sym,str) LISP_GPE_ENCAP_ERROR_##sym, - foreach_lisp_gpe_encap_error + foreach_lisp_gpe_encap_error #undef _ - LISP_GPE_ENCAP_N_ERROR, + LISP_GPE_ENCAP_N_ERROR, } lisp_gpe_encap_error_t; -typedef enum { - LISP_GPE_ENCAP_NEXT_IP4_LOOKUP, - LISP_GPE_ENCAP_NEXT_DROP, - LISP_GPE_ENCAP_N_NEXT, +typedef enum +{ + LISP_GPE_ENCAP_NEXT_DROP, + LISP_GPE_ENCAP_NEXT_IP4_LOOKUP, + LISP_GPE_ENCAP_N_NEXT, } lisp_gpe_encap_next_t; -typedef struct { +typedef struct +{ u32 tunnel_index; } lisp_gpe_encap_trace_t; -u8 * format_lisp_gpe_encap_trace (u8 * s, va_list * args) +u8 * +format_lisp_gpe_encap_trace (u8 * s, va_list * args) { CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - lisp_gpe_encap_trace_t * t - = va_arg (*args, lisp_gpe_encap_trace_t *); + lisp_gpe_encap_trace_t * t = va_arg (*args, lisp_gpe_encap_trace_t *); s = format (s, "LISP-GPE-ENCAP: tunnel %d", t->tunnel_index); return s; } -#define foreach_fixed_header_offset \ -_(0) _(1) _(2) _(3) - static uword -lisp_gpe_encap (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) +lisp_gpe_encap (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * from_frame) { u32 n_left_from, next_index, * from, * to_next; - lisp_gpe_main_t * ngm = &lisp_gpe_main; - vnet_main_t * vnm = ngm->vnet_main; + lisp_gpe_main_t * lgm = &lisp_gpe_main; u32 pkts_encapsulated = 0; - u16 old_l0 = 0; from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -81,196 +79,131 @@ lisp_gpe_encap (vlib_main_t * vm, u32 n_left_to_next; vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); + to_next, n_left_to_next); -#if 0 while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t * b0, * b1; - nsh_unicast_header_t * h0, * h1; - u32 label0, label1; - u32 next0, next1; - uword * p0, * p1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t * p2, * p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); - } - - bi0 = from[0]; - bi1 = from[1]; - to_next[0] = bi0; - to_next[1] = bi1; - from += 2; - to_next += 2; - n_left_to_next -= 2; - n_left_from -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - h0 = vlib_buffer_get_current (b0); - h1 = vlib_buffer_get_current (b1); - - next0 = next1 = NSH_INPUT_NEXT_IP4_INPUT; - - label0 = clib_net_to_host_u32 (h0->label_exp_s_ttl); - label1 = clib_net_to_host_u32 (h1->label_exp_s_ttl); - - /* - * Translate label contents into a fib index. - * This is a decent sanity check, and guarantees - * a sane FIB for the downstream lookup - */ - label0 = vnet_nsh_uc_get_label (label0); - label1 = vnet_nsh_uc_get_label (label1); - - /* If 2xlabels match, and match the 1-wide cache, use it */ - if (label0 == label1 && rt->last_label == label0) - { - vnet_buffer(b0)->sw_if_index[VLIB_TX] = rt->last_fib_index; - vnet_buffer(b1)->sw_if_index[VLIB_TX] = rt->last_fib_index; - } - else + { + u32 bi0, bi1; + vlib_buffer_t * b0, * b1; + u32 next0, next1; + u32 adj_index0, adj_index1, tunnel_index0, tunnel_index1; + ip_adjacency_t * adj0, * adj1; + lisp_gpe_tunnel_t * t0, * t1; + + next0 = next1 = LISP_GPE_ENCAP_NEXT_IP4_LOOKUP; + + /* Prefetch next iteration. */ { - p0 = hash_get (rt->mm->fib_index_by_nsh_label, label0); - if (PREDICT_FALSE (p0 == 0)) - { - next0 = NSH_INPUT_NEXT_DROP; - b0->error = node->errors[NSH_ERROR_BAD_LABEL]; - } - else - vnet_buffer(b0)->sw_if_index[VLIB_TX] = p0[0]; - - p1 = hash_get (rt->mm->fib_index_by_nsh_label, label1); - if (PREDICT_FALSE (p1 == 0)) - { - next1 = NSH_INPUT_NEXT_DROP; - b1->error = node->errors[NSH_ERROR_BAD_LABEL]; - } - else - { - vnet_buffer(b1)->sw_if_index[VLIB_TX] = p1[0]; - rt->last_fib_index = p1[0]; - rt->last_label = label1; - } + vlib_buffer_t * p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header(p2, LOAD); + vlib_prefetch_buffer_header(p3, LOAD); + + CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); } - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + bi0 = from[0]; + bi1 = from[1]; + to_next[0] = bi0; + to_next[1] = bi1; + from += 2; + to_next += 2; + n_left_to_next -= 2; + n_left_from -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + /* Get adjacency and from it the tunnel_index */ + adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; + adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX]; + + adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0); + adj1 = ip_get_adjacency (lgm->lookup_main, adj_index1); + + tunnel_index0 = adj0->rewrite_header.sw_if_index; + tunnel_index1 = adj1->rewrite_header.sw_if_index; + + t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0); + t1 = pool_elt_at_index (lgm->tunnels, tunnel_index1); + + ASSERT(t0 != 0); + ASSERT(t1 != 0); + + ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36); + ip4_udp_encap_two (vm, b0, b1, t0->rewrite, t1->rewrite, 36); + + /* Reset to look up tunnel partner in the configured FIB */ + vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index; + vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->encap_fib_index; + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { - nsh_rx_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->label_exp_s_ttl = label0; + lisp_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b0, + sizeof(*tr)); + tr->tunnel_index = t0 - lgm->tunnels; } - if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) + if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) { - nsh_rx_trace_t *tr = vlib_add_trace (vm, node, - b1, sizeof (*tr)); - tr->label_exp_s_ttl = label1; + lisp_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b1, + sizeof(*tr)); + tr->tunnel_index = t1 - lgm->tunnels; } - vlib_buffer_advance (b0, sizeof (*h0)); - vlib_buffer_advance (b1, sizeof (*h1)); + pkts_encapsulated += 2; + + vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, + n_left_to_next, bi0, bi1, next0, + next1); + } - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } -#endif - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0 = LISP_GPE_ENCAP_NEXT_IP4_LOOKUP; - vnet_hw_interface_t * hi0; - ip4_header_t * ip0; - udp_header_t * udp0; - u64 * copy_src0, * copy_dst0; - u32 * copy_src_last0, * copy_dst_last0; - lisp_gpe_tunnel_t * t0; - u16 new_l0; - ip_csum_t sum0; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - /* 1-wide cache? */ - hi0 = vnet_get_sup_hw_interface - (vnm, vnet_buffer(b0)->sw_if_index[VLIB_TX]); - - t0 = pool_elt_at_index (ngm->tunnels, hi0->dev_instance); - - ASSERT(vec_len(t0->rewrite) >= 24); - - /* Apply the rewrite string. $$$$ vnet_rewrite? */ - vlib_buffer_advance (b0, -(word)_vec_len(t0->rewrite)); - - ip0 = vlib_buffer_get_current(b0); - /* Copy the fixed header */ - copy_dst0 = (u64 *) ip0; - copy_src0 = (u64 *) t0->rewrite; - - ASSERT (sizeof (ip4_udp_lisp_gpe_header_t) == 36); - - /* Copy first 32 octets 8-bytes at a time */ -#define _(offs) copy_dst0[offs] = copy_src0[offs]; - foreach_fixed_header_offset; -#undef _ - /* Last 4 octets. Hopefully gcc will be our friend */ - copy_dst_last0 = (u32 *)(©_dst0[4]); - copy_src_last0 = (u32 *)(©_src0[4]); - - copy_dst_last0[0] = copy_src_last0[0]; - - /* fix the <bleep>ing outer-IP checksum */ - sum0 = ip0->checksum; - /* old_l0 always 0, see the rewrite setup */ - new_l0 = - clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); - - sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, - length /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - ip0->length = new_l0; - - /* Fix UDP length */ - udp0 = (udp_header_t *)(ip0+1); - new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) - - sizeof (*ip0)); - - udp0->length = new_l0; + { + vlib_buffer_t * b0; + u32 bi0, adj_index0, tunnel_index0; + u32 next0 = LISP_GPE_ENCAP_NEXT_IP4_LOOKUP; + lisp_gpe_tunnel_t * t0 = 0; + ip_adjacency_t * adj0; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + /* Get adjacency and from it the tunnel_index */ + adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; + adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0); + + tunnel_index0 = adj0->rewrite_header.sw_if_index; + t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0); + + ASSERT(t0 != 0); + + ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36); + ip4_udp_encap_one (vm, b0, t0->rewrite, 36); /* Reset to look up tunnel partner in the configured FIB */ vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index; - pkts_encapsulated ++; + + pkts_encapsulated++; if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { - lisp_gpe_encap_trace_t *tr = - vlib_add_trace (vm, node, b0, sizeof (*tr)); - tr->tunnel_index = t0 - ngm->tunnels; + lisp_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b0, + sizeof(*tr)); + tr->tunnel_index = t0 - lgm->tunnels; } - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } + vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } @@ -293,7 +226,7 @@ VLIB_REGISTER_NODE (lisp_gpe_encap_node) = { .n_next_nodes = LISP_GPE_ENCAP_N_NEXT, .next_nodes = { - [LISP_GPE_ENCAP_NEXT_IP4_LOOKUP] = "ip4-lookup", - [LISP_GPE_ENCAP_NEXT_DROP] = "error-drop", + [LISP_GPE_ENCAP_NEXT_DROP] = "error-drop", + [LISP_GPE_ENCAP_NEXT_IP4_LOOKUP] = "ip4-lookup", }, }; diff --git a/vnet/vnet/lisp-gpe/lisp_gpe.c b/vnet/vnet/lisp-gpe/lisp_gpe.c index eb4ca919b20..b8072494c2c 100644 --- a/vnet/vnet/lisp-gpe/lisp_gpe.c +++ b/vnet/vnet/lisp-gpe/lisp_gpe.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * 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: @@ -12,129 +12,551 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include <vnet/lisp-gpe/lisp_gpe.h> lisp_gpe_main_t lisp_gpe_main; -static u8 * format_decap_next (u8 * s, va_list * args) +/* avoids calling route callbacks for src fib */ +static void +ip4_sd_fib_set_adj_index (lisp_gpe_main_t * lgm, ip4_fib_t * fib, u32 flags, + u32 dst_address_u32, u32 dst_address_length, + u32 adj_index) { - u32 next_index = va_arg (*args, u32); + ip_lookup_main_t * lm = lgm->lookup_main; + uword * hash; - switch (next_index) + if (vec_bytes(fib->old_hash_values)) + memset (fib->old_hash_values, ~0, vec_bytes (fib->old_hash_values)); + if (vec_bytes(fib->new_hash_values)) + memset (fib->new_hash_values, ~0, vec_bytes (fib->new_hash_values)); + fib->new_hash_values[0] = adj_index; + + /* Make sure adj index is valid. */ + if (CLIB_DEBUG > 0) + (void) ip_get_adjacency (lm, adj_index); + + hash = fib->adj_index_by_dst_address[dst_address_length]; + + hash = _hash_set3 (hash, dst_address_u32, + fib->new_hash_values, + fib->old_hash_values); + + fib->adj_index_by_dst_address[dst_address_length] = hash; +} + +/* copied from ip4_forward since it's static */ +static void +ip4_fib_init_adj_index_by_dst_address (ip_lookup_main_t * lm, + ip4_fib_t * fib, + u32 address_length) +{ + hash_t * h; + uword max_index; + + ASSERT (lm->fib_result_n_bytes >= sizeof (uword)); + lm->fib_result_n_words = round_pow2 (lm->fib_result_n_bytes, sizeof (uword)) / sizeof (uword); + + fib->adj_index_by_dst_address[address_length] = + hash_create (32 /* elts */, lm->fib_result_n_words * sizeof (uword)); + + hash_set_flags (fib->adj_index_by_dst_address[address_length], + HASH_FLAG_NO_AUTO_SHRINK); + + h = hash_header (fib->adj_index_by_dst_address[address_length]); + max_index = (hash_value_bytes (h) / sizeof (fib->new_hash_values[0])) - 1; + + /* Initialize new/old hash value vectors. */ + vec_validate_init_empty (fib->new_hash_values, max_index, ~0); + vec_validate_init_empty (fib->old_hash_values, max_index, ~0); +} + +void +ip4_sd_fib_add_del_src_route (lisp_gpe_main_t * lgm, + ip4_add_del_route_args_t * a) +{ + ip_lookup_main_t * lm = lgm->lookup_main; + ip4_fib_t * fib; + u32 dst_address, dst_address_length, adj_index, old_adj_index; + uword * hash, is_del; + + /* Either create new adjacency or use given one depending on arguments. */ + if (a->n_add_adj > 0) + ip_add_adjacency (lm, a->add_adj, a->n_add_adj, &adj_index); + else + adj_index = a->adj_index; + + dst_address = a->dst_address.data_u32; + dst_address_length = a->dst_address_length; + + fib = pool_elt_at_index(lgm->src_fibs, a->table_index_or_table_id); + + if (! fib->adj_index_by_dst_address[dst_address_length]) + ip4_fib_init_adj_index_by_dst_address (lm, fib, dst_address_length); + + hash = fib->adj_index_by_dst_address[dst_address_length]; + + is_del = (a->flags & IP4_ROUTE_FLAG_DEL) != 0; + + if (is_del) { - case LISP_GPE_INPUT_NEXT_DROP: - return format (s, "drop"); - case LISP_GPE_INPUT_NEXT_IP4_INPUT: - return format (s, "ip4"); - case LISP_GPE_INPUT_NEXT_IP6_INPUT: - return format (s, "ip6"); - case LISP_GPE_INPUT_NEXT_LISP_GPE_ENCAP: - return format (s, "nsh-lisp-gpe"); - default: - return format (s, "unknown %d", next_index); + fib->old_hash_values[0] = ~0; + hash = _hash_unset (hash, dst_address, fib->old_hash_values); + fib->adj_index_by_dst_address[dst_address_length] = hash; } - return s; + else + ip4_sd_fib_set_adj_index (lgm, fib, a->flags, dst_address, + dst_address_length, adj_index); + + old_adj_index = fib->old_hash_values[0]; + + ip4_fib_mtrie_add_del_route (fib, a->dst_address, dst_address_length, + is_del ? old_adj_index : adj_index, + is_del); + + /* Delete old adjacency index if present and changed. */ + if (! (a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY) + && old_adj_index != ~0 + && old_adj_index != adj_index) + ip_del_adjacency (lm, old_adj_index); } -u8 * format_lisp_gpe_tunnel (u8 * s, va_list * args) +void * +ip4_sd_get_src_route (lisp_gpe_main_t * lgm, u32 src_fib_index, + ip4_address_t * src, u32 address_length) { - lisp_gpe_tunnel_t * t = va_arg (*args, lisp_gpe_tunnel_t *); - lisp_gpe_main_t * ngm = &lisp_gpe_main; + ip4_fib_t * fib = pool_elt_at_index (lgm->src_fibs, src_fib_index); + uword * hash, * p; - s = format (s, - "[%d] %U (src) %U (dst) fibs: encap %d, decap %d", - t - ngm->tunnels, - format_ip4_address, &t->src, - format_ip4_address, &t->dst, - t->encap_fib_index, - t->decap_fib_index); + hash = fib->adj_index_by_dst_address[address_length]; + p = hash_get (hash, src->as_u32); + return (void *) p; +} - s = format (s, " decap next %U\n", format_decap_next, t->decap_next_index); - s = format (s, "lisp ver %d ", (t->ver_res>>6)); +typedef CLIB_PACKED (struct { + ip4_address_t address; + u32 address_length : 6; + u32 index : 26; +}) ip4_route_t; -#define _(n,v) if (t->flags & v) s = format (s, "%s-bit ", #n); - foreach_lisp_gpe_flag_bit; -#undef _ +static void +ip4_sd_fib_clear_src_fib (lisp_gpe_main_t * lgm, ip4_fib_t * fib) +{ + ip4_route_t * routes = 0, * r; + u32 i; - s = format (s, "next_protocol %d ver_res %x res %x\n", - t->next_protocol, t->ver_res, t->res); - - s = format (s, "iid %d (0x%x)\n", t->iid, t->iid); - return s; + vec_reset_length (routes); + + for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++) { + uword * hash = fib->adj_index_by_dst_address[i]; + hash_pair_t * p; + ip4_route_t x; + + x.address_length = i; + + hash_foreach_pair (p, hash, + ({ + x.address.data_u32 = p->key; + vec_add1 (routes, x); + })); + } + + vec_foreach (r, routes) { + ip4_add_del_route_args_t a; + + memset (&a, 0, sizeof (a)); + a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL; + a.table_index_or_table_id = fib - lgm->src_fibs; + a.dst_address = r->address; + a.dst_address_length = r->address_length; + a.adj_index = ~0; + + ip4_sd_fib_add_del_src_route (lgm, &a); + } } -static u8 * format_lisp_gpe_name (u8 * s, va_list * args) +int +ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix, + ip_prefix_t * src_prefix, u32 table_index, + ip_adjacency_t * add_adj, u8 is_add) { - u32 dev_instance = va_arg (*args, u32); - return format (s, "lisp_gpe_tunnel%d", dev_instance); + uword * p; + ip4_add_del_route_args_t a; + ip_adjacency_t * dst_adjp, dst_adj; + ip4_address_t dst = ip_prefix_v4(dst_prefix), src; + u32 dst_address_length = ip_prefix_len(dst_prefix), src_address_length = 0; + ip4_fib_t * src_fib; + + if (src_prefix) + { + src = ip_prefix_v4(src_prefix); + src_address_length = ip_prefix_len(src_prefix); + } + else + memset(&src, 0, sizeof(src)); + + /* lookup dst adj */ + p = ip4_get_route (lgm->im4, table_index, 0, dst.as_u8, dst_address_length); + + if (is_add) + { + /* insert dst prefix to ip4 fib, if it's not in yet */ + if (p == 0) + { + /* dst adj should point to lisp gpe lookup */ + dst_adj = add_adj[0]; + dst_adj.lookup_next_index = lgm->ip4_lookup_next_lgpe_ip4_lookup; + + memset(&a, 0, sizeof(a)); + a.flags = IP4_ROUTE_FLAG_TABLE_ID; + a.table_index_or_table_id = table_index; /* vrf */ + a.adj_index = ~0; + a.dst_address_length = dst_address_length; + a.dst_address = dst; + a.flags |= IP4_ROUTE_FLAG_ADD; + a.add_adj = &dst_adj; + a.n_add_adj = 1; + + ip4_add_del_route (lgm->im4, &a); + + /* lookup dst adj to obtain the adj index */ + p = ip4_get_route (lgm->im4, table_index, 0, dst.as_u8, + dst_address_length); + if (p == 0) + { + clib_warning("Failed to insert dst route for eid %U!", + format_ip4_address_and_length, dst.as_u8, + dst_address_length); + return -1; + } + + /* allocate and init src ip4 fib */ + pool_get(lgm->src_fibs, src_fib); + ip4_mtrie_init (&src_fib->mtrie); + + /* reuse rewrite header to store pointer to src fib */ + dst_adjp = ip_get_adjacency (lgm->lookup_main, p[0]); + dst_adjp->rewrite_header.sw_if_index = src_fib - lgm->src_fibs; + } + } + else + { + if (p == 0) + { + clib_warning("Trying to delete inexistent dst route for %U. Aborting", + format_ip4_address_and_length, dst.as_u8, + dst_address_length); + return -1; + } + } + + dst_adjp = ip_get_adjacency (lgm->lookup_main, p[0]); + + /* add/del src prefix to src fib */ + memset(&a, 0, sizeof(a)); + a.flags = IP4_ROUTE_FLAG_TABLE_ID; + a.table_index_or_table_id = dst_adjp->rewrite_header.sw_if_index; + a.adj_index = ~0; + a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL; + a.add_adj = add_adj; + a.n_add_adj = 1; + /* if src prefix is null, add 0/0 */ + a.dst_address_length = src_address_length; + a.dst_address = src; + ip4_sd_fib_add_del_src_route (lgm, &a); + + /* if a delete, check if there are elements left in the src fib */ + if (!is_add) + { + src_fib = pool_elt_at_index(lgm->src_fibs, + dst_adjp->rewrite_header.sw_if_index); + if (!src_fib) + return 0; + + /* if there's nothing left, clear src fib .. */ + if (ARRAY_LEN(src_fib->adj_index_by_dst_address) == 0) + { + ip4_sd_fib_clear_src_fib (lgm, src_fib); + pool_put(lgm->src_fibs, src_fib); + } + + /* .. and remove dst route */ + memset(&a, 0, sizeof(a)); + a.flags = IP4_ROUTE_FLAG_TABLE_ID; + a.table_index_or_table_id = table_index; /* vrf */ + a.adj_index = ~0; + a.dst_address_length = dst_address_length; + a.dst_address = dst; + a.flags |= IP4_ROUTE_FLAG_DEL; + + ip4_add_del_route (lgm->im4, &a); + } + + return 0; } -static uword dummy_interface_tx (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +static void * +ip4_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix, + ip_prefix_t * src_prefix, u32 table_index) { - clib_warning ("you shouldn't be here, leaking buffers..."); - return frame->n_vectors; + uword * p; + ip4_address_t dst = ip_prefix_v4(dst_prefix), src; + u32 dst_address_length = ip_prefix_len(dst_prefix), src_address_length = 0; + ip_adjacency_t * dst_adj; + + if (src_prefix) + { + src = ip_prefix_v4(src_prefix); + src_address_length = ip_prefix_len(src_prefix); + } + else + memset(&src, 0, sizeof(src)); + + /* lookup dst adj */ + p = ip4_get_route (lgm->im4, table_index, 0, dst.as_u8, dst_address_length); + if (p == 0) + return p; + + dst_adj = ip_get_adjacency (lgm->lookup_main, p[0]); + return ip4_sd_get_src_route (lgm, dst_adj->rewrite_header.sw_if_index, &src, + src_address_length); } -VNET_DEVICE_CLASS (lisp_gpe_device_class,static) = { - .name = "LISP_GPE", - .format_device_name = format_lisp_gpe_name, - .format_tx_trace = format_lisp_gpe_encap_trace, - .tx_function = dummy_interface_tx, -}; +typedef enum +{ + LGPE_IP4_LOOKUP_NEXT_DROP, + LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP, + LGPE_IP4_LOOKUP_NEXT_LGPE_ENCAP, + LGPE_IP4_LOOKUP_N_NEXT, +} lgpe_ip4_lookup_next_t; -static uword dummy_set_rewrite (vnet_main_t * vnm, - u32 sw_if_index, - u32 l3_type, - void * dst_address, - void * rewrite, - uword max_rewrite_bytes) +always_inline void +ip4_src_fib_lookup_one (lisp_gpe_main_t * lgm, u32 src_fib_index0, + ip4_address_t * addr0, u32 * src_adj_index0) { - return 0; + ip4_fib_mtrie_leaf_t leaf0, leaf1; + ip4_fib_mtrie_t * mtrie0; + + mtrie0 = &vec_elt_at_index(lgm->src_fibs, src_fib_index0)->mtrie; + + leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT; + leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 0); + leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 1); + leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2); + leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3); + + /* Handle default route. */ + leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0); + src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0); } -u8 * format_lisp_gpe_header_with_length (u8 * s, va_list * args) +always_inline void +ip4_src_fib_lookup_two (lisp_gpe_main_t * lgm, u32 src_fib_index0, + u32 src_fib_index1, ip4_address_t * addr0, + ip4_address_t * addr1, u32 * src_adj_index0, + u32 * src_adj_index1) { - lisp_gpe_header_t * h = va_arg (*args, lisp_gpe_header_t *); - u32 max_header_bytes = va_arg (*args, u32); - u32 header_bytes; + ip4_fib_mtrie_leaf_t leaf0, leaf1; + ip4_fib_mtrie_t * mtrie0, * mtrie1; - header_bytes = sizeof (h[0]); - if (max_header_bytes != 0 && header_bytes > max_header_bytes) - return format (s, "gre-nsh header truncated"); + mtrie0 = &vec_elt_at_index(lgm->src_fibs, src_fib_index0)->mtrie; + mtrie1 = &vec_elt_at_index(lgm->src_fibs, src_fib_index1)->mtrie; - s = format (s, "flags: "); -#define _(n,v) if (h->flags & v) s = format (s, "%s ", #n); - foreach_lisp_gpe_flag_bit; -#undef _ + leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT; - s = format (s, "\n ver_res %d res %d next_protocol %d iid %d(%x)", - h->ver_res, h->res, h->next_protocol, - clib_net_to_host_u32 (h->iid), - clib_net_to_host_u32 (h->iid)); - return s; + leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 0); + leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 0); + + leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 1); + leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 1); + + leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2); + leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 2); + + leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3); + leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 3); + + /* Handle default route. */ + leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0); + leaf1 = (leaf1 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1); + src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0); + src_adj_index1[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf1); } -VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = { - .name = "LISP_GPE", - .format_header = format_lisp_gpe_header_with_length, - .set_rewrite = dummy_set_rewrite, -}; +always_inline uword +lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, next_index, * from, * to_next; + lisp_gpe_main_t * lgm = &lisp_gpe_main; -#define foreach_copy_field \ -_(src.as_u32) \ -_(dst.as_u32) \ -_(encap_fib_index) \ -_(decap_fib_index) \ -_(decap_next_index) \ -_(flags) \ -_(next_protocol) \ -_(ver_res) \ -_(res) \ -_(iid) + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t * b0, * b1; + ip4_header_t * ip0, * ip1; + u32 dst_adj_index0, src_adj_index0, src_fib_index0, dst_adj_index1, + src_adj_index1, src_fib_index1; + ip_adjacency_t * dst_adj0, * src_adj0, * dst_adj1, * src_adj1; + u32 next0, next1; + + next0 = next1 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP; -static int lisp_gpe_rewrite (lisp_gpe_tunnel_t * t) + /* Prefetch next iteration. */ + { + vlib_buffer_t * p2, * p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); + } + + bi0 = from[0]; + bi1 = from[1]; + to_next[0] = bi0; + to_next[1] = bi1; + from += 2; + to_next += 2; + n_left_to_next -= 2; + n_left_from -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + ip0 = vlib_buffer_get_current (b0); + ip1 = vlib_buffer_get_current (b1); + + /* dst lookup was done by ip4 lookup */ + dst_adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; + dst_adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX]; + + dst_adj0 = ip_get_adjacency (lgm->lookup_main, dst_adj_index0); + dst_adj1 = ip_get_adjacency (lgm->lookup_main, dst_adj_index1); + + src_fib_index0 = dst_adj0->rewrite_header.sw_if_index; + src_fib_index1 = dst_adj1->rewrite_header.sw_if_index; + + /* if default route not hit in ip4 lookup */ + if (PREDICT_TRUE(src_fib_index0 != (u32) ~0 + && src_fib_index1 != (u32) ~0)) + { + ip4_src_fib_lookup_two (lgm, src_fib_index0, src_fib_index1, + &ip0->src_address, &ip1->src_address, + &src_adj_index0, &src_adj_index1); + + vnet_buffer(b0)->ip.adj_index[VLIB_TX] = src_adj_index0; + vnet_buffer(b1)->ip.adj_index[VLIB_TX] = src_adj_index1; + + src_adj0 = ip_get_adjacency (lgm->lookup_main, src_adj_index0); + src_adj1 = ip_get_adjacency (lgm->lookup_main, src_adj_index1); + + next0 = src_adj0->lookup_next_index; + next1 = src_adj1->lookup_next_index; + } + else + { + if (src_fib_index0 != (u32) ~0) + { + ip4_src_fib_lookup_one (lgm, src_fib_index0, + &ip0->src_address, &src_adj_index0); + vnet_buffer(b0)->ip.adj_index[VLIB_TX] = src_adj_index0; + src_adj0 = ip_get_adjacency (lgm->lookup_main, + src_adj_index0); + next0 = src_adj0->lookup_next_index; + } + if (src_fib_index1 != (u32) ~0) + { + ip4_src_fib_lookup_one (lgm, src_fib_index1, + &ip1->src_address, &src_adj_index1); + vnet_buffer(b1)->ip.adj_index[VLIB_TX] = src_adj_index1; + src_adj1 = ip_get_adjacency (lgm->lookup_main, + src_adj_index1); + next1 = src_adj1->lookup_next_index; + } + } + + vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, + n_left_to_next, bi0, bi1, next0, + next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + vlib_buffer_t * b0; + ip4_header_t * ip0; + u32 bi0, dst_adj_index0, src_adj_index0, src_fib_index0; + u32 next0 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP; + ip_adjacency_t * dst_adj0, * src_adj0; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + ip0 = vlib_buffer_get_current (b0); + + /* dst lookup was done by ip4 lookup */ + dst_adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; + dst_adj0 = ip_get_adjacency (lgm->lookup_main, dst_adj_index0); + src_fib_index0 = dst_adj0->rewrite_header.sw_if_index; + + /* default route hit in ip4 lookup, send to lisp control plane */ + if (src_fib_index0 == (u32) ~0) + goto done; + + /* src lookup we do here */ + ip4_src_fib_lookup_one (lgm, src_fib_index0, &ip0->src_address, + &src_adj_index0); + vnet_buffer(b0)->ip.adj_index[VLIB_TX] = src_adj_index0; + src_adj0 = ip_get_adjacency (lgm->lookup_main, src_adj_index0); + next0 = src_adj0->lookup_next_index; + + done: + vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + return from_frame->n_vectors; +} + + +VLIB_REGISTER_NODE (lgpe_ip4_lookup_node) = { + .function = lgpe_ip4_lookup, + .name = "lgpe-ip4-lookup", + .vector_size = sizeof (u32), + + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_next_nodes = LGPE_IP4_LOOKUP_N_NEXT, + .next_nodes = { + [LGPE_IP4_LOOKUP_NEXT_DROP] = "error-drop", + [LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP] = "lisp-cp-lookup", + [LGPE_IP4_LOOKUP_NEXT_LGPE_ENCAP] = "lisp-gpe-encap", + }, +}; + +static int +lisp_gpe_rewrite (lisp_gpe_tunnel_t * t) { u8 *rw = 0; ip4_header_t * ip0; @@ -142,9 +564,9 @@ static int lisp_gpe_rewrite (lisp_gpe_tunnel_t * t) ip4_udp_lisp_gpe_header_t * h0; int len; - len = sizeof (*h0); + len = sizeof(*h0); - vec_validate_aligned (rw, len-1, CLIB_CACHE_LINE_BYTES); + vec_validate_aligned(rw, len - 1, CLIB_CACHE_LINE_BYTES); h0 = (ip4_udp_lisp_gpe_header_t *) rw; @@ -165,308 +587,416 @@ static int lisp_gpe_rewrite (lisp_gpe_tunnel_t * t) /* LISP-gpe header */ lisp0 = &h0->lisp; - + lisp0->flags = t->flags; lisp0->ver_res = t->ver_res; lisp0->res = t->res; lisp0->next_protocol = t->next_protocol; lisp0->iid = clib_host_to_net_u32 (t->iid); - + t->rewrite = rw; - return (0); + return 0; +} + +/* TODO remove */ +int +vnet_lisp_gpe_add_del_tunnel (vnet_lisp_gpe_add_del_tunnel_args_t *a, + u32 * sw_if_indexp) +{ + clib_warning ("UNSUPPORTED! Use vnet_lisp_gpe_add_del_fwd_entry"); + return 0; } -int vnet_lisp_gpe_add_del_tunnel -(vnet_lisp_gpe_add_del_tunnel_args_t *a, u32 * sw_if_indexp) +#define foreach_copy_field \ +_(encap_fib_index) \ +_(decap_fib_index) \ +_(decap_next_index) \ +_(flags) \ +_(next_protocol) \ +_(ver_res) \ +_(res) \ +_(iid) + +static u32 +add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res) { - lisp_gpe_main_t * ngm = &lisp_gpe_main; + lisp_gpe_main_t * lgm = &lisp_gpe_main; lisp_gpe_tunnel_t *t = 0; - vnet_main_t * vnm = ngm->vnet_main; - vnet_hw_interface_t * hi; uword * p; - u32 hw_if_index = ~0; - u32 sw_if_index = ~0; int rv; - lisp_gpe_tunnel_key_t key, *key_copy; - hash_pair_t *hp; - - key.src = a->src.as_u32; - key.iid = clib_host_to_net_u32(a->iid); + lisp_gpe_tunnel_key_t key; + + memset(&key, 0, sizeof(key)); + gid_address_copy(&key.eid, &a->deid); + key.dst_loc = ip_addr_v4(&a->dlocator).as_u32; + key.iid = clib_host_to_net_u32 (a->iid); + + p = mhash_get (&lgm->lisp_gpe_tunnel_by_key, &key); - p = hash_get_mem (ngm->lisp_gpe_tunnel_by_key, &key); - if (a->is_add) { /* adding a tunnel: tunnel must not already exist */ - if (p) + if (p) return VNET_API_ERROR_INVALID_VALUE; - + if (a->decap_next_index >= LISP_GPE_INPUT_N_NEXT) return VNET_API_ERROR_INVALID_DECAP_NEXT; - - pool_get_aligned (ngm->tunnels, t, CLIB_CACHE_LINE_BYTES); + + pool_get_aligned (lgm->tunnels, t, CLIB_CACHE_LINE_BYTES); memset (t, 0, sizeof (*t)); - + /* copy from arg structure */ #define _(x) t->x = a->x; foreach_copy_field; #undef _ - + + t->src = ip_addr_v4(&a->slocator); + t->dst = ip_addr_v4(&a->dlocator); + rv = lisp_gpe_rewrite (t); if (rv) { - pool_put (ngm->tunnels, t); + pool_put(lgm->tunnels, t); return rv; } - key_copy = clib_mem_alloc (sizeof (*key_copy)); - memcpy (key_copy, &key, sizeof (*key_copy)); + mhash_set(&lgm->lisp_gpe_tunnel_by_key, &key, t - lgm->tunnels, 0); - hash_set_mem (ngm->lisp_gpe_tunnel_by_key, key_copy, - t - ngm->tunnels); - - if (vec_len (ngm->free_lisp_gpe_tunnel_hw_if_indices) > 0) - { - hw_if_index = ngm->free_lisp_gpe_tunnel_hw_if_indices - [vec_len (ngm->free_lisp_gpe_tunnel_hw_if_indices)-1]; - _vec_len (ngm->free_lisp_gpe_tunnel_hw_if_indices) -= 1; - - hi = vnet_get_hw_interface (vnm, hw_if_index); - hi->dev_instance = t - ngm->tunnels; - hi->hw_instance = hi->dev_instance; - } - else - { - hw_if_index = vnet_register_interface - (vnm, lisp_gpe_device_class.index, t - ngm->tunnels, - lisp_gpe_hw_class.index, t - ngm->tunnels); - hi = vnet_get_hw_interface (vnm, hw_if_index); - hi->output_node_index = lisp_gpe_encap_node.index; - } - - t->hw_if_index = hw_if_index; - t->sw_if_index = sw_if_index = hi->sw_if_index; - - vnet_sw_interface_set_flags (vnm, hi->sw_if_index, - VNET_SW_INTERFACE_FLAG_ADMIN_UP); + /* return tunnel index */ + if (tun_index_res) + tun_index_res[0] = t - lgm->tunnels; } else { /* deleting a tunnel: tunnel must exist */ - if (!p) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - t = pool_elt_at_index (ngm->tunnels, p[0]); + if (!p) + { + clib_warning("Tunnel for eid %U doesn't exist!", format_gid_address, + &a->deid); + return VNET_API_ERROR_NO_SUCH_ENTRY; + } - vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */); - vec_add1 (ngm->free_lisp_gpe_tunnel_hw_if_indices, t->hw_if_index); + t = pool_elt_at_index(lgm->tunnels, p[0]); - hp = hash_get_pair (ngm->lisp_gpe_tunnel_by_key, &key); - key_copy = (void *)(hp->key); - hash_unset_mem (ngm->lisp_gpe_tunnel_by_key, &key); - clib_mem_free (key_copy); + mhash_unset(&lgm->lisp_gpe_tunnel_by_key, &key, 0); - vec_free (t->rewrite); - pool_put (ngm->tunnels, t); + vec_free(t->rewrite); + pool_put(lgm->tunnels, t); } - if (sw_if_indexp) - *sw_if_indexp = sw_if_index; - return 0; } -static u32 fib_index_from_fib_id (u32 fib_id) +int +vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, + u32 * hw_if_indexp) { - ip4_main_t * im = &ip4_main; - uword * p; + lisp_gpe_main_t * lgm = &lisp_gpe_main; + ip_adjacency_t adj, * adjp; + u32 * adj_index, rv, tun_index = ~0; + ip_prefix_t * dpref = &gid_address_ippref(&a->deid); + ip_prefix_t * spref = &gid_address_ippref(&a->seid); - p = hash_get (im->fib_index_by_table_id, fib_id); - if (!p) - return ~0; + /* setup adjacency for eid */ + memset (&adj, 0, sizeof(adj)); + adj.n_adj = 1; + adj.explicit_fib_index = ~0; - return p[0]; -} + /* treat negative fwd entries separately */ + if (a->is_negative) + { + switch (a->action) + { + case NO_ACTION: + /* TODO update timers? */ + case FORWARD_NATIVE: + /* TODO check if route/next-hop for eid exists in fib and add + * more specific for the eid with the next-hop found */ + case SEND_MAP_REQUEST: + /* TODO insert tunnel that always sends map-request */ + case DROP: + /* for drop fwd entries, just add route, no need to add encap tunnel */ + adj.lookup_next_index = LGPE_IP4_LOOKUP_NEXT_DROP; -static uword unformat_decap_next (unformat_input_t * input, va_list * args) -{ - u32 * result = va_arg (*args, u32 *); - u32 tmp; - - if (unformat (input, "drop")) - *result = LISP_GPE_INPUT_NEXT_DROP; - else if (unformat (input, "ip4")) - *result = LISP_GPE_INPUT_NEXT_IP4_INPUT; - else if (unformat (input, "ip6")) - *result = LISP_GPE_INPUT_NEXT_IP6_INPUT; - else if (unformat (input, "ethernet")) - *result = LISP_GPE_INPUT_NEXT_IP6_INPUT; - else if (unformat (input, "lisp-gpe")) - *result = LISP_GPE_INPUT_NEXT_LISP_GPE_ENCAP; - else if (unformat (input, "%d", &tmp)) - *result = tmp; - else - return 0; - return 1; + /* add/delete route for prefix */ + rv = ip4_sd_fib_add_del_route (lgm, dpref, spref, a->iid, &adj, + a->is_add); + return rv; + break; + default: + return -1; + } + } + + /* send packets that hit this adj to lisp-gpe encap */ + adj.lookup_next_index = LGPE_IP4_LOOKUP_NEXT_LGPE_ENCAP; + + /* add/delete route for prefix + * TODO use hash to decide fib instead of using iid in clear */ + rv = ip4_sd_fib_add_del_route (lgm, dpref, spref, a->iid, &adj, a->is_add); + + if (rv) + return rv; + + /* add/del tunnel to tunnels pool */ + rv = add_del_tunnel (a, &tun_index); + + /* reuse sw_if_index for storing the tunnel index */ + if (a->is_add) + { + adj_index = ip4_sd_fib_get_route(lgm, dpref, spref, a->iid); + if (!adj_index) + { + clib_warning("Failed to insert fwd entry! For %U", + format_ip4_address_and_length, ip_prefix_v4(dpref), + ip_prefix_len(dpref)); + return -1; + } + adjp = ip_get_adjacency (lgm->lookup_main, adj_index[0]); + adjp->rewrite_header.sw_if_index = tun_index; + } + + return rv; } static clib_error_t * -lisp_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) +lisp_gpe_add_del_fwd_entry_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 src, dst; u8 is_add = 1; - u8 src_set = 0; - u8 dst_set = 0; - u32 encap_fib_index = 0; - u32 decap_fib_index = 0; - u8 next_protocol = LISP_GPE_NEXT_PROTOCOL_IP4; - u32 decap_next_index = LISP_GPE_INPUT_NEXT_IP4_INPUT; - u8 flags = LISP_GPE_FLAGS_P; - u8 ver_res = 0; - u8 res = 0; - u32 iid = 0; - u8 iid_set = 0; - u32 tmp; - int rv; - vnet_lisp_gpe_add_del_tunnel_args_t _a, * a = &_a; - + ip_address_t slocator, dlocator, *slocators = 0, *dlocators = 0; + ip_prefix_t * prefp; + gid_address_t * eids = 0, eid; + clib_error_t * error = 0; + u32 i; + + prefp = &gid_address_ippref(&eid); + /* 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, "del")) - is_add = 0; - else if (unformat (line_input, "src %U", - unformat_ip4_address, &src)) - src_set = 1; - else if (unformat (line_input, "dst %U", - unformat_ip4_address, &dst)) - dst_set = 1; - else if (unformat (line_input, "encap-vrf-id %d", &tmp)) - { - encap_fib_index = fib_index_from_fib_id (tmp); - if (encap_fib_index == ~0) - return clib_error_return (0, "nonexistent encap fib id %d", tmp); - } - else if (unformat (line_input, "decap-vrf-id %d", &tmp)) - { - decap_fib_index = fib_index_from_fib_id (tmp); - if (decap_fib_index == ~0) - return clib_error_return (0, "nonexistent decap fib id %d", tmp); - } - else if (unformat (line_input, "decap-next %U", unformat_decap_next, - &decap_next_index)) - ; - else if (unformat(line_input, "next-ip4")) - next_protocol = 1; - else if (unformat(line_input, "next-ip6")) - next_protocol = 2; - else if (unformat(line_input, "next-ethernet")) - next_protocol = 3; - else if (unformat(line_input, "next-nsh")) - next_protocol = 4; - /* Allow the user to specify anything they want in the LISP hdr */ - else if (unformat (line_input, "ver_res %x", &tmp)) - ver_res = tmp; - else if (unformat (line_input, "res %x", &tmp)) - res = tmp; - else if (unformat (line_input, "flags %x", &tmp)) - flags = tmp; - else if (unformat (line_input, "n-bit")) - flags |= LISP_GPE_FLAGS_N; - else if (unformat (line_input, "l-bit")) - flags |= LISP_GPE_FLAGS_L; - else if (unformat (line_input, "e-bit")) - flags |= LISP_GPE_FLAGS_E; - else if (unformat (line_input, "v-bit")) - flags |= LISP_GPE_FLAGS_V; - else if (unformat (line_input, "i-bit")) - flags |= LISP_GPE_FLAGS_V; - else if (unformat (line_input, "not-p-bit")) - flags &= ~LISP_GPE_FLAGS_P; - else if (unformat (line_input, "p-bit")) - flags |= LISP_GPE_FLAGS_P; - else if (unformat (line_input, "o-bit")) - flags |= LISP_GPE_FLAGS_O; - else if (unformat (line_input, "iidx %x", &iid)) - iid_set = 1; - else if (unformat (line_input, "iid %d", &iid)) - iid_set = 1; - else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - } - + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "add")) + is_add = 1; + else if (unformat (line_input, "eid %U slocator %U dlocator %U", + unformat_ip_prefix, prefp, + unformat_ip_address, &slocator, + unformat_ip_address, &dlocator)) + { + vec_add1 (eids, eid); + vec_add1 (slocators, slocator); + vec_add1 (dlocators, dlocator); + } + else + { + error = unformat_parse_error (line_input); + goto done; + } + } unformat_free (line_input); - if (src_set == 0) - return clib_error_return (0, "tunnel src address not specified"); + if (vec_len (eids) + vec_len (slocators) == 0) + { + error = clib_error_return (0, "expected ip4/ip6 eids/locators."); + goto done; + } - if (dst_set == 0) - return clib_error_return (0, "tunnel dst address not specified"); + if (vec_len (eids) != vec_len (slocators)) + { + error = clib_error_return (0, "number of eids not equal to that of locators."); + goto done; + } - if (iid_set == 0) - return clib_error_return (0, "iid not specified"); + for (i = 0; i < vec_len(eids); i++) + { + vnet_lisp_gpe_add_del_fwd_entry_args_t a; + memset (&a, 0, sizeof(a)); - memset (a, 0, sizeof (*a)); + a.is_add = is_add; + a.deid = eids[i]; + a.slocator = slocators[i]; + a.dlocator = dlocators[i]; + prefp = &gid_address_ippref(&a.deid); + a.decap_next_index = (ip_prefix_version(prefp) == IP4) ? + LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT; + vnet_lisp_gpe_add_del_fwd_entry (&a, 0); + } - a->is_add = is_add; + done: + vec_free(eids); + vec_free(slocators); + return error; +} -#define _(x) a->x = x; - foreach_copy_field; -#undef _ - - rv = vnet_lisp_gpe_add_del_tunnel (a, 0 /* hw_if_indexp */); +VLIB_CLI_COMMAND (add_del_lisp_gpe_mapping_tunnel_command, static) = { + .path = "lisp gpe maptunnel", + .short_help = "lisp gpe maptunnel eid <eid> sloc <src-locator> dloc <dst-locator> [del]", + .function = lisp_gpe_add_del_fwd_entry_command_fn, +}; - switch(rv) - { - case 0: - break; - case VNET_API_ERROR_INVALID_DECAP_NEXT: - return clib_error_return (0, "invalid decap-next..."); +int +add_del_ip_prefix_route (ip_prefix_t * dst_prefix, u32 table_id, + ip_adjacency_t * add_adj, u8 is_add, u32 * adj_index) +{ + uword * p; - case VNET_API_ERROR_TUNNEL_EXIST: - return clib_error_return (0, "tunnel already exists..."); + if (ip_prefix_version(dst_prefix) == IP4) + { + ip4_main_t * im4 = &ip4_main; + ip4_add_del_route_args_t a; + ip4_address_t addr = ip_prefix_v4(dst_prefix); - case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "tunnel does not exist..."); + memset(&a, 0, sizeof(a)); + a.flags = IP4_ROUTE_FLAG_TABLE_ID; + a.table_index_or_table_id = table_id; + a.adj_index = ~0; + a.dst_address_length = ip_prefix_len(dst_prefix); + a.dst_address = addr; + a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL; + a.add_adj = add_adj; + a.n_add_adj = 1; + ip4_add_del_route (im4, &a); - default: - return clib_error_return - (0, "vnet_lisp_gpe_add_del_tunnel returned %d", rv); + if (is_add) + { + p = ip4_get_route (im4, table_id, 0, addr.as_u8, + ip_prefix_len(dst_prefix)); + if (p == 0) + { + clib_warning("Failed to insert route for eid %U!", + format_ip4_address_and_length, addr.as_u8, + ip_prefix_len(dst_prefix)); + return -1; + } + adj_index[0] = p[0]; + } } + else + { + ip6_main_t * im6 = &ip6_main; + ip6_add_del_route_args_t a; + ip6_address_t addr = ip_prefix_v6(dst_prefix); + memset(&a, 0, sizeof(a)); + a.flags = IP6_ROUTE_FLAG_TABLE_ID; + a.table_index_or_table_id = table_id; + a.adj_index = ~0; + a.dst_address_length = ip_prefix_len(dst_prefix); + a.dst_address = addr; + a.flags |= is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL; + a.add_adj = add_adj; + a.n_add_adj = 1; + + ip6_add_del_route (im6, &a); + + if (is_add) + { + adj_index[0] = ip6_get_route (im6, table_id, 0, &addr, + ip_prefix_len(dst_prefix)); + if (adj_index[0] == 0) + { + clib_warning("Failed to insert route for eid %U!", + format_ip6_address_and_length, addr.as_u8, + ip_prefix_len(dst_prefix)); + return -1; + } + } + } return 0; } -VLIB_CLI_COMMAND (create_lisp_gpe_tunnel_command, static) = { - .path = "lisp gpe tunnel", - .short_help = - "lisp gpe tunnel src <ip4-addr> dst <ip4-addr> iidx <0xnn> | iid <nn>\n" - " [encap-fib-id <nn>] [decap-fib-id <nn>]\n" - " [n-bit][l-bit][e-bit][v-bit][i-bit][p-bit][not-p-bit][o-bit]\n" - " [next-ip4][next-ip6][next-ethernet][next-nsh]\n" - " [decap-next [ip4|ip6|ethernet|nsh-encap|<nn>]][del]\n", - .function = lisp_gpe_add_del_tunnel_command_fn, -}; +static void +add_del_lisp_gpe_default_route (u8 is_v4, u8 is_add) +{ + lisp_gpe_main_t * lgm = &lisp_gpe_main; + ip_adjacency_t adj; + ip_prefix_t prefix; + u32 adj_index = 0; + + /* setup adjacency */ + memset (&adj, 0, sizeof(adj)); + adj.n_adj = 1; + adj.explicit_fib_index = ~0; + adj.lookup_next_index = lgm->ip4_lookup_next_lgpe_ip4_lookup; + /* default route has tunnel_index ~0 */ + adj.rewrite_header.sw_if_index = ~0; + + /* set prefix to 0/0 */ + memset(&prefix, 0, sizeof(prefix)); + ip_prefix_version(&prefix) = is_v4 ? IP4 : IP6; + + /* add/delete route for prefix XXX default table only */ + add_del_ip_prefix_route (&prefix, 0, &adj, is_add, &adj_index); +} + +static u8 * +format_decap_next (u8 * s, va_list * args) +{ + u32 next_index = va_arg (*args, u32); + + switch (next_index) + { + case LISP_GPE_INPUT_NEXT_DROP: + return format (s, "drop"); + case LISP_GPE_INPUT_NEXT_IP4_INPUT: + return format (s, "ip4"); + case LISP_GPE_INPUT_NEXT_IP6_INPUT: + return format (s, "ip6"); + case LISP_GPE_INPUT_NEXT_LISP_GPE_ENCAP: + return format (s, "nsh-lisp-gpe"); + default: + return format (s, "unknown %d", next_index); + } + return s; +} + +u8 * +format_lisp_gpe_tunnel (u8 * s, va_list * args) +{ + lisp_gpe_tunnel_t * t = va_arg (*args, lisp_gpe_tunnel_t *); + lisp_gpe_main_t * lgm = &lisp_gpe_main; + + s = format (s, + "[%d] %U (src) %U (dst) fibs: encap %d, decap %d", + t - lgm->tunnels, + format_ip4_address, &t->src, + format_ip4_address, &t->dst, + t->encap_fib_index, + t->decap_fib_index); + + s = format (s, " decap next %U\n", format_decap_next, t->decap_next_index); + s = format (s, "lisp ver %d ", (t->ver_res>>6)); + +#define _(n,v) if (t->flags & v) s = format (s, "%s-bit ", #n); + foreach_lisp_gpe_flag_bit; +#undef _ + + s = format (s, "next_protocol %d ver_res %x res %x\n", + t->next_protocol, t->ver_res, t->res); + + s = format (s, "iid %d (0x%x)\n", t->iid, t->iid); + return s; +} static clib_error_t * show_lisp_gpe_tunnel_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - lisp_gpe_main_t * ngm = &lisp_gpe_main; + lisp_gpe_main_t * lgm = &lisp_gpe_main; lisp_gpe_tunnel_t * t; - if (pool_elts (ngm->tunnels) == 0) + if (pool_elts (lgm->tunnels) == 0) vlib_cli_output (vm, "No lisp-gpe tunnels configured..."); - pool_foreach (t, ngm->tunnels, + pool_foreach (t, lgm->tunnels, ({ vlib_cli_output (vm, "%U", format_lisp_gpe_tunnel, t); })); @@ -479,15 +1009,154 @@ VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) = { .function = show_lisp_gpe_tunnel_command_fn, }; -clib_error_t *lisp_gpe_init (vlib_main_t *vm) +static u8 * +format_lisp_gpe_name (u8 * s, va_list * args) { - lisp_gpe_main_t *ngm = &lisp_gpe_main; - - ngm->vnet_main = vnet_get_main(); - ngm->vlib_main = vm; + u32 dev_instance = va_arg (*args, u32); + return format (s, "lisp_gpe_tunnel%d", dev_instance); +} + +static uword +dummy_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + clib_warning("you shouldn't be here, leaking buffers..."); + return frame->n_vectors; +} + +VNET_DEVICE_CLASS (lisp_gpe_device_class,static) = { + .name = "LISP_GPE", + .format_device_name = format_lisp_gpe_name, + .format_tx_trace = format_lisp_gpe_encap_trace, + .tx_function = dummy_interface_tx, +}; + +static uword +dummy_set_rewrite (vnet_main_t * vnm, u32 sw_if_index, u32 l3_type, + void * dst_address, void * rewrite, uword max_rewrite_bytes) +{ + return 0; +} + +u8 * +format_lisp_gpe_header_with_length (u8 * s, va_list * args) +{ + lisp_gpe_header_t * h = va_arg (*args, lisp_gpe_header_t *); + u32 max_header_bytes = va_arg (*args, u32); + u32 header_bytes; + + header_bytes = sizeof (h[0]); + if (max_header_bytes != 0 && header_bytes > max_header_bytes) + return format (s, "gre-nsh header truncated"); + + s = format (s, "flags: "); +#define _(n,v) if (h->flags & v) s = format (s, "%s ", #n); + foreach_lisp_gpe_flag_bit; +#undef _ + + s = format (s, "\n ver_res %d res %d next_protocol %d iid %d(%x)", + h->ver_res, h->res, h->next_protocol, + clib_net_to_host_u32 (h->iid), + clib_net_to_host_u32 (h->iid)); + return s; +} + +VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = { + .name = "LISP_GPE", + .format_header = format_lisp_gpe_header_with_length, + .set_rewrite = dummy_set_rewrite, +}; + +void +vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a, + u32 * hw_if_indexp) +{ + lisp_gpe_main_t * lgm = &lisp_gpe_main; + vnet_main_t * vnm = lgm->vnet_main; + vnet_hw_interface_t * hi; + u32 hw_if_index = ~0; + + if (a->is_add) + { + /* create hw lisp_gpe0 iface */ + hw_if_index = vnet_register_interface (vnm, lisp_gpe_device_class.index, 0, + lisp_gpe_hw_class.index, 0); + + hi = vnet_get_hw_interface (vnm, hw_if_index); + hi->output_node_index = lisp_gpe_encap_node.index; + lgm->lisp_gpe_hw_if_index = hw_if_index; + + /* add lgpe_ip4_lookup as possible next_node for ip4 lookup */ + lgm->ip4_lookup_next_lgpe_ip4_lookup = vlib_node_add_next ( + vnm->vlib_main, ip4_lookup_node.index, lgpe_ip4_lookup_node.index); + + /* insert default routes that points at lisp-gpe-encap */ + add_del_lisp_gpe_default_route(/* is_v4 */1, 1); + add_del_lisp_gpe_default_route(/* is_v4 */0, 1); + } + else + { + vnet_sw_interface_set_flags (vnm, lgm->lisp_gpe_hw_if_index, + 0 /* down */); + } +} + +static clib_error_t * +lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, * line_input = &_line_input; + u8 is_add = 1; + vnet_lisp_gpe_add_del_iface_args_t _a, * a = &_a; + + /* 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, "up")) + is_add = 1; + else if (unformat (line_input, "down")) + is_add = 0; + else + { + return clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + } + } + + a->is_add = is_add; + vnet_lisp_gpe_add_del_iface (a, 0); + return 0; +} + +VLIB_CLI_COMMAND (add_del_lisp_gpe_iface_command, static) = { + .path = "lisp gpe iface", + .short_help = "lisp gpe iface [del]", + .function = lisp_gpe_add_del_iface_command_fn, +}; + +clib_error_t * +lisp_gpe_init (vlib_main_t *vm) +{ + lisp_gpe_main_t * lgm = &lisp_gpe_main; + clib_error_t * error = 0; + + if ((error = vlib_call_init_function (vm, ip_main_init))) + return error; + + if ((error = vlib_call_init_function (vm, ip4_lookup_init))) + return error; + + lgm->vnet_main = vnet_get_main(); + lgm->vlib_main = vm; + lgm->im4 = &ip4_main; + lgm->lookup_main = &ip4_main.lookup_main; - ngm->lisp_gpe_tunnel_by_key - = hash_create_mem (0, sizeof(lisp_gpe_tunnel_key_t), sizeof (uword)); + mhash_init (&lgm->lisp_gpe_tunnel_by_key, sizeof(uword), + sizeof(lisp_gpe_tunnel_key_t)); udp_register_dst_port (vm, UDP_DST_PORT_lisp_gpe, lisp_gpe_input_node.index, 1 /* is_ip4 */); @@ -495,4 +1164,3 @@ clib_error_t *lisp_gpe_init (vlib_main_t *vm) } VLIB_INIT_FUNCTION(lisp_gpe_init); - diff --git a/vnet/vnet/lisp-gpe/lisp_gpe.h b/vnet/vnet/lisp-gpe/lisp_gpe.h index 12c4ebce38c..7e86d57fc1a 100644 --- a/vnet/vnet/lisp-gpe/lisp_gpe.h +++ b/vnet/vnet/lisp-gpe/lisp_gpe.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * 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: @@ -12,18 +12,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #ifndef included_vnet_lisp_gpe_h #define included_vnet_lisp_gpe_h #include <vppinfra/error.h> -#include <vppinfra/hash.h> +#include <vppinfra/mhash.h> #include <vnet/vnet.h> #include <vnet/ip/ip.h> #include <vnet/l2/l2_input.h> #include <vnet/ethernet/ethernet.h> -#include <vnet/lisp-gpe/lisp_gpe_packet.h> #include <vnet/ip/ip4_packet.h> #include <vnet/ip/udp.h> +#include <vnet/lisp-cp/lisp_types.h> +#include <vnet/lisp-gpe/lisp_gpe_packet.h> + +#define IP_UDP_HDR_LEN (word) (sizeof(udp_header_t) + sizeof(ip4_header_t)) typedef CLIB_PACKED (struct { ip4_header_t ip4; /* 20 bytes */ @@ -31,21 +35,22 @@ typedef CLIB_PACKED (struct { lisp_gpe_header_t lisp; /* 8 bytes */ }) ip4_udp_lisp_gpe_header_t; -typedef CLIB_PACKED(struct { - /* - * Key fields: ip src, LISP iid, ??? $$$$$$$$$ correct answer ??? - * all fields in NET byte order - */ - union { - struct { - u32 src; - u32 iid; - }; - u64 as_u64[1]; +typedef struct +{ + union + { + struct + { + gid_address_t eid; + u32 dst_loc; + u32 iid; + }; + u8 as_u8[6]; }; -}) lisp_gpe_tunnel_key_t; +} lisp_gpe_tunnel_key_t; -typedef struct { +typedef struct +{ /* Rewrite string. $$$$ embed vnet_rewrite header */ u8 * rewrite; @@ -93,30 +98,53 @@ typedef enum { LISP_GPE_N_ERROR, } lisp_gpe_input_error_t; -typedef struct { +/* As a first step, reuse v4 fib. The goal of the typedef is to shield + * consumers from future updates that may result in the lisp ip4 fib diverging + * from ip4 fib */ +typedef ip4_fib_t lisp_ip4_fib_t; + +typedef struct lisp_gpe_main +{ + /* Pool of src fibs that are paired with dst fibs */ + ip4_fib_t * src_fibs; + /* vector of encap tunnel instances */ - lisp_gpe_tunnel_t *tunnels; + lisp_gpe_tunnel_t * tunnels; /* lookup tunnel by key */ - uword * lisp_gpe_tunnel_by_key; + mhash_t lisp_gpe_tunnel_by_key; + + /* lookup tunnel by adjacency index */ + uword * lisp_gpe_tunnel_by_adj_index; /* Free vlib hw_if_indices */ u32 * free_lisp_gpe_tunnel_hw_if_indices; + u32 lisp_gpe_hw_if_index; + + /* next node indexes that points ip4 lookup to lisp gpe lookup and lisp cp */ + u32 ip4_lookup_next_lgpe_ip4_lookup; + /* convenience */ vlib_main_t * vlib_main; vnet_main_t * vnet_main; + ip_lookup_main_t * lookup_main; + ip4_main_t * im4; } lisp_gpe_main_t; lisp_gpe_main_t lisp_gpe_main; +extern vlib_node_registration_t lgpe_ip4_lookup_node; extern vlib_node_registration_t lisp_gpe_input_node; extern vlib_node_registration_t lisp_gpe_encap_node; -u8 * format_lisp_gpe_encap_trace (u8 * s, va_list * args); -u8 * format_lisp_gpe_header_with_length (u8 * s, va_list * args); +u8 * +format_lisp_gpe_encap_trace (u8 * s, va_list * args); +u8 * +format_lisp_gpe_header_with_length (u8 * s, va_list * args); -typedef struct { +typedef struct +{ u8 is_add; ip4_address_t src, dst; u32 encap_fib_index; @@ -126,12 +154,54 @@ typedef struct { u8 ver_res; u8 res; u8 next_protocol; - u32 iid; /* host byte order */ + u32 iid; /* host byte order */ } vnet_lisp_gpe_add_del_tunnel_args_t; -int vnet_lisp_gpe_add_del_tunnel -(vnet_lisp_gpe_add_del_tunnel_args_t *a, u32 * sw_if_indexp); +int +vnet_lisp_gpe_add_del_tunnel (vnet_lisp_gpe_add_del_tunnel_args_t *a, + u32 * sw_if_indexp); + +typedef struct +{ + u8 is_add; +} vnet_lisp_gpe_add_del_iface_args_t; + +void +vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t *a, + u32 * hw_if_indexp); + +typedef enum +{ + NO_ACTION, + FORWARD_NATIVE, + SEND_MAP_REQUEST, + DROP +} negative_fwd_actions_e; + +typedef struct +{ + u8 is_add; + u8 is_negative; + negative_fwd_actions_e action; + gid_address_t seid; /* TODO convert to ip4, ip6, mac ? */ + gid_address_t deid; + ip_address_t slocator; + ip_address_t dlocator; + u32 encap_fib_index; + u32 decap_fib_index; + u32 decap_next_index; + u8 flags; + u8 ver_res; + u8 res; + u8 next_protocol; + u32 iid; /* host byte order */ +} vnet_lisp_gpe_add_del_fwd_entry_args_t; + +int +vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, + u32 * hw_if_indexp); -u8 * format_lisp_gpe_header_with_length (u8 * s, va_list * args); +u8 * +format_lisp_gpe_header_with_length (u8 * s, va_list * args); #endif /* included_vnet_lisp_gpe_h */ diff --git a/vnet/vnet/lisp-gpe/lisp_gpe_error.def b/vnet/vnet/lisp-gpe/lisp_gpe_error.def index 6ef894f474d..f002ecaeac0 100644 --- a/vnet/vnet/lisp-gpe/lisp_gpe_error.def +++ b/vnet/vnet/lisp-gpe/lisp_gpe_error.def @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * 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: @@ -12,5 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + lisp_gpe_error (DECAPSULATED, "good packets decapsulated") lisp_gpe_error (NO_SUCH_TUNNEL, "no such tunnel packets") diff --git a/vnet/vnet/lisp-gpe/lisp_gpe_packet.h b/vnet/vnet/lisp-gpe/lisp_gpe_packet.h index b3d96ed9d44..360157b700c 100644 --- a/vnet/vnet/lisp-gpe/lisp_gpe_packet.h +++ b/vnet/vnet/lisp-gpe/lisp_gpe_packet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * 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: @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #ifndef included_lisp_gpe_packet_h #define included_lisp_gpe_packet_h @@ -120,4 +121,13 @@ foreach_lisp_gpe_flag_bit #define LISP_GPE_NEXT_PROTOCOL_ETHERNET 0x3 #define LISP_GPE_NEXT_PROTOCOL_NSH 0x4 +typedef enum +{ + LISP_GPE_NEXT_PROTO_IP4 = 1, + LISP_GPE_NEXT_PROTO_IP6, + LISP_GPE_NEXT_PROTO_ETHERNET, + LISP_GPE_NEXT_PROTO_NSH, + LISP_GPE_NEXT_PROTOS +} lisp_gpe_next_protocol_e; + #endif /* included_lisp_gpe_packet_h */ |