From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vnet/lisp-cp/gid_dictionary.c | 865 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 865 insertions(+) create mode 100644 src/vnet/lisp-cp/gid_dictionary.c (limited to 'src/vnet/lisp-cp/gid_dictionary.c') diff --git a/src/vnet/lisp-cp/gid_dictionary.c b/src/vnet/lisp-cp/gid_dictionary.c new file mode 100644 index 00000000..d238124e --- /dev/null +++ b/src/vnet/lisp-cp/gid_dictionary.c @@ -0,0 +1,865 @@ +/* + * 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 + +typedef struct +{ + void *arg; + ip_prefix_t src; + foreach_subprefix_match_cb_t cb; + union + { + gid_ip4_table_t *ip4_table; + gid_ip6_table_t *ip6_table; + }; +} sfib_entry_arg_t; + +static u32 ip4_lookup (gid_ip4_table_t * db, u32 vni, ip_prefix_t * key); + +static u32 ip6_lookup (gid_ip6_table_t * db, u32 vni, ip_prefix_t * key); + +static void +foreach_sfib4_subprefix (BVT (clib_bihash_kv) * kvp, void *arg) +{ + sfib_entry_arg_t *a = arg; + u32 ip = (u32) kvp->key[0]; + ip4_address_t *mask; + u8 plen = ip_prefix_len (&a->src); + + ASSERT (plen <= 32); + mask = &a->ip4_table->ip4_fib_masks[plen]; + + u32 src_ip = ip_prefix_v4 (&a->src).as_u32; + src_ip &= mask->as_u32; + ip &= mask->as_u32; + + if (src_ip == ip) + { + /* found sub-prefix of src prefix */ + (a->cb) (kvp->value, a->arg); + } +} + +static void +gid_dict_foreach_ip4_subprefix (gid_dictionary_t * db, u32 vni, + ip_prefix_t * src, ip_prefix_t * dst, + foreach_subprefix_match_cb_t cb, void *arg) +{ + u32 sfi; + gid_ip4_table_t *sfib4; + sfib_entry_arg_t a; + + sfi = ip4_lookup (&db->dst_ip4_table, vni, dst); + if (GID_LOOKUP_MISS == sfi) + return; + + sfib4 = pool_elt_at_index (db->src_ip4_table_pool, sfi); + + a.arg = arg; + a.cb = cb; + a.src = src[0]; + a.ip4_table = sfib4; + + BV (clib_bihash_foreach_key_value_pair) (&sfib4->ip4_lookup_table, + foreach_sfib4_subprefix, &a); +} + +static void +foreach_sfib6_subprefix (BVT (clib_bihash_kv) * kvp, void *arg) +{ + sfib_entry_arg_t *a = arg; + ip6_address_t ip; + ip6_address_t *mask; + u8 plen = ip_prefix_len (&a->src); + + mask = &a->ip6_table->ip6_fib_masks[plen]; + ip.as_u64[0] = kvp->key[0]; + ip.as_u64[1] = kvp->key[1]; + + if (ip6_address_is_equal_masked (&ip_prefix_v6 (&a->src), &ip, mask)) + { + /* found sub-prefix of src prefix */ + (a->cb) (kvp->value, a->arg); + } +} + +static void +gid_dict_foreach_ip6_subprefix (gid_dictionary_t * db, u32 vni, + ip_prefix_t * src, ip_prefix_t * dst, + foreach_subprefix_match_cb_t cb, void *arg) +{ + u32 sfi; + gid_ip6_table_t *sfib6; + sfib_entry_arg_t a; + + sfi = ip6_lookup (&db->dst_ip6_table, vni, dst); + if (GID_LOOKUP_MISS == sfi) + return; + + sfib6 = pool_elt_at_index (db->src_ip6_table_pool, sfi); + + a.arg = arg; + a.cb = cb; + a.src = src[0]; + a.ip6_table = sfib6; + + BV (clib_bihash_foreach_key_value_pair) (&sfib6->ip6_lookup_table, + foreach_sfib6_subprefix, &a); +} + +void +gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid, + foreach_subprefix_match_cb_t cb, void *arg) +{ + ip_prefix_t *ippref = &gid_address_sd_dst_ippref (eid); + + if (IP4 == ip_prefix_version (ippref)) + gid_dict_foreach_ip4_subprefix (db, gid_address_vni (eid), + &gid_address_sd_src_ippref (eid), + &gid_address_sd_dst_ippref (eid), cb, + arg); + else + gid_dict_foreach_ip6_subprefix (db, gid_address_vni (eid), + &gid_address_sd_src_ippref (eid), + &gid_address_sd_dst_ippref (eid), cb, + arg); +} + +static void +make_mac_sd_key (BVT (clib_bihash_kv) * kv, u32 vni, u8 src_mac[6], + u8 dst_mac[6]) +{ + kv->key[0] = (u64) vni; + kv->key[1] = mac_to_u64 (dst_mac); + kv->key[2] = src_mac ? mac_to_u64 (src_mac) : (u64) 0; +} + +static u32 +mac_sd_lookup (gid_mac_table_t * db, u32 vni, u8 * dst, u8 * src) +{ + int rv; + BVT (clib_bihash_kv) kv, value; + + make_mac_sd_key (&kv, vni, src, dst); + rv = BV (clib_bihash_search_inline_2) (&db->mac_lookup_table, &kv, &value); + + /* no match, try with src 0, catch all for dst */ + if (rv != 0) + { + kv.key[2] = 0; + rv = BV (clib_bihash_search_inline_2) (&db->mac_lookup_table, &kv, + &value); + if (rv == 0) + return value.value; + } + else + return value.value; + + return GID_LOOKUP_MISS; +} + +static u32 +ip4_lookup_exact_match (gid_ip4_table_t * db, u32 vni, ip_prefix_t * key) +{ + int rv; + BVT (clib_bihash_kv) kv, value; + + ip4_address_t *mask; + + mask = &db->ip4_fib_masks[ip_prefix_len (key)]; + + 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 +ip4_lookup (gid_ip4_table_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_exact_match (gid_ip6_table_t * db, u32 vni, ip_prefix_t * key) +{ + int rv; + BVT (clib_bihash_kv) kv, value; + + ip6_address_t *mask; + mask = &db->ip6_fib_masks[ip_prefix_len (key)]; + + 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 +ip6_lookup (gid_ip6_table_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_sd_lookup (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst, + ip_prefix_t * src) +{ + u32 sfi; + gid_ip4_table_t *sfib4; + gid_ip6_table_t *sfib6; + + switch (ip_prefix_version (dst)) + { + case IP4: + sfi = ip4_lookup (&db->dst_ip4_table, vni, dst); + if (GID_LOOKUP_MISS != sfi) + sfib4 = pool_elt_at_index (db->src_ip4_table_pool, sfi); + else + return GID_LOOKUP_MISS; + + if (!src) + { + ip_prefix_t sp; + memset (&sp, 0, sizeof (sp)); + return ip4_lookup_exact_match (sfib4, 0, &sp); + } + else + return ip4_lookup (sfib4, 0, src); + + break; + case IP6: + sfi = ip6_lookup (&db->dst_ip6_table, vni, dst); + if (GID_LOOKUP_MISS != sfi) + sfib6 = pool_elt_at_index (db->src_ip6_table_pool, sfi); + else + return GID_LOOKUP_MISS; + + if (!src) + { + ip_prefix_t sp; + memset (&sp, 0, sizeof (sp)); + ip_prefix_version (&sp) = IP6; + return ip6_lookup_exact_match (sfib6, 0, &sp); + } + else + return ip6_lookup (sfib6, 0, src); + + break; + default: + clib_warning ("address type %d not supported!", + ip_prefix_version (dst)); + break; + } + return GID_LOOKUP_MISS; +} + +u32 +gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) +{ + switch (gid_address_type (key)) + { + case GID_ADDR_IP_PREFIX: + return ip_sd_lookup (db, gid_address_vni (key), + &gid_address_ippref (key), 0); + case GID_ADDR_MAC: + return mac_sd_lookup (&db->sd_mac_table, gid_address_vni (key), + gid_address_mac (key), 0); + case GID_ADDR_SRC_DST: + switch (gid_address_sd_dst_type (key)) + { + case FID_ADDR_IP_PREF: + return ip_sd_lookup (db, gid_address_vni (key), + &gid_address_sd_dst_ippref (key), + &gid_address_sd_src_ippref (key)); + break; + case FID_ADDR_MAC: + return mac_sd_lookup (&db->sd_mac_table, gid_address_vni (key), + gid_address_sd_dst_mac (key), + gid_address_sd_src_mac (key)); + break; + default: + clib_warning ("Source/Dest address type %d not supported!", + gid_address_sd_dst_type (key)); + break; + } + break; + default: + clib_warning ("address type %d not supported!", gid_address_type (key)); + break; + } + return GID_LOOKUP_MISS; +} + +u32 +gid_dictionary_sd_lookup (gid_dictionary_t * db, gid_address_t * dst, + gid_address_t * src) +{ + switch (gid_address_type (dst)) + { + case GID_ADDR_IP_PREFIX: + return ip_sd_lookup (db, gid_address_vni (dst), + &gid_address_ippref (dst), + &gid_address_ippref (src)); + case GID_ADDR_MAC: + return mac_sd_lookup (&db->sd_mac_table, gid_address_vni (dst), + gid_address_mac (dst), gid_address_mac (src)); + case GID_ADDR_SRC_DST: + switch (gid_address_sd_dst_type (dst)) + { + case FID_ADDR_IP_PREF: + return ip_sd_lookup (db, gid_address_vni (dst), + &gid_address_sd_dst_ippref (dst), + &gid_address_sd_src_ippref (dst)); + break; + case FID_ADDR_MAC: + return mac_sd_lookup (&db->sd_mac_table, gid_address_vni (dst), + gid_address_sd_dst_mac (dst), + gid_address_sd_src_mac (dst)); + break; + default: + clib_warning ("Source/Dest address type %d not supported!", + gid_address_sd_dst_type (dst)); + break; + } + break; + default: + clib_warning ("address type %d not supported!", gid_address_type (dst)); + break; + } + return GID_LOOKUP_MISS; +} + +static void +ip4_compute_prefix_lengths_in_search_order (gid_ip4_table_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 */ + + /* *INDENT-OFF* */ + 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); + })); + /* *INDENT-ON* */ + +} + +static u32 +add_del_ip4_key (gid_ip4_table_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); + + clib_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 +ip4_lookup_init (gid_ip4_table_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 u32 +add_del_sd_ip4_key (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst_pref, + ip_prefix_t * src_pref, u32 val, u8 is_add) +{ + u32 sfi, old_val = ~0; + gid_ip4_table_t *sfib; + + sfi = ip4_lookup_exact_match (&db->dst_ip4_table, vni, dst_pref); + + if (is_add) + { + if (GID_LOOKUP_MISS == sfi) + { + pool_get (db->src_ip4_table_pool, sfib); + ip4_lookup_init (sfib); + add_del_ip4_key (&db->dst_ip4_table, vni, dst_pref, + sfib - db->src_ip4_table_pool, is_add); + if (src_pref) + add_del_ip4_key (sfib, 0 /* vni */ , src_pref, val, is_add); + else + { + ip_prefix_t sp; + memset (&sp, 0, sizeof (sp)); + add_del_ip4_key (sfib, 0 /* vni */ , &sp, val, is_add); + } + } + else + { + ASSERT (!pool_is_free_index (db->src_ip4_table_pool, sfi)); + sfib = pool_elt_at_index (db->src_ip4_table_pool, sfi); + if (src_pref) + { + old_val = ip4_lookup_exact_match (sfib, 0, src_pref); + add_del_ip4_key (sfib, 0 /* vni */ , src_pref, val, is_add); + } + else + { + ip_prefix_t sp; + memset (&sp, 0, sizeof (sp)); + old_val = + add_del_ip4_key (sfib, 0 /* vni */ , &sp, val, is_add); + } + } + } + else + { + if (GID_LOOKUP_MISS != sfi) + { + add_del_ip4_key (&db->dst_ip4_table, vni, dst_pref, 0, is_add); + sfib = pool_elt_at_index (db->src_ip4_table_pool, sfi); + if (src_pref) + old_val = add_del_ip4_key (sfib, 0, src_pref, 0, is_add); + else + { + ip_prefix_t sp; + memset (&sp, 0, sizeof (sp)); + old_val = add_del_ip4_key (sfib, 0, &sp, 0, is_add); + } + } + else + clib_warning ("cannot delete dst mapping %U!", format_ip_prefix, + dst_pref); + } + return old_val; +} + +static void +ip6_compute_prefix_lengths_in_search_order (gid_ip6_table_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 */ + + /* *INDENT-OFF* */ + 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); + })); + /* *INDENT-ON* */ +} + +static u32 +add_del_ip6_key (gid_ip6_table_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); + + clib_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 +add_del_mac (gid_mac_table_t * db, u32 vni, u8 * dst_mac, u8 * src_mac, + u32 val, u8 is_add) +{ + BVT (clib_bihash_kv) kv, value; + u32 old_val = ~0; + + make_mac_sd_key (&kv, vni, src_mac, dst_mac); + + if (BV (clib_bihash_search) (&db->mac_lookup_table, &kv, &value) == 0) + old_val = value.value; + + if (!is_add) + BV (clib_bihash_add_del) (&db->mac_lookup_table, &kv, 0 /* is_add */ ); + else + { + kv.value = val; + BV (clib_bihash_add_del) (&db->mac_lookup_table, &kv, 1 /* is_add */ ); + } + return old_val; +} + +static void +ip6_lookup_init (gid_ip6_table_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); +} + +static u32 +add_del_sd_ip6_key (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst_pref, + ip_prefix_t * src_pref, u32 val, u8 is_add) +{ + u32 sfi, old_val = ~0; + gid_ip6_table_t *sfib; + + sfi = ip6_lookup_exact_match (&db->dst_ip6_table, vni, dst_pref); + + if (is_add) + { + if (GID_LOOKUP_MISS == sfi) + { + pool_get (db->src_ip6_table_pool, sfib); + ip6_lookup_init (sfib); + add_del_ip6_key (&db->dst_ip6_table, vni, dst_pref, + sfib - db->src_ip6_table_pool, is_add); + if (src_pref) + add_del_ip6_key (sfib, 0 /* vni */ , src_pref, val, is_add); + else + { + ip_prefix_t sp; + memset (&sp, 0, sizeof (sp)); + ip_prefix_version (&sp) = IP6; + add_del_ip6_key (sfib, 0 /* vni */ , &sp, val, is_add); + } + } + else + { + ASSERT (!pool_is_free_index (db->src_ip6_table_pool, sfi)); + sfib = pool_elt_at_index (db->src_ip6_table_pool, sfi); + if (src_pref) + { + old_val = ip6_lookup_exact_match (sfib, 0, src_pref); + add_del_ip6_key (sfib, 0 /* vni */ , src_pref, val, is_add); + } + else + { + ip_prefix_t sp; + memset (&sp, 0, sizeof (sp)); + ip_prefix_version (&sp) = IP6; + old_val = + add_del_ip6_key (sfib, 0 /* vni */ , &sp, val, is_add); + } + } + } + else + { + if (GID_LOOKUP_MISS != sfi) + { + add_del_ip6_key (&db->dst_ip6_table, vni, dst_pref, 0, is_add); + sfib = pool_elt_at_index (db->src_ip6_table_pool, sfi); + if (src_pref) + old_val = add_del_ip6_key (sfib, 0, src_pref, 0, is_add); + else + { + ip_prefix_t sp; + memset (&sp, 0, sizeof (sp)); + ip_prefix_version (&sp) = IP6; + old_val = add_del_ip6_key (sfib, 0, &sp, 0, is_add); + } + } + else + clib_warning ("cannot delete dst mapping %U!", format_ip_prefix, + dst_pref); + } + return old_val; +} + +static u32 +add_del_ip (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst_key, + ip_prefix_t * src_key, u32 value, u8 is_add) +{ + switch (ip_prefix_version (dst_key)) + { + case IP4: + return add_del_sd_ip4_key (db, vni, dst_key, src_key, value, is_add); + break; + case IP6: + return add_del_sd_ip6_key (db, vni, dst_key, src_key, value, is_add); + break; + default: + clib_warning ("address type %d not supported!", + ip_prefix_version (dst_key)); + break; + } + return ~0; +} + +static u32 +add_del_sd (gid_dictionary_t * db, u32 vni, source_dest_t * key, u32 value, + u8 is_add) +{ + switch (sd_dst_type (key)) + { + case FID_ADDR_IP_PREF: + add_del_ip (db, vni, &sd_dst_ippref (key), &sd_src_ippref (key), + value, is_add); + + case FID_ADDR_MAC: + return add_del_mac (&db->sd_mac_table, vni, sd_dst_mac (key), + sd_src_mac (key), value, is_add); + + default: + clib_warning ("SD address type %d not supprted!", sd_dst_type (key)); + break; + } + + return ~0; +} + +u32 +gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u32 value, + u8 is_add) +{ + switch (gid_address_type (key)) + { + case GID_ADDR_IP_PREFIX: + return add_del_ip (db, gid_address_vni (key), &gid_address_ippref (key), + 0, value, is_add); + case GID_ADDR_MAC: + return add_del_mac (&db->sd_mac_table, gid_address_vni (key), + gid_address_mac (key), 0, value, is_add); + case GID_ADDR_SRC_DST: + return add_del_sd (db, gid_address_vni (key), &gid_address_sd (key), + value, is_add); + default: + clib_warning ("address type %d not supported!", gid_address_type (key)); + break; + } + return ~0; +} + +static void +mac_lookup_init (gid_mac_table_t * db) +{ + if (db->mac_lookup_table_nbuckets == 0) + db->mac_lookup_table_nbuckets = MAC_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; + + db->mac_lookup_table_nbuckets = + 1 << max_log2 (db->mac_lookup_table_nbuckets); + + if (db->mac_lookup_table_size == 0) + db->mac_lookup_table_size = MAC_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; + + BV (clib_bihash_init) (&db->mac_lookup_table, "mac lookup table", + db->mac_lookup_table_nbuckets, + db->mac_lookup_table_size); +} + +void +gid_dictionary_init (gid_dictionary_t * db) +{ + ip4_lookup_init (&db->dst_ip4_table); + ip6_lookup_init (&db->dst_ip6_table); + mac_lookup_init (&db->sd_mac_table); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From f3fe820fd840173df2571a49c929a7f193b68508 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Wed, 15 Feb 2017 13:27:08 +0100 Subject: LISP: fix deleting src/dst entry from GID dictionary Change-Id: Ic674cc953b45ddd4811e07821e1a0af28b5f6214 Signed-off-by: Filip Tehlar --- src/vnet/lisp-cp/gid_dictionary.c | 26 +++++++++++++++++++++----- src/vnet/lisp-cp/gid_dictionary.h | 3 +++ 2 files changed, 24 insertions(+), 5 deletions(-) (limited to 'src/vnet/lisp-cp/gid_dictionary.c') diff --git a/src/vnet/lisp-cp/gid_dictionary.c b/src/vnet/lisp-cp/gid_dictionary.c index d238124e..b01bb0e0 100644 --- a/src/vnet/lisp-cp/gid_dictionary.c +++ b/src/vnet/lisp-cp/gid_dictionary.c @@ -464,11 +464,15 @@ add_del_ip4_key (gid_ip4_table_t * db, u32 vni, ip_prefix_t * pref, u32 val, old_val = value.value; if (!is_add) - BV (clib_bihash_add_del) (&db->ip4_lookup_table, &kv, 0 /* is_add */ ); + { + BV (clib_bihash_add_del) (&db->ip4_lookup_table, &kv, 0 /* is_add */ ); + db->count--; + } else { kv.value = val; BV (clib_bihash_add_del) (&db->ip4_lookup_table, &kv, 1 /* is_add */ ); + db->count++; } return old_val; } @@ -553,7 +557,6 @@ add_del_sd_ip4_key (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst_pref, { if (GID_LOOKUP_MISS != sfi) { - add_del_ip4_key (&db->dst_ip4_table, vni, dst_pref, 0, is_add); sfib = pool_elt_at_index (db->src_ip4_table_pool, sfi); if (src_pref) old_val = add_del_ip4_key (sfib, 0, src_pref, 0, is_add); @@ -563,6 +566,9 @@ add_del_sd_ip4_key (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst_pref, memset (&sp, 0, sizeof (sp)); old_val = add_del_ip4_key (sfib, 0, &sp, 0, is_add); } + + if (sfib->count == 0) + add_del_ip4_key (&db->dst_ip4_table, vni, dst_pref, 0, is_add); } else clib_warning ("cannot delete dst mapping %U!", format_ip_prefix, @@ -630,11 +636,15 @@ add_del_ip6_key (gid_ip6_table_t * db, u32 vni, ip_prefix_t * pref, u32 val, old_val = value.value; if (!is_add) - BV (clib_bihash_add_del) (&db->ip6_lookup_table, &kv, 0 /* is_add */ ); + { + BV (clib_bihash_add_del) (&db->ip6_lookup_table, &kv, 0 /* is_add */ ); + db->count--; + } else { kv.value = val; BV (clib_bihash_add_del) (&db->ip6_lookup_table, &kv, 1 /* is_add */ ); + db->count++; } return old_val; } @@ -652,11 +662,15 @@ add_del_mac (gid_mac_table_t * db, u32 vni, u8 * dst_mac, u8 * src_mac, old_val = value.value; if (!is_add) - BV (clib_bihash_add_del) (&db->mac_lookup_table, &kv, 0 /* is_add */ ); + { + BV (clib_bihash_add_del) (&db->mac_lookup_table, &kv, 0 /* is_add */ ); + db->count--; + } else { kv.value = val; BV (clib_bihash_add_del) (&db->mac_lookup_table, &kv, 1 /* is_add */ ); + db->count++; } return old_val; } @@ -748,7 +762,6 @@ add_del_sd_ip6_key (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst_pref, { if (GID_LOOKUP_MISS != sfi) { - add_del_ip6_key (&db->dst_ip6_table, vni, dst_pref, 0, is_add); sfib = pool_elt_at_index (db->src_ip6_table_pool, sfi); if (src_pref) old_val = add_del_ip6_key (sfib, 0, src_pref, 0, is_add); @@ -759,6 +772,9 @@ add_del_sd_ip6_key (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst_pref, ip_prefix_version (&sp) = IP6; old_val = add_del_ip6_key (sfib, 0, &sp, 0, is_add); } + + if (sfib->count == 0) + add_del_ip6_key (&db->dst_ip6_table, vni, dst_pref, 0, is_add); } else clib_warning ("cannot delete dst mapping %U!", format_ip_prefix, diff --git a/src/vnet/lisp-cp/gid_dictionary.h b/src/vnet/lisp-cp/gid_dictionary.h index c5aaf8cb..825e9856 100644 --- a/src/vnet/lisp-cp/gid_dictionary.h +++ b/src/vnet/lisp-cp/gid_dictionary.h @@ -50,6 +50,7 @@ typedef struct /* ip4 lookup table config parameters */ u32 ip4_lookup_table_nbuckets; uword ip4_lookup_table_size; + u32 count; } gid_ip4_table_t; typedef struct @@ -65,6 +66,7 @@ typedef struct /* ip6 lookup table config parameters */ u32 ip6_lookup_table_nbuckets; uword ip6_lookup_table_size; + u64 count; } gid_ip6_table_t; typedef struct gid_mac_table @@ -74,6 +76,7 @@ typedef struct gid_mac_table /* mac lookup table config parameters */ u32 mac_lookup_table_nbuckets; uword mac_lookup_table_size; + u64 count; } gid_mac_table_t; typedef struct -- cgit 1.2.3-korg From d5a65db98d66c66b03b057ac568be05f2456f73c Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Wed, 17 May 2017 17:21:10 +0200 Subject: LISP: L2 ARP handling Change-Id: I1ec328cda73f7eaf7867cd8a2a17852ee0cd23f1 Signed-off-by: Filip Tehlar --- src/vat/api_format.c | 233 ++++++++++++++++++++++++++++++++++++++ src/vnet/lisp-cp/control.c | 232 ++++++++++++++++++++++++++++++++----- src/vnet/lisp-cp/control.h | 15 +++ src/vnet/lisp-cp/gid_dictionary.c | 91 ++++++++++++++- src/vnet/lisp-cp/gid_dictionary.h | 25 +++- src/vnet/lisp-cp/lisp_types.c | 3 + src/vnet/lisp-cp/lisp_types.h | 15 +++ src/vnet/lisp-cp/one.api | 73 ++++++++++++ src/vnet/lisp-cp/one_api.c | 82 ++++++++++++++ src/vnet/lisp-cp/one_cli.c | 100 ++++++++++++++++ 10 files changed, 833 insertions(+), 36 deletions(-) (limited to 'src/vnet/lisp-cp/gid_dictionary.c') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index f3e6f64c..3eff8ef0 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -3163,6 +3163,123 @@ end: vam->result_ready = 1; } +static void + vl_api_one_l2_arp_entries_get_reply_t_handler + (vl_api_one_l2_arp_entries_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + print (vam->ofp, "%U -> %U", format_ip4_address, &mp->entries[i].ip4, + format_ethernet_address, mp->entries[i].mac); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_l2_arp_entries_get_reply_t_handler_json + (vl_api_one_l2_arp_entries_get_reply_t * mp) +{ + u8 *s = 0; + vat_main_t *vam = &vat_main; + vat_json_node_t *e = 0, root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + vl_api_one_l2_arp_entry_t *arp_entry; + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + e = vat_json_array_add (&root); + arp_entry = &mp->entries[i]; + + vat_json_init_object (e); + s = format (0, "%U", format_ethernet_address, arp_entry->mac); + vec_add1 (s, 0); + + vat_json_object_add_string_copy (e, "mac", s); + vec_free (s); + + s = format (0, "%U", format_ip4_address, &arp_entry->ip4); + vec_add1 (s, 0); + vat_json_object_add_string_copy (e, "ip4", s); + vec_free (s); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_l2_arp_bd_get_reply_t_handler + (vl_api_one_l2_arp_bd_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + { + print (vam->ofp, "%d", clib_net_to_host_u32 (mp->bridge_domains[i])); + } + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_l2_arp_bd_get_reply_t_handler_json + (vl_api_one_l2_arp_bd_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + vat_json_array_add_uint (&root, + clib_net_to_host_u32 (mp->bridge_domains[i])); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + static void vl_api_one_adjacencies_get_reply_t_handler (vl_api_one_adjacencies_get_reply_t * mp) @@ -4158,6 +4275,10 @@ static void vl_api_flow_classify_details_t_handler_json #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler #define vl_api_one_adjacencies_get_reply_t_endian vl_noop_handler #define vl_api_one_adjacencies_get_reply_t_print vl_noop_handler +#define vl_api_one_l2_arp_bd_get_reply_t_print vl_noop_handler +#define vl_api_one_l2_arp_entries_get_reply_t_endian vl_noop_handler +#define vl_api_one_l2_arp_entries_get_reply_t_print vl_noop_handler +#define vl_api_one_l2_arp_bd_get_reply_t_endian vl_noop_handler /* * Generate boilerplate reply handlers, which @@ -4267,6 +4388,7 @@ _(one_add_del_map_request_itr_rlocs_reply) \ _(one_eid_table_add_del_map_reply) \ _(one_use_petr_reply) \ _(one_stats_enable_disable_reply) \ +_(one_add_del_l2_arp_entry_reply) \ _(one_stats_flush_reply) \ _(gpe_add_del_fwd_entry_reply) \ _(gpe_enable_disable_reply) \ @@ -4499,6 +4621,9 @@ _(ONE_STATS_FLUSH_REPLY, one_stats_flush_reply) \ _(ONE_STATS_ENABLE_DISABLE_REPLY, one_stats_enable_disable_reply) \ _(SHOW_ONE_STATS_ENABLE_DISABLE_REPLY, \ show_one_stats_enable_disable_reply) \ +_(ONE_ADD_DEL_L2_ARP_ENTRY_REPLY, one_add_del_l2_arp_entry_reply) \ +_(ONE_L2_ARP_BD_GET_REPLY, one_l2_arp_bd_get_reply) \ +_(ONE_L2_ARP_ENTRIES_GET_REPLY, one_l2_arp_entries_get_reply) \ _(GPE_SET_ENCAP_MODE_REPLY, gpe_set_encap_mode_reply) \ _(GPE_GET_ENCAP_MODE_REPLY, gpe_get_encap_mode_reply) \ _(GPE_ADD_DEL_IFACE_REPLY, gpe_add_del_iface_reply) \ @@ -14736,6 +14861,111 @@ api_show_one_rloc_probe_state (vat_main_t * vam) #define api_show_lisp_rloc_probe_state api_show_one_rloc_probe_state +static int +api_one_add_del_l2_arp_entry (vat_main_t * vam) +{ + vl_api_one_add_del_l2_arp_entry_t *mp; + unformat_input_t *input = vam->input; + u8 is_add = 1; + u8 mac_set = 0; + u8 bd_set = 0; + u8 ip_set = 0; + u8 mac[6] = { 0, }; + u32 ip4 = 0, bd = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "mac %U", unformat_ethernet_address, mac)) + mac_set = 1; + else if (unformat (input, "ip %U", unformat_ip4_address, &ip4)) + ip_set = 1; + else if (unformat (input, "bd %d", &bd)) + bd_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!bd_set || !ip_set || (!mac_set && is_add)) + { + errmsg ("Missing BD, IP or MAC!"); + return -99; + } + + M (ONE_ADD_DEL_L2_ARP_ENTRY, mp); + mp->is_add = is_add; + clib_memcpy (mp->mac, mac, 6); + mp->bd = clib_host_to_net_u32 (bd); + mp->ip4 = ip4; + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + +static int +api_one_l2_arp_bd_get (vat_main_t * vam) +{ + vl_api_one_l2_arp_bd_get_t *mp; + int ret; + + M (ONE_L2_ARP_BD_GET, mp); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + +static int +api_one_l2_arp_entries_get (vat_main_t * vam) +{ + vl_api_one_l2_arp_entries_get_t *mp; + unformat_input_t *input = vam->input; + u8 bd_set = 0; + u32 bd = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "bd %d", &bd)) + bd_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!bd_set) + { + errmsg ("Expected bridge domain!"); + return -99; + } + + M (ONE_L2_ARP_ENTRIES_GET, mp); + mp->bd = clib_host_to_net_u32 (bd); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_one_stats_enable_disable (vat_main_t * vam) { @@ -19052,6 +19282,9 @@ _(one_locator_set_dump, "[local | remote]") \ _(one_locator_dump, "ls_index | ls_name ") \ _(one_eid_table_dump, "[eid / | ] [vni] " \ "[local] | [remote]") \ +_(one_add_del_l2_arp_entry, "[del] mac bd ip4 ") \ +_(one_l2_arp_bd_get, "") \ +_(one_l2_arp_entries_get, "bd ") \ _(one_stats_enable_disable, "enable|disalbe") \ _(show_one_stats_enable_disable, "") \ _(one_eid_table_vni_dump, "") \ diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 439802c9..cea92556 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -821,6 +823,99 @@ vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a, return vnet_lisp_map_cache_add_del (a, map_index_result); } +static void +add_l2_arp_bd (BVT (clib_bihash_kv) * kvp, void *arg) +{ + u32 **ht = arg; + u32 bd = (u32) kvp->key[0]; + hash_set (ht[0], bd, 0); +} + +u32 * +vnet_lisp_l2_arp_bds_get (void) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + u32 *bds = 0; + + gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_bd, &bds); + return bds; +} + +typedef struct +{ + void *vector; + u32 bd; +} lisp_add_l2_arp_args_t; + +static void +add_l2_arp_entry (BVT (clib_bihash_kv) * kvp, void *arg) +{ + lisp_add_l2_arp_args_t *a = arg; + lisp_api_l2_arp_entry_t **vector = a->vector, e; + + if ((u32) kvp->key[0] == a->bd) + { + mac_copy (e.mac, (void *) &kvp->value); + e.ip4 = (u32) kvp->key[1]; + vec_add1 (vector[0], e); + } +} + +lisp_api_l2_arp_entry_t * +vnet_lisp_l2_arp_entries_get_by_bd (u32 bd) +{ + lisp_api_l2_arp_entry_t *entries = 0; + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + lisp_add_l2_arp_args_t a; + + a.vector = &entries; + a.bd = bd; + + gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_entry, &a); + return entries; +} + +int +vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add) +{ + if (vnet_lisp_enable_disable_status () == 0) + { + clib_warning ("LISP is disabled!"); + return VNET_API_ERROR_LISP_DISABLED; + } + + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + int rc = 0; + + u64 res = gid_dictionary_lookup (&lcm->mapping_index_by_gid, key); + if (is_add) + { + if (res != GID_LOOKUP_MISS_L2) + { + clib_warning ("Entry %U exists in DB!", format_gid_address, key); + return VNET_API_ERROR_ENTRY_ALREADY_EXISTS; + } + u64 val = mac_to_u64 (mac); + gid_dictionary_add_del (&lcm->mapping_index_by_gid, key, val, + 1 /* is_add */ ); + } + else + { + if (res == GID_LOOKUP_MISS_L2) + { + clib_warning ("ONE ARP entry %U not found - cannot delete!", + format_gid_address, key); + return -1; + } + gid_dictionary_add_del (&lcm->mapping_index_by_gid, key, 0, + 0 /* is_add */ ); + } + + return rc; +} + int vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add) { @@ -830,7 +925,7 @@ vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add) if (vnet_lisp_enable_disable_status () == 0) { clib_warning ("LISP is disabled!"); - return -1; + return VNET_API_ERROR_LISP_DISABLED; } dp_table_by_vni = is_l2 ? &lcm->bd_id_by_vni : &lcm->table_id_by_vni; @@ -1931,7 +2026,8 @@ vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a) /* Statistics (not really errors) */ #define foreach_lisp_cp_lookup_error \ _(DROP, "drop") \ -_(MAP_REQUESTS_SENT, "map-request sent") +_(MAP_REQUESTS_SENT, "map-request sent") \ +_(ARP_REPLY_TX, "ARP replies sent") static char *lisp_cp_lookup_error_strings[] = { #define _(sym,string) string, @@ -1950,6 +2046,7 @@ typedef enum typedef enum { LISP_CP_LOOKUP_NEXT_DROP, + LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX, LISP_CP_LOOKUP_N_NEXT, } lisp_cp_lookup_next_t; @@ -2710,10 +2807,8 @@ lisp_get_vni_from_buffer_ip (lisp_cp_main_t * lcm, vlib_buffer_t * b, } always_inline u32 -lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b) +lisp_get_bd_from_buffer_eth (vlib_buffer_t * b) { - uword *vnip; - u32 vni = ~0; u32 sw_if_index0; l2input_main_t *l2im = &l2input_main; @@ -2724,12 +2819,21 @@ lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b) config = vec_elt_at_index (l2im->configs, sw_if_index0); bd_config = vec_elt_at_index (l2im->bd_configs, config->bd_index); - vnip = hash_get (lcm->vni_by_bd_id, bd_config->bd_id); + return bd_config->bd_id; +} + +always_inline u32 +lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b) +{ + uword *vnip; + u32 vni = ~0; + u32 bd = lisp_get_bd_from_buffer_eth (b); + + vnip = hash_get (lcm->vni_by_bd_id, bd); if (vnip) vni = vnip[0]; else - clib_warning ("bridge domain %d is not mapped to any vni!", - config->bd_index); + clib_warning ("bridge domain %d is not mapped to any vni!", bd); return vni; } @@ -2744,6 +2848,9 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, memset (src, 0, sizeof (*src)); memset (dst, 0, sizeof (*dst)); + gid_address_type (dst) = GID_ADDR_NO_ADDRESS; + gid_address_type (src) = GID_ADDR_NO_ADDRESS; + if (LISP_AFI_IP == type || LISP_AFI_IP6 == type) { ip4_header_t *ip; @@ -2767,19 +2874,35 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, else if (LISP_AFI_MAC == type) { ethernet_header_t *eh; + ethernet_arp_header_t *ah; eh = vlib_buffer_get_current (b); - gid_address_type (src) = GID_ADDR_MAC; - gid_address_type (dst) = GID_ADDR_MAC; - mac_copy (&gid_address_mac (src), eh->src_address); - mac_copy (&gid_address_mac (dst), eh->dst_address); + if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_ARP) + { + ah = (ethernet_arp_header_t *) (((u8 *) eh) + sizeof (*eh)); + if (clib_net_to_host_u16 (ah->opcode) + != ETHERNET_ARP_OPCODE_request) + return; + + gid_address_type (dst) = GID_ADDR_ARP; + gid_address_arp_bd (dst) = lisp_get_bd_from_buffer_eth (b); + clib_memcpy (&gid_address_arp_ip4 (dst), + &ah->ip4_over_ethernet[1].ip4, 4); + } + else + { + gid_address_type (src) = GID_ADDR_MAC; + gid_address_type (dst) = GID_ADDR_MAC; + mac_copy (&gid_address_mac (src), eh->src_address); + mac_copy (&gid_address_mac (dst), eh->dst_address); - /* get vni */ - vni = lisp_get_vni_from_buffer_eth (lcm, b); + /* get vni */ + vni = lisp_get_vni_from_buffer_eth (lcm, b); - gid_address_vni (dst) = vni; - gid_address_vni (src) = vni; + gid_address_vni (dst) = vni; + gid_address_vni (src) = vni; + } } else if (LISP_AFI_LCAF == type) { @@ -2793,38 +2916,81 @@ lisp_cp_lookup_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, int overlay) { - u32 *from, *to_next_drop, di, si; + u32 *from, *to_next, di, si; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); - u32 pkts_mapped = 0; - uword n_left_from, n_left_to_next_drop; + u32 pkts_mapped = 0, next_index; + uword n_left_from, n_left_to_next; + vnet_main_t *vnm = vnet_get_main (); 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) { - vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, - to_next_drop, n_left_to_next_drop); + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - while (n_left_from > 0 && n_left_to_next_drop > 0) + while (n_left_from > 0 && n_left_to_next > 0) { - u32 pi0; + u32 pi0, sw_if_index0, next0; + u64 mac0; vlib_buffer_t *b0; gid_address_t src, dst; + ethernet_arp_header_t *arp0; + ethernet_header_t *eth0; + vnet_hw_interface_t *hw_if0; pi0 = from[0]; from += 1; n_left_from -= 1; - to_next_drop[0] = pi0; - to_next_drop += 1; - n_left_to_next_drop -= 1; + to_next[0] = pi0; + to_next += 1; + n_left_to_next -= 1; b0 = vlib_get_buffer (vm, pi0); - b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; /* src/dst eid pair */ get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst, overlay); + if (gid_address_type (&dst) == GID_ADDR_ARP) + { + mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst); + if (GID_LOOKUP_MISS_L2 != mac0) + { + /* send ARP reply */ + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; + + hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); + + eth0 = vlib_buffer_get_current (b0); + arp0 = (ethernet_arp_header_t *) (((u8 *) eth0) + + sizeof (*eth0)); + arp0->opcode = + clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply); + arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0]; + clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, + (u8 *) & mac0, 6); + clib_memcpy (&arp0->ip4_over_ethernet[0].ip4, + &gid_address_arp_ip4 (&dst), 4); + + /* Hardware must be ethernet-like. */ + ASSERT (vec_len (hw_if0->hw_address) == 6); + + clib_memcpy (eth0->dst_address, eth0->src_address, 6); + clib_memcpy (eth0->src_address, hw_if0->hw_address, 6); + + b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX]; + next0 = LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX; + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, + n_left_to_next, pi0, + next0); + } + continue; + } + /* if we have remote mapping for destination already in map-chache add forwarding tunnel directly. If not send a map-request */ di = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid, &dst, @@ -2859,6 +3025,7 @@ lisp_cp_lookup_inline (vlib_main_t * vm, pkts_mapped++; } + b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0, @@ -2871,10 +3038,13 @@ lisp_cp_lookup_inline (vlib_main_t * vm, } gid_address_free (&dst); gid_address_free (&src); + next0 = LISP_CP_LOOKUP_NEXT_DROP; + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, + n_left_to_next, pi0, next0); } - vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, - n_left_to_next_drop); + vlib_put_next_frame (vm, node, next_index, n_left_to_next); } vlib_node_increment_counter (vm, node->node_index, LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT, @@ -2926,6 +3096,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -2945,6 +3116,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -2964,6 +3136,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -2983,6 +3156,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h index cb98eb09..feb8cfa4 100644 --- a/src/vnet/lisp-cp/control.h +++ b/src/vnet/lisp-cp/control.h @@ -87,6 +87,12 @@ typedef struct miss_packet_type_t type; } miss_packet_t; +typedef struct +{ + u8 mac[6]; + u32 ip4; +} lisp_api_l2_arp_entry_t; + typedef enum { MR_MODE_DST_ONLY = 0, @@ -112,6 +118,12 @@ typedef enum lisp_flags #undef _ } lisp_flags_e; +typedef struct +{ + ip_address_t addr; + u32 bd; +} lisp_l2_arp_key_t; + typedef struct { u32 flags; @@ -338,6 +350,9 @@ int vnet_lisp_rloc_probe_enable_disable (u8 is_enable); int vnet_lisp_map_register_enable_disable (u8 is_enable); u8 vnet_lisp_map_register_state_get (void); u8 vnet_lisp_rloc_probe_state_get (void); +int vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add); +u32 *vnet_lisp_l2_arp_bds_get (void); +lisp_api_l2_arp_entry_t *vnet_lisp_l2_arp_entries_get_by_bd (u32 bd); map_records_arg_t *parse_map_reply (vlib_buffer_t * b); diff --git a/src/vnet/lisp-cp/gid_dictionary.c b/src/vnet/lisp-cp/gid_dictionary.c index b01bb0e0..80d59faf 100644 --- a/src/vnet/lisp-cp/gid_dictionary.c +++ b/src/vnet/lisp-cp/gid_dictionary.c @@ -138,6 +138,15 @@ gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid, arg); } +void +gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb) + (BVT (clib_bihash_kv) * kvp, void *arg), + void *ht) +{ + gid_l2_arp_table_t *tab = &db->arp_table; + BV (clib_bihash_foreach_key_value_pair) (&tab->arp_lookup_table, cb, ht); +} + static void make_mac_sd_key (BVT (clib_bihash_kv) * kv, u32 vni, u8 src_mac[6], u8 dst_mac[6]) @@ -328,7 +337,30 @@ ip_sd_lookup (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst, return GID_LOOKUP_MISS; } -u32 +static void +make_arp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip4_address_t * addr) +{ + kv->key[0] = (u64) bd; + kv->key[1] = (u64) addr->as_u32; + kv->key[2] = (u64) 0; +} + +static u64 +arp_lookup (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key) +{ + int rv; + BVT (clib_bihash_kv) kv, value; + + make_arp_key (&kv, bd, key); + rv = BV (clib_bihash_search_inline_2) (&db->arp_lookup_table, &kv, &value); + + if (rv == 0) + return value.value; + + return GID_LOOKUP_MISS_L2; +} + +u64 gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) { switch (gid_address_type (key)) @@ -358,6 +390,9 @@ gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) break; } break; + case GID_ADDR_ARP: + return arp_lookup (&db->arp_table, gid_address_arp_bd (key), + &gid_address_arp_ip4 (key)); default: clib_warning ("address type %d not supported!", gid_address_type (key)); break; @@ -825,21 +860,49 @@ add_del_sd (gid_dictionary_t * db, u32 vni, source_dest_t * key, u32 value, return ~0; } +static u32 +add_del_arp (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key, u64 value, + u8 is_add) +{ + BVT (clib_bihash_kv) kv, result; + u32 old_val = ~0; + + make_arp_key (&kv, bd, key); + if (BV (clib_bihash_search) (&db->arp_lookup_table, &kv, &result) == 0) + old_val = result.value; + + if (is_add) + { + kv.value = value; + BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 1 /* is_add */ ); + db->count++; + } + else + { + BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 0 /* is_add */ ); + db->count--; + } + return old_val; +} + u32 -gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u32 value, +gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, u8 is_add) { switch (gid_address_type (key)) { case GID_ADDR_IP_PREFIX: return add_del_ip (db, gid_address_vni (key), &gid_address_ippref (key), - 0, value, is_add); + 0, (u32) value, is_add); case GID_ADDR_MAC: return add_del_mac (&db->sd_mac_table, gid_address_vni (key), - gid_address_mac (key), 0, value, is_add); + gid_address_mac (key), 0, (u32) value, is_add); case GID_ADDR_SRC_DST: return add_del_sd (db, gid_address_vni (key), &gid_address_sd (key), - value, is_add); + (u32) value, is_add); + case GID_ADDR_ARP: + return add_del_arp (&db->arp_table, gid_address_arp_bd (key), + &gid_address_arp_ip4 (key), value, is_add); default: clib_warning ("address type %d not supported!", gid_address_type (key)); break; @@ -864,12 +927,30 @@ mac_lookup_init (gid_mac_table_t * db) db->mac_lookup_table_size); } +static void +arp_lookup_init (gid_l2_arp_table_t * db) +{ + if (db->arp_lookup_table_nbuckets == 0) + db->arp_lookup_table_nbuckets = ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; + + db->arp_lookup_table_nbuckets = + 1 << max_log2 (db->arp_lookup_table_nbuckets); + + if (db->arp_lookup_table_size == 0) + db->arp_lookup_table_size = ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; + + BV (clib_bihash_init) (&db->arp_lookup_table, "arp lookup table", + db->arp_lookup_table_nbuckets, + db->arp_lookup_table_size); +} + void gid_dictionary_init (gid_dictionary_t * db) { ip4_lookup_init (&db->dst_ip4_table); ip6_lookup_init (&db->dst_ip6_table); mac_lookup_init (&db->sd_mac_table); + arp_lookup_init (&db->arp_table); } /* diff --git a/src/vnet/lisp-cp/gid_dictionary.h b/src/vnet/lisp-cp/gid_dictionary.h index 825e9856..9612fb13 100644 --- a/src/vnet/lisp-cp/gid_dictionary.h +++ b/src/vnet/lisp-cp/gid_dictionary.h @@ -22,6 +22,7 @@ #include #define GID_LOOKUP_MISS ((u32)~0) +#define GID_LOOKUP_MISS_L2 ((u64)~0) /* Default size of the ip4 hash table */ #define IP4_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) @@ -35,6 +36,10 @@ #define MAC_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) #define MAC_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) +/* Default size of the ARP hash table */ +#define ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) + typedef void (*foreach_subprefix_match_cb_t) (u32, void *); typedef struct @@ -81,6 +86,17 @@ typedef struct gid_mac_table typedef struct { + BVT (clib_bihash) arp_lookup_table; + u32 arp_lookup_table_nbuckets; + uword arp_lookup_table_size; + u64 count; +} gid_l2_arp_table_t; + +typedef struct +{ + /** L2 ARP table */ + gid_l2_arp_table_t arp_table; + /** destination IP LPM ip4 lookup table */ gid_ip4_table_t dst_ip4_table; @@ -99,10 +115,10 @@ typedef struct } gid_dictionary_t; u32 -gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u32 value, +gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, u8 is_add); -u32 gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key); +u64 gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key); u32 gid_dictionary_sd_lookup (gid_dictionary_t * db, gid_address_t * dst, gid_address_t * src); @@ -112,6 +128,11 @@ void gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid, foreach_subprefix_match_cb_t cb, void *arg); +void +gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb) + (BVT (clib_bihash_kv) * kvp, void *arg), + void *ht); + #endif /* VNET_LISP_GPE_GID_DICTIONARY_H_ */ /* diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index 31a80081..85cefae0 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -256,6 +256,9 @@ format_gid_address (u8 * s, va_list * args) &gid_address_mac (a)); case GID_ADDR_NSH: return format (s, "%U", format_nsh_address, &gid_address_nsh (a)); + case GID_ADDR_ARP: + return format (s, "[%d, %U]", gid_address_arp_bd (a), + format_ip4_address, &gid_address_arp_ip4 (a)); default: clib_warning ("Can't format gid type %d", type); return 0; diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index a65a479e..f5d2a676 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -90,6 +90,7 @@ typedef enum GID_ADDR_MAC, GID_ADDR_SRC_DST, GID_ADDR_NSH, + GID_ADDR_ARP, GID_ADDR_NO_ADDRESS, GID_ADDR_TYPES } gid_address_type_t; @@ -165,12 +166,22 @@ typedef struct u8 si; } nsh_t; +typedef struct +{ + ip4_address_t addr; + u32 bd; +} lcaf_arp_t; + +#define lcaf_arp_ip4(_a) (_a)->addr +#define lcaf_arp_bd(_a) (_a)->bd + typedef struct { /* the union needs to be at the beginning! */ union { source_dest_t sd; + lcaf_arp_t arp; vni_t uni; }; u8 type; @@ -189,6 +200,7 @@ typedef struct _gid_address_t lcaf_t lcaf; u8 mac[6]; source_dest_t sd; + lcaf_arp_t arp; nsh_t nsh; }; u8 type; @@ -257,6 +269,9 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); #define gid_address_sd_dst(_a) sd_dst(&gid_address_sd(_a)) #define gid_address_sd_src_type(_a) sd_src_type(&gid_address_sd(_a)) #define gid_address_sd_dst_type(_a) sd_dst_type(&gid_address_sd(_a)) +#define gid_address_arp(_a) (_a)->arp +#define gid_address_arp_ip4(_a) lcaf_arp_ip4(&gid_address_arp (_a)) +#define gid_address_arp_bd(_a) lcaf_arp_bd(&gid_address_arp (_a)) /* 'sub'address functions */ #define foreach_gid_address_type_fcns \ diff --git a/src/vnet/lisp-cp/one.api b/src/vnet/lisp-cp/one.api index 2fa1edf6..7d07cc47 100644 --- a/src/vnet/lisp-cp/one.api +++ b/src/vnet/lisp-cp/one.api @@ -348,6 +348,79 @@ autoreply manual_print manual_endian define one_add_del_remote_mapping vl_api_one_remote_locator_t rlocs[rloc_num]; }; +/** \brief Add/delete L2 ARP entries + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add if non-zero; delete otherwise + @param bd - bridge domain + @param mac - MAC address + @param ip4 - IPv4 address +*/ +autoreply define one_add_del_l2_arp_entry +{ + u32 client_index; + u32 context; + u8 is_add; + u8 mac[6]; + u32 bd; + u32 ip4; +}; + +/** \brief Request for L2 ARP entries from specified bridge domain + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bd - bridge domain +*/ +define one_l2_arp_entries_get +{ + u32 client_index; + u32 context; + u32 bd; +}; + +typeonly manual_print manual_endian define one_l2_arp_entry +{ + u8 mac[6]; + u32 ip4; +}; + +/** \brief Reply with L2 ARP entries from specified bridge domain + @param context - sender context, to match reply w/ request + @param retval - error code + @param count - number of elements in the list + @param vl_api_one_arp_entry_t - list of entries +*/ +manual_print manual_endian define one_l2_arp_entries_get_reply +{ + u32 context; + i32 retval; + u32 count; + vl_api_one_l2_arp_entry_t entries[count]; +}; + +/** \brief Request for list of bridge domains used by L2 ARP table + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define one_l2_arp_bd_get +{ + u32 client_index; + u32 context; +}; + +/** \brief Reply with list of bridge domains used by L2 ARP table + @param context - sender context, to match reply w/ request + @param count - number of elements in the list + @param bridge_domains - list of BDs +*/ +manual_print manual_endian define one_l2_arp_bd_get_reply +{ + u32 context; + i32 retval; + u32 count; + u32 bridge_domains[count]; +}; + /** \brief add or delete ONE adjacency adjacency @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index 23549afa..724e58df 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -42,6 +42,11 @@ #define vl_api_one_add_del_remote_mapping_t_endian vl_noop_handler #define vl_api_one_add_del_remote_mapping_t_print vl_noop_handler +#define vl_api_one_l2_arp_entry_t_endian vl_noop_handler +#define vl_api_one_l2_arp_entry_t_print vl_noop_handler +#define vl_api_one_add_del_l2_arp_entry vl_noop_handler +#define vl_api_one_l2_arp_bd_get vl_noop_handler + #define vl_typedefs /* define message structures */ #include #undef vl_typedefs @@ -109,6 +114,9 @@ _(SHOW_ONE_STATS_ENABLE_DISABLE, show_one_stats_enable_disable) \ _(ONE_STATS_ENABLE_DISABLE, one_stats_enable_disable) \ _(ONE_STATS_DUMP, one_stats_dump) \ _(ONE_STATS_FLUSH, one_stats_flush) \ +_(ONE_L2_ARP_BD_GET, one_l2_arp_bd_get) \ +_(ONE_L2_ARP_ENTRIES_GET, one_l2_arp_entries_get) \ +_(ONE_ADD_DEL_L2_ARP_ENTRY, one_add_del_l2_arp_entry) \ static locator_t * @@ -1387,6 +1395,80 @@ vl_api_one_stats_dump_t_handler (vl_api_one_stats_dump_t * mp) } } +static void + vl_api_one_add_del_l2_arp_entry_t_handler + (vl_api_one_add_del_l2_arp_entry_t * mp) +{ + vl_api_one_add_del_l2_arp_entry_reply_t *rmp; + int rv = 0; + gid_address_t _arp, *arp = &_arp; + memset (arp, 0, sizeof (*arp)); + + gid_address_type (arp) = GID_ADDR_ARP; + gid_address_arp_bd (arp) = clib_net_to_host_u32 (mp->bd); + + /* vpp keeps ip4 addresses in network byte order */ + clib_memcpy (&gid_address_arp_ip4 (arp), &mp->ip4, 4); + + rv = vnet_lisp_add_del_l2_arp_entry (arp, mp->mac, mp->is_add); + + REPLY_MACRO (VL_API_ONE_ADD_DEL_L2_ARP_ENTRY_REPLY); +} + +static void +vl_api_one_l2_arp_bd_get_t_handler (vl_api_one_l2_arp_bd_get_t * mp) +{ + vl_api_one_l2_arp_bd_get_reply_t *rmp; + int rv = 0; + u32 i = 0; + hash_pair_t *p; + + u32 *bds = vnet_lisp_l2_arp_bds_get (); + u32 size = hash_elts (bds) * sizeof (u32); + + /* *INDENT-OFF* */ + REPLY_MACRO4 (VL_API_ONE_L2_ARP_BD_GET_REPLY, size, + { + rmp->count = clib_host_to_net_u32 (hash_elts (bds)); + hash_foreach_pair (p, bds, + ({ + rmp->bridge_domains[i++] = clib_host_to_net_u32 (p->key); + })); + }); + /* *INDENT-ON* */ + + hash_free (bds); +} + +static void +vl_api_one_l2_arp_entries_get_t_handler (vl_api_one_l2_arp_entries_get_t * mp) +{ + vl_api_one_l2_arp_entries_get_reply_t *rmp; + lisp_api_l2_arp_entry_t *entries = 0, *e; + u32 i = 0; + int rv = 0; + + u32 bd = clib_net_to_host_u32 (mp->bd); + + entries = vnet_lisp_l2_arp_entries_get_by_bd (bd); + u32 size = vec_len (entries) * sizeof (u32); + + /* *INDENT-OFF* */ + REPLY_MACRO4 (VL_API_ONE_L2_ARP_ENTRIES_GET_REPLY, size, + { + rmp->count = clib_host_to_net_u32 (vec_len (entries)); + vec_foreach (e, entries) + { + mac_copy (rmp->entries[i].mac, e->mac); + rmp->entries[i].ip4 = e->ip4; + i++; + } + }); + /* *INDENT-ON* */ + + vec_free (entries); +} + /* * one_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index 109aca2e..db6a6c83 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -276,6 +276,106 @@ VLIB_CLI_COMMAND (one_eid_table_map_command) = { }; /* *INDENT-ON* */ +static clib_error_t * +lisp_add_del_l2_arp_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; + clib_error_t *error = NULL; + int rc = 0; + u8 hw_addr[6], bd = 0; + ip4_address_t ip4; + u32 hw_addr_set = 0, ip_set = 0, is_add = 1; + gid_address_t _arp, *arp = &_arp; + + memset (&ip4, 0, sizeof (ip4)); + memset (hw_addr, 0, sizeof (hw_addr)); + memset (arp, 0, sizeof (*arp)); + + 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, "mac %U", unformat_mac_address, hw_addr)) + hw_addr_set = 1; + else if (unformat (line_input, "ip %U", unformat_ip4_address, &ip4)) + ip_set = 1; + else if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "bd %d", &bd)) + ; + else + { + error = clib_error_return (0, "parse error"); + goto done; + } + } + + if (!ip_set || (!hw_addr_set && is_add)) + { + vlib_cli_output (vm, "expected IP and MAC addresses!"); + return 0; + } + + /* build GID address */ + gid_address_arp_ip4 (arp) = ip4; + gid_address_arp_bd (arp) = bd; + gid_address_type (arp) = GID_ADDR_ARP; + rc = vnet_lisp_add_del_l2_arp_entry (arp, hw_addr, is_add); + if (rc) + clib_warning ("Failed to %s l2 arp entry!", is_add ? "add" : "delete"); + +done: + unformat_free (line_input); + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_add_del_l2_arp_entry_command) = { + .path = "one l2 arp", + .short_help = "one l2 arp [del] bd mac ip ", + .function = lisp_add_del_l2_arp_entry_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +lisp_show_l2_arp_entries_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u32 *ht = vnet_lisp_l2_arp_bds_get (); + lisp_api_l2_arp_entry_t *entries, *e; + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, ht, + ({ + entries = vnet_lisp_l2_arp_entries_get_by_bd (p->key); + vlib_cli_output (vm, "Table: %d", p->key); + + vec_foreach (e, entries) + { + vlib_cli_output (vm, "\t%U -> %U", format_ip4_address, &e->ip4, + format_mac_address, e->mac); + } + vec_free (entries); + })); + /* *INDENT-ON* */ + + hash_free (ht); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_show_l2_arp_entries_command) = { + .path = "show one l2 arp entries", + .short_help = "Show ONE L2 ARP entries", + .function = lisp_show_l2_arp_entries_command_fn, +}; +/* *INDENT-ON* */ + /** * Handler for add/del remote mapping CLI. * -- cgit 1.2.3-korg From ef2a5bf0a31c9c0a94f9f497cb6353f46073e6ec Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Tue, 30 May 2017 07:14:46 +0200 Subject: LISP: add NSH support Change-Id: I971c110ed126f1a24a963f9d3b88cf8f8c308816 Signed-off-by: Filip Tehlar --- src/tests/vnet/lisp-cp/test_lisp_types.c | 76 ++++++++++++- src/vat/api_format.c | 180 +++++++++++++++++++++++++++++-- src/vnet/lisp-cp/control.c | 139 +++++++++++++++++++++--- src/vnet/lisp-cp/control.h | 4 + src/vnet/lisp-cp/gid_dictionary.c | 79 +++++++++++++- src/vnet/lisp-cp/gid_dictionary.h | 17 +++ src/vnet/lisp-cp/lisp_cp_messages.h | 31 ++++++ src/vnet/lisp-cp/lisp_types.c | 108 ++++++++++++++++--- src/vnet/lisp-cp/lisp_types.h | 10 +- src/vnet/lisp-cp/one.api | 49 +++++++++ src/vnet/lisp-cp/one_api.c | 105 +++++++++++++++++- src/vnet/lisp-cp/one_cli.c | 58 +++++++++- src/vnet/lisp-gpe/interface.c | 8 +- src/vnet/lisp-gpe/lisp_gpe.h | 3 + src/vpp/api/test_client.c | 3 +- 15 files changed, 826 insertions(+), 44 deletions(-) (limited to 'src/vnet/lisp-cp/gid_dictionary.c') diff --git a/src/tests/vnet/lisp-cp/test_lisp_types.c b/src/tests/vnet/lisp-cp/test_lisp_types.c index 21575015..7c55a9c1 100644 --- a/src/tests/vnet/lisp-cp/test_lisp_types.c +++ b/src/tests/vnet/lisp-cp/test_lisp_types.c @@ -90,7 +90,7 @@ static clib_error_t * test_gid_parse_ip_pref () { clib_error_t * error = 0; gid_address_t _gid_addr, * gid_addr = &_gid_addr; - gid_address_t _gid_addr_copy, * gid_addr_copy = &_gid_addr_copy; + gid_address_t _gid_addr_copy, * copy = &_gid_addr_copy; u8 data[] = { 0x00, 0x01, /* AFI = IPv4 */ @@ -99,8 +99,8 @@ static clib_error_t * test_gid_parse_ip_pref () u32 len = gid_address_parse (data, gid_addr); _assert (6 == len); - gid_address_copy (gid_addr_copy, gid_addr); - _assert (0 == gid_address_cmp (gid_addr_copy, gid_addr)); + gid_address_copy (copy, gid_addr); + _assert (0 == gid_address_cmp (copy, gid_addr)); done: return error; } @@ -127,6 +127,74 @@ done: return error; } +static clib_error_t * +test_gid_write_nsh (void) +{ + clib_error_t * error = 0; + + u8 * b = clib_mem_alloc(500); + memset(b, 0, 500); + + gid_address_t g = + { + .vni = 0, + .nsh.spi = 0x112233, + .nsh.si = 0x42, + .type = GID_ADDR_NSH, + }; + + u16 len = gid_address_put (b, &g); + + u8 expected[] = + { + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF*/ + 0x11, 0x00, 0x00, 0x04, /* type = SPI LCAF, length = 4 */ + + /* Service Path ID, Service index */ + 0x11, 0x22, 0x33, 0x42, /* SPI, SI */ + }; + + _assert (sizeof (expected) == len); + _assert (0 == memcmp (expected, b, len)); +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * +test_gid_parse_nsh () +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid_addr = &_gid_addr; + gid_address_t _gid_addr_copy, * copy = &_gid_addr_copy; + + memset (gid_addr, 0, sizeof (gid_addr[0])); + memset (copy, 0, sizeof (copy[0])); + + u8 data[] = + { + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF*/ + 0x11, 0x00, 0x00, 0x04, /* type = SPI LCAF, length = 4 */ + + /* Service Path ID, Service index */ + 0x55, 0x99, 0x42, 0x09, /* SPI, SI */ + }; + + u32 len = gid_address_parse (data, gid_addr); + _assert (sizeof (data) == len); + gid_address_copy (copy, gid_addr); + _assert (0 == gid_address_cmp (gid_addr, copy)); + _assert (GID_ADDR_NSH == gid_address_type (copy)); + _assert (0 == gid_address_vni (copy)); + _assert (gid_address_nsh_spi (copy) == 0x559942); + _assert (gid_address_nsh_si (copy) == 0x09); + +done: + gid_address_free (copy); + gid_address_free (gid_addr); + return error; +} + static clib_error_t * test_gid_parse_lcaf () { clib_error_t * error = 0; @@ -555,6 +623,8 @@ done: _(gid_parse_ip_pref) \ _(gid_parse_mac) \ _(gid_parse_lcaf) \ + _(gid_parse_nsh) \ + _(gid_write_nsh) \ _(mac_address_write) \ _(gid_address_write) \ _(src_dst_serdes) \ diff --git a/src/vat/api_format.c b/src/vat/api_format.c index f33b4592..766624a0 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -2583,6 +2583,26 @@ static void vec_free (ls_name); } +typedef struct +{ + u32 spi; + u8 si; +} __attribute__ ((__packed__)) lisp_nsh_api_t; + +uword +unformat_nsh_address (unformat_input_t * input, va_list * args) +{ + lisp_nsh_api_t *nsh = va_arg (*args, lisp_nsh_api_t *); + return unformat (input, "SPI:%d SI:%d", &nsh->spi, &nsh->si); +} + +u8 * +format_nsh_address_vat (u8 * s, va_list * args) +{ + nsh_t *a = va_arg (*args, nsh_t *); + return format (s, "SPI:%d SI:%d", clib_net_to_host_u32 (a->spi), a->si); +} + static u8 * format_lisp_flat_eid (u8 * s, va_list * args) { @@ -2598,6 +2618,8 @@ format_lisp_flat_eid (u8 * s, va_list * args) return format (s, "%U/%d", format_ip6_address, eid, eid_len); case 2: return format (s, "%U", format_ethernet_address, eid); + case 3: + return format (s, "%U", format_nsh_address_vat, eid); } return 0; } @@ -2672,13 +2694,26 @@ vl_api_one_eid_table_details_t_handler_json (vl_api_one_eid_table_details_t clib_net_to_host_u32 (mp->locator_set_index)); vat_json_object_add_uint (node, "is_local", mp->is_local ? 1 : 0); - eid = format (0, "%U", format_lisp_eid_vat, - mp->eid_type, - mp->eid, - mp->eid_prefix_len, - mp->seid, mp->seid_prefix_len, mp->is_src_dst); - vec_add1 (eid, 0); - vat_json_object_add_string_copy (node, "eid", eid); + if (mp->eid_type == 3) + { + vat_json_node_t *nsh_json = vat_json_object_add (node, "eid"); + vat_json_init_object (nsh_json); + lisp_nsh_api_t *nsh = (lisp_nsh_api_t *) mp->eid; + vat_json_object_add_uint (nsh_json, "spi", + clib_net_to_host_u32 (nsh->spi)); + vat_json_object_add_uint (nsh_json, "si", nsh->si); + } + else + { + eid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, + mp->eid, + mp->eid_prefix_len, + mp->seid, mp->seid_prefix_len, mp->is_src_dst); + vec_add1 (eid, 0); + vat_json_object_add_string_copy (node, "eid", eid); + vec_free (eid); + } vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); vat_json_object_add_uint (node, "ttl", clib_net_to_host_u32 (mp->ttl)); vat_json_object_add_uint (node, "authoritative", (mp->authoritative)); @@ -2689,7 +2724,6 @@ vl_api_one_eid_table_details_t_handler_json (vl_api_one_eid_table_details_t clib_net_to_host_u16 (mp->key_id)); vat_json_object_add_string_copy (node, "key", mp->key); } - vec_free (eid); } static void @@ -3665,6 +3699,52 @@ static void vam->result_ready = 1; } +static void + vl_api_show_one_nsh_mapping_reply_t_handler + (vl_api_show_one_nsh_mapping_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (0 <= retval) + { + print (vam->ofp, "%-20s%-16s", + mp->is_set ? "set" : "not-set", + mp->is_set ? (char *) mp->locator_set_name : ""); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_one_nsh_mapping_reply_t_handler_json + (vl_api_show_one_nsh_mapping_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + u8 *status = 0; + + status = format (0, "%s", mp->is_set ? "yes" : "no"); + vec_add1 (status, 0); + + vat_json_init_object (&node); + vat_json_object_add_string_copy (&node, "is_set", status); + if (mp->is_set) + { + vat_json_object_add_string_copy (&node, "locator_set", + mp->locator_set_name); + } + + vec_free (status); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + static void vl_api_show_one_pitr_reply_t_handler (vl_api_show_one_pitr_reply_t * mp) { @@ -4672,6 +4752,7 @@ _(ONE_ADD_DEL_MAP_REQUEST_ITR_RLOCS_REPLY, \ one_add_del_map_request_itr_rlocs_reply) \ _(ONE_GET_MAP_REQUEST_ITR_RLOCS_REPLY, \ one_get_map_request_itr_rlocs_reply) \ +_(SHOW_ONE_NSH_MAPPING_REPLY, show_one_nsh_mapping_reply) \ _(SHOW_ONE_PITR_REPLY, show_one_pitr_reply) \ _(SHOW_ONE_USE_PETR_REPLY, show_one_use_petr_reply) \ _(SHOW_ONE_MAP_REQUEST_MODE_REPLY, show_one_map_request_mode_reply) \ @@ -14044,6 +14125,12 @@ unformat_lisp_eid_vat (unformat_input_t * input, va_list * args) { a->type = 2; /* mac type */ } + else if (unformat (input, "%U", unformat_nsh_address, a->addr)) + { + a->type = 3; /* NSH type */ + lisp_nsh_api_t *nsh = (lisp_nsh_api_t *) a->addr; + nsh->spi = clib_host_to_net_u32 (nsh->spi); + } else { return 0; @@ -14068,6 +14155,8 @@ lisp_eid_size_vat (u8 type) return 16; case 2: return 6; + case 3: + return 5; } return 0; } @@ -15166,6 +15255,50 @@ api_one_pitr_set_locator_set (vat_main_t * vam) #define api_lisp_pitr_set_locator_set api_one_pitr_set_locator_set +static int +api_one_nsh_set_locator_set (vat_main_t * vam) +{ + u8 ls_name_set = 0; + unformat_input_t *input = vam->input; + vl_api_one_nsh_set_locator_set_t *mp; + u8 is_add = 1; + u8 *ls_name = 0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "ls %s", &ls_name)) + ls_name_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!ls_name_set && is_add) + { + errmsg ("locator-set name not set!"); + return -99; + } + + M (ONE_NSH_SET_LOCATOR_SET, mp); + + mp->is_add = is_add; + clib_memcpy (mp->ls_name, ls_name, vec_len (ls_name)); + vec_free (ls_name); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_show_one_pitr (vat_main_t * vam) { @@ -15245,6 +15378,26 @@ api_one_use_petr (vat_main_t * vam) #define api_lisp_use_petr api_one_use_petr +static int +api_show_one_nsh_mapping (vat_main_t * vam) +{ + vl_api_show_one_use_petr_t *mp; + int ret; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "local ONE NSH mapping:"); + } + + M (SHOW_ONE_NSH_MAPPING, mp); + /* send it... */ + S (mp); + + /* Wait for a reply... */ + W (ret); + return ret; +} + static int api_show_one_use_petr (vat_main_t * vam) { @@ -16031,6 +16184,7 @@ api_one_eid_table_dump (vat_main_t * vam) u32 prefix_length = ~0, t, vni = 0; u8 filter = 0; int ret; + lisp_nsh_api_t nsh; while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { @@ -16051,6 +16205,11 @@ api_one_eid_table_dump (vat_main_t * vam) eid_set = 1; eid_type = 2; } + else if (unformat (i, "eid %U", unformat_nsh_address, &nsh)) + { + eid_set = 1; + eid_type = 3; + } else if (unformat (i, "vni %d", &t)) { vni = t; @@ -16097,6 +16256,9 @@ api_one_eid_table_dump (vat_main_t * vam) case 2: clib_memcpy (mp->eid, mac, sizeof (mac)); break; + case 3: + clib_memcpy (mp->eid, &nsh, sizeof (nsh)); + break; default: errmsg ("unknown EID type %d!", eid_type); return -99; @@ -19423,12 +19585,14 @@ _(one_eid_table_map_dump, "l2|l3") \ _(one_map_resolver_dump, "") \ _(one_map_server_dump, "") \ _(one_adjacencies_get, "vni ") \ +_(one_nsh_set_locator_set, "[del] ls ") \ _(show_one_rloc_probe_state, "") \ _(show_one_map_register_state, "") \ _(show_one_status, "") \ _(one_stats_dump, "") \ _(one_stats_flush, "") \ _(one_get_map_request_itr_rlocs, "") \ +_(show_one_nsh_mapping, "") \ _(show_one_pitr, "") \ _(show_one_use_petr, "") \ _(show_one_map_request_mode, "") \ diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 19bbd618..db78678d 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -28,6 +28,8 @@ #include #include +#define MAX_VALUE_U24 0xffffff + lisp_cp_main_t lisp_control_main; u8 *format_lisp_cp_input_trace (u8 * s, va_list * args); @@ -697,6 +699,20 @@ vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a, mapping_t *m, *old_map; u32 **eid_indexes; + if (gid_address_type (&a->eid) == GID_ADDR_NSH) + { + if (gid_address_vni (&a->eid) != 0) + { + clib_warning ("Supported only default VNI for NSH!"); + return VNET_API_ERROR_INVALID_ARGUMENT; + } + if (gid_address_nsh_spi (&a->eid) > MAX_VALUE_U24) + { + clib_warning ("SPI is greater than 24bit!"); + return VNET_API_ERROR_INVALID_ARGUMENT; + } + } + mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid); old_map = mi != ~0 ? pool_elt_at_index (lcm->mapping_pool, mi) : 0; if (a->is_add) @@ -812,7 +828,7 @@ vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a, else if (GID_ADDR_MAC == type) dp_table = hash_get (lcm->bd_id_by_vni, vni); - if (!dp_table) + if (!dp_table && GID_ADDR_NSH != type) { clib_warning ("vni %d not associated to a %s!", vni, GID_ADDR_IP_PREFIX == type ? "vrf" : "bd"); @@ -1329,8 +1345,23 @@ vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a) { /* check if source eid has an associated mapping. If pitr mode is on, * just use the pitr's mapping */ - local_mi = lcm->lisp_pitr ? lcm->pitr_map_index : - gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->leid); + if (lcm->lisp_pitr) + local_mi = lcm->pitr_map_index; + else + { + if (gid_address_type (&a->reid) == GID_ADDR_NSH) + { + if (lcm->nsh_map_index == ~0) + local_mi = GID_LOOKUP_MISS; + else + local_mi = lcm->nsh_map_index; + } + else + { + local_mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, + &a->leid); + } + } if (GID_LOOKUP_MISS == local_mi) { @@ -1370,6 +1401,57 @@ vnet_lisp_set_map_request_mode (u8 mode) return 0; } +int +vnet_lisp_nsh_set_locator_set (u8 * locator_set_name, u8 is_add) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + u32 locator_set_index = ~0; + mapping_t *m; + uword *p; + + if (vnet_lisp_enable_disable_status () == 0) + { + clib_warning ("LISP is disabled!"); + return VNET_API_ERROR_LISP_DISABLED; + } + + if (is_add) + { + if (lcm->nsh_map_index == (u32) ~ 0) + { + p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name); + if (!p) + { + clib_warning ("locator-set %v doesn't exist", locator_set_name); + return -1; + } + locator_set_index = p[0]; + + pool_get (lcm->mapping_pool, m); + memset (m, 0, sizeof *m); + m->locator_set_index = locator_set_index; + m->local = 1; + m->nsh_set = 1; + lcm->nsh_map_index = m - lcm->mapping_pool; + + if (~0 == vnet_lisp_gpe_add_nsh_iface (lgm)) + return -1; + } + } + else + { + if (lcm->nsh_map_index != (u32) ~ 0) + { + /* remove NSH mapping */ + pool_put_index (lcm->mapping_pool, lcm->nsh_map_index); + lcm->nsh_map_index = ~0; + vnet_lisp_gpe_del_nsh_iface (lgm); + } + } + return 0; +} + int vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add) { @@ -2667,7 +2749,7 @@ _send_encapsulated_map_request (lisp_cp_main_t * lcm, } /* get locator-set for seid */ - if (!lcm->lisp_pitr) + if (!lcm->lisp_pitr && gid_address_type (deid) != GID_ADDR_NSH) { map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid); if (map_index == ~0) @@ -2690,9 +2772,24 @@ _send_encapsulated_map_request (lisp_cp_main_t * lcm, } else { - map_index = lcm->pitr_map_index; - map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index); - ls_index = map->locator_set_index; + if (lcm->lisp_pitr) + { + map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index); + ls_index = map->locator_set_index; + } + else + { + if (lcm->nsh_map_index == (u32) ~ 0) + { + clib_warning ("No locator-set defined for NSH!"); + return -1; + } + else + { + map = pool_elt_at_index (lcm->mapping_pool, lcm->nsh_map_index); + ls_index = map->locator_set_index; + } + } } /* overwrite locator set if map-request itr-rlocs configured */ @@ -2843,6 +2940,7 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, gid_address_t * src, gid_address_t * dst, u16 type) { + ethernet_header_t *eh; u32 vni = 0; memset (src, 0, sizeof (*src)); @@ -2873,7 +2971,6 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, } else if (LISP_AFI_MAC == type) { - ethernet_header_t *eh; ethernet_arp_header_t *ah; eh = vlib_buffer_get_current (b); @@ -2906,8 +3003,19 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, } else if (LISP_AFI_LCAF == type) { - /* Eventually extend this to support NSH and other */ - ASSERT (0); + lisp_nsh_hdr_t *nh; + eh = vlib_buffer_get_current (b); + + if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_NSH) + { + nh = (lisp_nsh_hdr_t *) (((u8 *) eh) + sizeof (*eh)); + u32 spi = clib_net_to_host_u32 (nh->spi_si << 8); + u8 si = (u8) clib_net_to_host_u32 (nh->spi_si); + gid_address_nsh_spi (dst) = spi; + gid_address_nsh_si (dst) = si; + + gid_address_type (dst) = GID_ADDR_NSH; + } } } @@ -3009,8 +3117,14 @@ lisp_cp_lookup_inline (vlib_main_t * vm, } else { - si = gid_dictionary_lookup (&lcm->mapping_index_by_gid, - &src); + if (GID_ADDR_NSH != gid_address_type (&dst)) + { + si = gid_dictionary_lookup (&lcm->mapping_index_by_gid, + &src); + } + else + si = lcm->nsh_map_index; + if (~0 != si) { dp_add_fwd_entry_from_mt (si, di); @@ -3862,6 +3976,7 @@ lisp_cp_init (vlib_main_t * vm) u64 now = clib_cpu_time_now (); timing_wheel_init (&lcm->wheel, now, vm->clib_time.clocks_per_second); + lcm->nsh_map_index = ~0; return 0; } diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h index feb8cfa4..ad90b526 100644 --- a/src/vnet/lisp-cp/control.h +++ b/src/vnet/lisp-cp/control.h @@ -211,6 +211,9 @@ typedef struct /* LISP PITR mode */ u8 lisp_pitr; + /* mapping index for NSH */ + u32 nsh_map_index; + /* map request mode */ u8 map_request_mode; @@ -353,6 +356,7 @@ u8 vnet_lisp_rloc_probe_state_get (void); int vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add); u32 *vnet_lisp_l2_arp_bds_get (void); lisp_api_l2_arp_entry_t *vnet_lisp_l2_arp_entries_get_by_bd (u32 bd); +int vnet_lisp_nsh_set_locator_set (u8 * locator_set_name, u8 is_add); map_records_arg_t *parse_map_reply (vlib_buffer_t * b); diff --git a/src/vnet/lisp-cp/gid_dictionary.c b/src/vnet/lisp-cp/gid_dictionary.c index 80d59faf..cf9a741a 100644 --- a/src/vnet/lisp-cp/gid_dictionary.c +++ b/src/vnet/lisp-cp/gid_dictionary.c @@ -345,6 +345,14 @@ make_arp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip4_address_t * addr) kv->key[2] = (u64) 0; } +static void +make_nsh_key (BVT (clib_bihash_kv) * kv, u32 vni, u32 spi, u8 si) +{ + kv->key[0] = (u64) vni; + kv->key[1] = (u64) spi; + kv->key[2] = (u64) si; +} + static u64 arp_lookup (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key) { @@ -360,6 +368,21 @@ arp_lookup (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key) return GID_LOOKUP_MISS_L2; } +static u32 +nsh_lookup (gid_nsh_table_t * db, u32 vni, u32 spi, u8 si) +{ + int rv; + BVT (clib_bihash_kv) kv, value; + + make_nsh_key (&kv, vni, spi, si); + rv = BV (clib_bihash_search_inline_2) (&db->nsh_lookup_table, &kv, &value); + + if (rv == 0) + return value.value; + + return GID_LOOKUP_MISS; +} + u64 gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) { @@ -393,6 +416,9 @@ gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) case GID_ADDR_ARP: return arp_lookup (&db->arp_table, gid_address_arp_bd (key), &gid_address_arp_ip4 (key)); + case GID_ADDR_NSH: + return nsh_lookup (&db->nsh_table, gid_address_vni (key), + gid_address_nsh_spi (key), gid_address_nsh_si (key)); default: clib_warning ("address type %d not supported!", gid_address_type (key)); break; @@ -432,6 +458,9 @@ gid_dictionary_sd_lookup (gid_dictionary_t * db, gid_address_t * dst, break; } break; + case GID_ADDR_NSH: + return gid_dictionary_lookup (db, dst); + break; default: clib_warning ("address type %d not supported!", gid_address_type (dst)); break; @@ -860,7 +889,7 @@ add_del_sd (gid_dictionary_t * db, u32 vni, source_dest_t * key, u32 value, return ~0; } -static u32 +static u64 add_del_arp (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key, u64 value, u8 is_add) { @@ -885,6 +914,31 @@ add_del_arp (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key, u64 value, return old_val; } +static u32 +add_del_nsh (gid_nsh_table_t * db, u32 vni, u32 spi, u8 si, u32 value, + u8 is_add) +{ + BVT (clib_bihash_kv) kv, result; + u32 old_val = ~0; + + make_nsh_key (&kv, vni, spi, si); + if (BV (clib_bihash_search) (&db->nsh_lookup_table, &kv, &result) == 0) + old_val = result.value; + + if (is_add) + { + kv.value = value; + BV (clib_bihash_add_del) (&db->nsh_lookup_table, &kv, 1 /* is_add */ ); + db->count++; + } + else + { + BV (clib_bihash_add_del) (&db->nsh_lookup_table, &kv, 0 /* is_add */ ); + db->count--; + } + return old_val; +} + u32 gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, u8 is_add) @@ -903,6 +957,11 @@ gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, case GID_ADDR_ARP: return add_del_arp (&db->arp_table, gid_address_arp_bd (key), &gid_address_arp_ip4 (key), value, is_add); + case GID_ADDR_NSH: + return add_del_nsh (&db->nsh_table, gid_address_vni (key), + gid_address_nsh_spi (key), gid_address_nsh_si (key), + value, is_add); + default: clib_warning ("address type %d not supported!", gid_address_type (key)); break; @@ -944,6 +1003,23 @@ arp_lookup_init (gid_l2_arp_table_t * db) db->arp_lookup_table_size); } +static void +nsh_lookup_init (gid_nsh_table_t * db) +{ + if (db->nsh_lookup_table_nbuckets == 0) + db->nsh_lookup_table_nbuckets = MAC_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; + + db->nsh_lookup_table_nbuckets = + 1 << max_log2 (db->nsh_lookup_table_nbuckets); + + if (db->nsh_lookup_table_size == 0) + db->nsh_lookup_table_size = MAC_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; + + BV (clib_bihash_init) (&db->nsh_lookup_table, "nsh lookup table", + db->nsh_lookup_table_nbuckets, + db->nsh_lookup_table_size); +} + void gid_dictionary_init (gid_dictionary_t * db) { @@ -951,6 +1027,7 @@ gid_dictionary_init (gid_dictionary_t * db) ip6_lookup_init (&db->dst_ip6_table); mac_lookup_init (&db->sd_mac_table); arp_lookup_init (&db->arp_table); + nsh_lookup_init (&db->nsh_table); } /* diff --git a/src/vnet/lisp-cp/gid_dictionary.h b/src/vnet/lisp-cp/gid_dictionary.h index 9612fb13..51806bd6 100644 --- a/src/vnet/lisp-cp/gid_dictionary.h +++ b/src/vnet/lisp-cp/gid_dictionary.h @@ -40,6 +40,10 @@ #define ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) #define ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) +/* Default size of the NSH hash table */ +#define NSH_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define NSH_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) + typedef void (*foreach_subprefix_match_cb_t) (u32, void *); typedef struct @@ -84,6 +88,16 @@ typedef struct gid_mac_table u64 count; } gid_mac_table_t; +typedef struct gid_nsh_table +{ + BVT (clib_bihash) nsh_lookup_table; + + /* nsh lookup table config parameters */ + u32 nsh_lookup_table_nbuckets; + uword nsh_lookup_table_size; + u64 count; +} gid_nsh_table_t; + typedef struct { BVT (clib_bihash) arp_lookup_table; @@ -97,6 +111,9 @@ typedef struct /** L2 ARP table */ gid_l2_arp_table_t arp_table; + /** NSH lookup table */ + gid_nsh_table_t nsh_table; + /** destination IP LPM ip4 lookup table */ gid_ip4_table_t dst_ip4_table; diff --git a/src/vnet/lisp-cp/lisp_cp_messages.h b/src/vnet/lisp-cp/lisp_cp_messages.h index 278f60e1..69510a0e 100644 --- a/src/vnet/lisp-cp/lisp_cp_messages.h +++ b/src/vnet/lisp-cp/lisp_cp_messages.h @@ -473,6 +473,22 @@ typedef struct _lcaf_src_dst_hdr_t #define LCAF_SD_SRC_ML(_h) (_h)->src_mask_len #define LCAF_SD_DST_ML(_h) (_h)->dst_mask_len +/* + * SPI LCAF + * + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Service Path ID | Service index | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct _lcaf_spi_hdr_t +{ + u32 spi_si; +} __attribute__ ((__packed__)) lcaf_spi_hdr_t; + +#define LCAF_SPI_SI(_h) (_h)->spi_si + /* * The Map-Register message format is: * @@ -602,6 +618,21 @@ typedef struct #define MNOTIFY_AUTH_DATA_LEN(h_) (MREG_HDR_CAST(h_))->auth_data_len #define MNOTIFY_DATA(h_) (MREG_HDR_CAST(h_))->data +/* + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Ver|O|C|R|R|R|R|R|R| Length | MD type=0x1 | Next Protocol | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Service Path Identifer | Service Index | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +typedef struct +{ + u32 header; + u32 spi_si; +} __attribute__ ((__packed__)) lisp_nsh_hdr_t; + #endif /* VNET_LISP_GPE_LISP_CP_MESSAGES_H_ */ /* diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index 85cefae0..e50c3aa1 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -31,16 +31,28 @@ typedef int (*cmp_fct) (void *, void *); size_to_write_fct size_to_write_fcts[GID_ADDR_TYPES] = { ip_prefix_size_to_write, lcaf_size_to_write, mac_size_to_write, - sd_size_to_write, nsh_size_to_write + sd_size_to_write, nsh_size_to_write, 0 /* arp */ , no_addr_size_to_write }; + serdes_fct write_fcts[GID_ADDR_TYPES] = - { ip_prefix_write, lcaf_write, mac_write, sd_write, nsh_write }; + { ip_prefix_write, lcaf_write, mac_write, sd_write, nsh_write, 0 /* arp */ , + no_addr_write +}; + cast_fct cast_fcts[GID_ADDR_TYPES] = - { ip_prefix_cast, lcaf_cast, mac_cast, sd_cast, nsh_cast }; + { ip_prefix_cast, lcaf_cast, mac_cast, sd_cast, nsh_cast, 0 /* arp */ , + no_addr_cast +}; + addr_len_fct addr_len_fcts[GID_ADDR_TYPES] = - { ip_prefix_length, lcaf_length, mac_length, sd_length, nsh_length }; + { ip_prefix_length, lcaf_length, mac_length, sd_length, nsh_length, + 0 /* arp */ , no_addr_length +}; + copy_fct copy_fcts[GID_ADDR_TYPES] = - { ip_prefix_copy, lcaf_copy, mac_copy, sd_copy, nsh_copy }; + { ip_prefix_copy, lcaf_copy, mac_copy, sd_copy, nsh_copy, 0 /* arp */ , + no_addr_copy +}; #define foreach_lcaf_type \ _(1, no_addr) \ @@ -55,7 +67,12 @@ copy_fct copy_fcts[GID_ADDR_TYPES] = _(0, NULL) \ _(0, NULL) \ _(0, NULL) \ - _(1, sd) + _(1, sd) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(1, nsh) #define _(cond, name) \ u16 name ## _write (u8 * p, void * a); \ @@ -254,11 +271,12 @@ format_gid_address (u8 * s, va_list * args) case GID_ADDR_MAC: return format (s, "[%d] %U", gid_address_vni (a), format_mac_address, &gid_address_mac (a)); - case GID_ADDR_NSH: - return format (s, "%U", format_nsh_address, &gid_address_nsh (a)); case GID_ADDR_ARP: return format (s, "[%d, %U]", gid_address_arp_bd (a), format_ip4_address, &gid_address_arp_ip4 (a)); + case GID_ADDR_NSH: + return format (s, "%U", format_nsh_address, &gid_address_nsh (a)); + default: clib_warning ("Can't format gid type %d", type); return 0; @@ -287,7 +305,7 @@ unformat_fid_address (unformat_input_t * i, va_list * args) else if (unformat (i, "%U", unformat_nsh_address, &nsh)) { fid_addr_type (a) = FID_ADDR_NSH; - nsh_copy (&fid_addr_nsh (a), mac); + nsh_copy (&fid_addr_nsh (a), &nsh); } else return 0; @@ -673,6 +691,38 @@ do { \ dst += _sum; \ } while (0); +void +nsh_free (void *a) +{ + /* nothing to do */ +} + +u16 +nsh_parse (u8 * p, void *a) +{ + lcaf_spi_hdr_t *h = (lcaf_spi_hdr_t *) p; + gid_address_t *g = a; + + gid_address_type (g) = GID_ADDR_NSH; + gid_address_nsh_spi (g) = clib_net_to_host_u32 (LCAF_SPI_SI (h)) >> 8; + gid_address_nsh_si (g) = (u8) clib_net_to_host_u32 (LCAF_SPI_SI (h)); + + return sizeof (lcaf_spi_hdr_t); +} + +int +nsh_cmp (void *a1, void *a2) +{ + nsh_t *n1 = a1; + nsh_t *n2 = a2; + + if (n1->spi != n2->spi) + return 1; + if (n1->si != n2->si) + return 1; + return 0; +} + u16 sd_parse (u8 * p, void *a) { @@ -1094,6 +1144,12 @@ mac_cast (gid_address_t * a) return &gid_address_mac (a); } +void * +no_addr_cast (gid_address_t * a) +{ + return (void *) a; +} + void * sd_cast (gid_address_t * a) { @@ -1227,8 +1283,33 @@ sd_write (u8 * p, void *a) u16 nsh_write (u8 * p, void *a) { - clib_warning ("not done"); - return 0; + lcaf_spi_hdr_t spi; + lcaf_hdr_t lcaf; + gid_address_t *g = a; + u16 size = 0; + + ASSERT (gid_address_type (g) == GID_ADDR_NSH); + + memset (&lcaf, 0, sizeof (lcaf)); + memset (&spi, 0, sizeof (spi)); + + LCAF_TYPE (&lcaf) = LCAF_NSH; + LCAF_LENGTH (&lcaf) = clib_host_to_net_u16 (sizeof (lcaf_spi_hdr_t)); + + u32 s = clib_host_to_net_u32 (gid_address_nsh_spi (g) << 8 | + gid_address_nsh_si (g)); + LCAF_SPI_SI (&spi) = s; + + *(u16 *) p = clib_host_to_net_u16 (LISP_AFI_LCAF); + size += sizeof (u16); + + clib_memcpy (p + size, &lcaf, sizeof (lcaf)); + size += sizeof (lcaf); + + clib_memcpy (p + size, &spi, sizeof (spi)); + size += sizeof (spi); + + return size; } u16 @@ -1354,7 +1435,7 @@ mac_size_to_write (void *a) u16 nsh_size_to_write (void *a) { - return sizeof (u16) + 4; + return sizeof (u16) + sizeof (lcaf_hdr_t) + sizeof (lcaf_spi_hdr_t); } u8 @@ -1581,6 +1662,9 @@ gid_address_cmp (gid_address_t * a1, gid_address_t * a2) case GID_ADDR_SRC_DST: cmp = sd_cmp (&gid_address_sd (a1), &gid_address_sd (a2)); break; + case GID_ADDR_NSH: + cmp = nsh_cmp (&gid_address_nsh (a1), &gid_address_nsh (a2)); + break; default: break; } diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index f5d2a676..b7ad0f27 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -102,6 +102,7 @@ typedef enum LCAF_AFI_LIST_TYPE, LCAF_INSTANCE_ID, LCAF_SOURCE_DEST = 12, + LCAF_NSH = 17, LCAF_TYPES } lcaf_type_t; @@ -166,6 +167,9 @@ typedef struct u8 si; } nsh_t; +#define nsh_spi(_a) (_a)->spi +#define nsh_si(_a) (_a)->si + typedef struct { ip4_address_t addr; @@ -258,6 +262,8 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); #define gid_address_lcaf(_a) (_a)->lcaf #define gid_address_mac(_a) (_a)->mac #define gid_address_nsh(_a) (_a)->nsh +#define gid_address_nsh_spi(_a) nsh_spi(&gid_address_nsh(_a)) +#define gid_address_nsh_si(_a) nsh_si(&gid_address_nsh(_a)) #define gid_address_vni(_a) (_a)->vni #define gid_address_vni_mask(_a) (_a)->vni_mask #define gid_address_sd_dst_ippref(_a) sd_dst_ippref(&(_a)->sd) @@ -275,6 +281,7 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); /* 'sub'address functions */ #define foreach_gid_address_type_fcns \ + _(no_addr) \ _(ip_prefix) \ _(lcaf) \ _(mac) \ @@ -350,7 +357,8 @@ typedef struct /* valid only for remote mappings */ u8 is_static:1; u8 pitr_set:1; - u8 rsvd:4; + u8 nsh_set:1; + u8 rsvd:3; u8 *key; diff --git a/src/vnet/lisp-cp/one.api b/src/vnet/lisp-cp/one.api index 7d07cc47..31811a34 100644 --- a/src/vnet/lisp-cp/one.api +++ b/src/vnet/lisp-cp/one.api @@ -146,6 +146,20 @@ autoreply define one_enable_disable u8 is_en; }; +/** \brief configure or delete ONE NSH mapping + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param ls_name - locator set name + @param is_add - add locator set if non-zero; delete otherwise +*/ +autoreply define one_nsh_set_locator_set +{ + u32 client_index; + u32 context; + u8 is_add; + u8 ls_name[64]; +}; + /** \brief configure or disable ONE PITR node @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -325,6 +339,12 @@ typeonly manual_endian manual_print define one_remote_locator 0 : ipv4 1 : ipv6 2 : mac + 3 : NSH : both information (service path ID and service index) are + encoded in 'eid' field in a following way: + + |4 B |1 B | + ----------- + |SPI | SI | @param deid - dst EID @param seid - src EID, valid only if is_src_dst is enabled @param rloc_num - number of remote locators @@ -596,6 +616,12 @@ define one_eid_table_details 0: EID is IPv4 1: EID is IPv6 2: EID is ethernet address + 3 : NSH : both information (service path ID and service index) are + encoded in 'eid' field in a following way: + + |4 B |1 B | + ----------- + |SPI | SI | @param eid - endpoint identifier @param filter - filter type; Support values: @@ -787,6 +813,29 @@ define one_get_map_request_itr_rlocs_reply u8 locator_set_name[64]; }; +/** \brief Request for ONE NSH mapping + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define show_one_nsh_mapping +{ + u32 client_index; + u32 context; +}; + +/** \brief Reply for ONE NSH mapping + @param context - sender context, to match reply w/ request + @param is_set - is ONE NSH mapping set + @param locator_set_name - name of the locator_set if NSH mapping is set +*/ +define show_one_nsh_mapping_reply +{ + u32 context; + i32 retval; + u8 is_set; + u8 locator_set_name[64]; +}; + /** \brief Request for ONE PITR status @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index 724e58df..18235fa4 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -90,6 +90,7 @@ _(ONE_MAP_REGISTER_ENABLE_DISABLE, one_map_register_enable_disable) \ _(ONE_ADD_DEL_REMOTE_MAPPING, one_add_del_remote_mapping) \ _(ONE_ADD_DEL_ADJACENCY, one_add_del_adjacency) \ _(ONE_PITR_SET_LOCATOR_SET, one_pitr_set_locator_set) \ +_(ONE_NSH_SET_LOCATOR_SET, one_nsh_set_locator_set) \ _(ONE_MAP_REQUEST_MODE, one_map_request_mode) \ _(ONE_EID_TABLE_ADD_DEL_MAP, one_eid_table_add_del_map) \ _(ONE_LOCATOR_SET_DUMP, one_locator_set_dump) \ @@ -100,6 +101,7 @@ _(ONE_MAP_SERVER_DUMP, one_map_server_dump) \ _(ONE_EID_TABLE_MAP_DUMP, one_eid_table_map_dump) \ _(ONE_EID_TABLE_VNI_DUMP, one_eid_table_vni_dump) \ _(ONE_ADJACENCIES_GET, one_adjacencies_get) \ +_(SHOW_ONE_NSH_MAPPING, show_one_nsh_mapping) \ _(SHOW_ONE_RLOC_PROBE_STATE, show_one_rloc_probe_state) \ _(SHOW_ONE_MAP_REGISTER_STATE, show_one_map_register_state) \ _(SHOW_ONE_STATUS, show_one_status) \ @@ -225,10 +227,18 @@ vl_api_one_add_del_locator_t_handler (vl_api_one_add_del_locator_t * mp) REPLY_MACRO (VL_API_ONE_ADD_DEL_LOCATOR_REPLY); } +typedef struct +{ + u32 spi; + u8 si; +} __attribute__ ((__packed__)) lisp_nsh_api_t; + static int unformat_one_eid_api (gid_address_t * dst, u32 vni, u8 type, void *src, u8 len) { + lisp_nsh_api_t *nsh; + switch (type) { case 0: /* ipv4 */ @@ -247,6 +257,12 @@ unformat_one_eid_api (gid_address_t * dst, u32 vni, u8 type, void *src, gid_address_type (dst) = GID_ADDR_MAC; clib_memcpy (&gid_address_mac (dst), src, 6); break; + case 3: /* NSH */ + gid_address_type (dst) = GID_ADDR_NSH; + nsh = src; + gid_address_nsh_spi (dst) = clib_net_to_host_u32 (nsh->spi); + gid_address_nsh_si (dst) = nsh->si; + break; default: /* unknown type */ return VNET_API_ERROR_INVALID_VALUE; @@ -276,6 +292,12 @@ vl_api_one_add_del_local_eid_t_handler (vl_api_one_add_del_local_eid_t * mp) if (rv) goto out; + if (gid_address_type (eid) == GID_ADDR_NSH) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto out; + } + name = format (0, "%s", mp->locator_set_name); p = hash_get_mem (lcm->locator_set_index_by_name, name); if (!p) @@ -408,6 +430,21 @@ vl_api_one_map_request_mode_t_handler (vl_api_one_map_request_mode_t * mp) REPLY_MACRO (VL_API_ONE_MAP_REQUEST_MODE_REPLY); } +static void +vl_api_one_nsh_set_locator_set_t_handler (vl_api_one_nsh_set_locator_set_t + * mp) +{ + vl_api_one_nsh_set_locator_set_reply_t *rmp; + int rv = 0; + u8 *ls_name = 0; + + ls_name = format (0, "%s", mp->ls_name); + rv = vnet_lisp_nsh_set_locator_set (ls_name, mp->is_add); + vec_free (ls_name); + + REPLY_MACRO (VL_API_ONE_PITR_SET_LOCATOR_SET_REPLY); +} + static void vl_api_one_pitr_set_locator_set_t_handler (vl_api_one_pitr_set_locator_set_t * mp) @@ -781,7 +818,7 @@ send_one_eid_table_details (mapping_t * mapit, u8 *mac = 0; ip_prefix_t *ip_prefix = NULL; - if (mapit->pitr_set) + if (mapit->pitr_set || mapit->nsh_set) return; switch (filter) @@ -851,6 +888,13 @@ send_one_eid_table_details (mapping_t * mapit, rmp->eid_type = 2; /* l2 mac type */ clib_memcpy (rmp->eid, mac, 6); break; + case GID_ADDR_NSH: + rmp->eid_type = 3; /* NSH type */ + lisp_nsh_api_t nsh; + nsh.spi = clib_host_to_net_u32 (gid_address_nsh_spi (gid)); + nsh.si = gid_address_nsh_si (gid); + clib_memcpy (rmp->eid, &nsh, sizeof (nsh)); + break; default: ASSERT (0); } @@ -1071,6 +1115,7 @@ one_adjacency_copy (vl_api_one_adjacency_t * dst, lisp_adjacency_t * adjs) lisp_adjacency_t *adj; vl_api_one_adjacency_t a; u32 i, n = vec_len (adjs); + lisp_nsh_api_t nsh; for (i = 0; i < n; i++) { @@ -1100,6 +1145,15 @@ one_adjacency_copy (vl_api_one_adjacency_t * dst, lisp_adjacency_t * adjs) mac_copy (a.reid, gid_address_mac (&adj->reid)); mac_copy (a.leid, gid_address_mac (&adj->leid)); break; + case GID_ADDR_NSH: + a.eid_type = 3; /* NSH type */ + nsh.spi = clib_host_to_net_u32 (gid_address_nsh_spi (&adj->reid)); + nsh.si = gid_address_nsh_si (&adj->reid); + clib_memcpy (a.reid, &nsh, sizeof (nsh)); + + nsh.spi = clib_host_to_net_u32 (gid_address_nsh_spi (&adj->leid)); + nsh.si = gid_address_nsh_si (&adj->leid); + clib_memcpy (a.leid, &nsh, sizeof (nsh)); default: ASSERT (0); } @@ -1255,6 +1309,55 @@ static void vec_free (tmp_str); } +static void +vl_api_show_one_nsh_mapping_t_handler (vl_api_show_one_nsh_mapping_t * mp) +{ + unix_shared_memory_queue_t *q = NULL; + vl_api_show_one_nsh_mapping_reply_t *rmp = NULL; + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + mapping_t *m; + locator_set_t *ls = 0; + u8 *tmp_str = 0; + u8 is_set = 0; + int rv = 0; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + if (lcm->nsh_map_index == (u32) ~ 0) + { + tmp_str = format (0, "N/A"); + } + else + { + m = pool_elt_at_index (lcm->mapping_pool, lcm->nsh_map_index); + if (~0 != m->locator_set_index) + { + ls = + pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index); + tmp_str = format (0, "%s", ls->name); + is_set = 1; + } + else + { + tmp_str = format (0, "N/A"); + } + } + vec_add1 (tmp_str, 0); + + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_SHOW_ONE_NSH_MAPPING_REPLY, + ({ + rmp->is_set = is_set; + strncpy((char *) rmp->locator_set_name, (char *) tmp_str, + ARRAY_LEN(rmp->locator_set_name) - 1); + })); + /* *INDENT-ON* */ +} + static void vl_api_show_one_pitr_t_handler (vl_api_show_one_pitr_t * mp) { diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index db6a6c83..e3fbf5a1 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -721,6 +721,62 @@ VLIB_CLI_COMMAND (one_show_map_resolvers_command) = { }; /* *INDENT-ON* */ +static clib_error_t * +lisp_nsh_set_locator_set_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u8 locator_name_set = 0; + u8 *locator_set_name = 0; + u8 is_add = 1; + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = 0; + int rv = 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, "ls %_%v%_", &locator_set_name)) + locator_name_set = 1; + else if (unformat (line_input, "disable")) + is_add = 0; + else + { + error = clib_error_return (0, "parse error"); + goto done; + } + } + + if (!locator_name_set) + { + clib_warning ("No locator set specified!"); + goto done; + } + + rv = vnet_lisp_nsh_set_locator_set (locator_set_name, is_add); + if (0 != rv) + { + error = clib_error_return (0, "failed to %s NSH mapping!", + is_add ? "add" : "delete"); + } + +done: + vec_free (locator_set_name); + unformat_free (line_input); + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_nsh_set_locator_set_command) = { + .path = "one nsh-mapping", + .short_help = "one nsh-mapping [del] ls ", + .function = lisp_nsh_set_locator_set_command_fn, +}; +/* *INDENT-ON* */ + static clib_error_t * lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm, @@ -923,7 +979,7 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ pool_foreach (mapit, lcm->mapping_pool, ({ - if (mapit->pitr_set) + if (mapit->pitr_set || mapit->nsh_set) continue; locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool, diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c index 94703abc..52b939f0 100644 --- a/src/vnet/lisp-gpe/interface.c +++ b/src/vnet/lisp-gpe/interface.c @@ -742,7 +742,7 @@ lisp_gpe_del_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id) * @return sw_if_index. */ u32 -lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm) +vnet_lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm) { vnet_main_t *vnm = lgm->vnet_main; tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces; @@ -782,7 +782,7 @@ lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm) * */ void -lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm) +vnet_lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm) { tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces; uword *hip; @@ -851,7 +851,7 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, { if (is_add) { - if (~0 == lisp_gpe_add_nsh_iface (&lisp_gpe_main)) + if (~0 == vnet_lisp_gpe_add_nsh_iface (&lisp_gpe_main)) { error = clib_error_return (0, "NSH interface not created"); goto done; @@ -859,7 +859,7 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, } else { - lisp_gpe_del_nsh_iface (&lisp_gpe_main); + vnet_lisp_gpe_del_nsh_iface (&lisp_gpe_main); } goto done; } diff --git a/src/vnet/lisp-gpe/lisp_gpe.h b/src/vnet/lisp-gpe/lisp_gpe.h index 660f8a66..5eafdd55 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.h +++ b/src/vnet/lisp-gpe/lisp_gpe.h @@ -324,6 +324,9 @@ vnet_api_error_t vnet_lisp_stats_enable_disable (u8 enable); lisp_api_stats_t *vnet_lisp_get_stats (void); int vnet_lisp_flush_stats (void); int vnet_gpe_add_del_native_fwd_rpath (vnet_gpe_native_fwd_rpath_args_t * a); +u32 vnet_lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm); +void vnet_lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm); + #endif /* included_vnet_lisp_gpe_h */ /* diff --git a/src/vpp/api/test_client.c b/src/vpp/api/test_client.c index 231b3c18..844b9702 100644 --- a/src/vpp/api/test_client.c +++ b/src/vpp/api/test_client.c @@ -245,6 +245,7 @@ static void vl_api_ip_neighbor_add_del_reply_t_handler fformat (stdout, "ip neighbor add del reply %d\n", ntohl (mp->retval)); } +#if 0 static void vl_api_vnet_interface_counters_t_handler (vl_api_vnet_interface_counters_t * mp) @@ -332,6 +333,7 @@ vl_api_vnet_interface_counters_t_handler (vl_api_vnet_interface_counters_t * } } } +#endif /* Format an IP4 address. */ u8 * @@ -578,7 +580,6 @@ _(WANT_STATS_REPLY, want_stats_reply) \ _(WANT_OAM_EVENTS_REPLY, want_oam_events_reply) \ _(OAM_EVENT, oam_event) \ _(OAM_ADD_DEL_REPLY, oam_add_del_reply) \ -_(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ _(IP_ADD_DEL_ROUTE_REPLY, ip_add_del_route_reply) \ -- cgit 1.2.3-korg From 058799951d062bbbe4df8df101b4db5bc7797b8f Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Tue, 5 Sep 2017 15:46:09 +0200 Subject: LISP: support for neighbor discovery Change-Id: I0f1a051dd3b5786dc7c457bc6fc7ce4fcd0f530c Signed-off-by: Filip Tehlar --- src/vat/api_format.c | 233 +++++++++++++++++++++++++++++++++++++ src/vnet/lisp-cp/control.c | 236 +++++++++++++++++++++++++++++--------- src/vnet/lisp-cp/control.h | 8 ++ src/vnet/lisp-cp/gid_dictionary.c | 82 +++++++------ src/vnet/lisp-cp/gid_dictionary.h | 24 ++-- src/vnet/lisp-cp/lisp_types.c | 5 +- src/vnet/lisp-cp/lisp_types.h | 26 +++-- src/vnet/lisp-cp/one_api.c | 77 ++++++++++++- src/vnet/lisp-cp/one_cli.c | 36 ++++++ 9 files changed, 617 insertions(+), 110 deletions(-) (limited to 'src/vnet/lisp-cp/gid_dictionary.c') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index ff3354c9..520ae4f6 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -3392,6 +3392,71 @@ end: vam->result_ready = 1; } +static void + vl_api_one_ndp_entries_get_reply_t_handler + (vl_api_one_ndp_entries_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + print (vam->ofp, "%U -> %U", format_ip6_address, &mp->entries[i].ip6, + format_ethernet_address, mp->entries[i].mac); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_ndp_entries_get_reply_t_handler_json + (vl_api_one_ndp_entries_get_reply_t * mp) +{ + u8 *s = 0; + vat_main_t *vam = &vat_main; + vat_json_node_t *e = 0, root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + vl_api_one_ndp_entry_t *arp_entry; + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + e = vat_json_array_add (&root); + arp_entry = &mp->entries[i]; + + vat_json_init_object (e); + s = format (0, "%U", format_ethernet_address, arp_entry->mac); + vec_add1 (s, 0); + + vat_json_object_add_string_copy (e, "mac", s); + vec_free (s); + + s = format (0, "%U", format_ip6_address, &arp_entry->ip6); + vec_add1 (s, 0); + vat_json_object_add_string_copy (e, "ip6", s); + vec_free (s); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + static void vl_api_one_l2_arp_entries_get_reply_t_handler (vl_api_one_l2_arp_entries_get_reply_t * mp) @@ -3457,6 +3522,57 @@ end: vam->result_ready = 1; } +static void +vl_api_one_ndp_bd_get_reply_t_handler (vl_api_one_ndp_bd_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + { + print (vam->ofp, "%d", clib_net_to_host_u32 (mp->bridge_domains[i])); + } + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_ndp_bd_get_reply_t_handler_json + (vl_api_one_ndp_bd_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + vat_json_array_add_uint (&root, + clib_net_to_host_u32 (mp->bridge_domains[i])); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + static void vl_api_one_l2_arp_bd_get_reply_t_handler (vl_api_one_l2_arp_bd_get_reply_t * mp) @@ -4590,6 +4706,10 @@ static void vl_api_flow_classify_details_t_handler_json #define vl_api_one_l2_arp_entries_get_reply_t_endian vl_noop_handler #define vl_api_one_l2_arp_entries_get_reply_t_print vl_noop_handler #define vl_api_one_l2_arp_bd_get_reply_t_endian vl_noop_handler +#define vl_api_one_ndp_bd_get_reply_t_endian vl_noop_handler +#define vl_api_one_ndp_bd_get_reply_t_print vl_noop_handler +#define vl_api_one_ndp_entries_get_reply_t_print vl_noop_handler +#define vl_api_one_ndp_entries_get_reply_t_endian vl_noop_handler /* * Generate boilerplate reply handlers, which @@ -4706,6 +4826,7 @@ _(one_eid_table_add_del_map_reply) \ _(one_use_petr_reply) \ _(one_stats_enable_disable_reply) \ _(one_add_del_l2_arp_entry_reply) \ +_(one_add_del_ndp_entry_reply) \ _(one_stats_flush_reply) \ _(gpe_enable_disable_reply) \ _(gpe_set_encap_mode_reply) \ @@ -4950,6 +5071,9 @@ _(ONE_STATS_FLUSH_REPLY, one_stats_flush_reply) \ _(ONE_STATS_ENABLE_DISABLE_REPLY, one_stats_enable_disable_reply) \ _(SHOW_ONE_STATS_ENABLE_DISABLE_REPLY, \ show_one_stats_enable_disable_reply) \ +_(ONE_ADD_DEL_NDP_ENTRY_REPLY, one_add_del_ndp_entry_reply) \ +_(ONE_NDP_BD_GET_REPLY, one_ndp_bd_get_reply) \ +_(ONE_NDP_ENTRIES_GET_REPLY, one_ndp_entries_get_reply) \ _(ONE_ADD_DEL_L2_ARP_ENTRY_REPLY, one_add_del_l2_arp_entry_reply) \ _(ONE_L2_ARP_BD_GET_REPLY, one_l2_arp_bd_get_reply) \ _(ONE_L2_ARP_ENTRIES_GET_REPLY, one_l2_arp_entries_get_reply) \ @@ -15413,6 +15537,58 @@ api_show_one_rloc_probe_state (vat_main_t * vam) #define api_show_lisp_rloc_probe_state api_show_one_rloc_probe_state +static int +api_one_add_del_ndp_entry (vat_main_t * vam) +{ + vl_api_one_add_del_ndp_entry_t *mp; + unformat_input_t *input = vam->input; + u8 is_add = 1; + u8 mac_set = 0; + u8 bd_set = 0; + u8 ip_set = 0; + u8 mac[6] = { 0, }; + u8 ip6[16] = { 0, }; + u32 bd = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "mac %U", unformat_ethernet_address, mac)) + mac_set = 1; + else if (unformat (input, "ip %U", unformat_ip6_address, ip6)) + ip_set = 1; + else if (unformat (input, "bd %d", &bd)) + bd_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!bd_set || !ip_set || (!mac_set && is_add)) + { + errmsg ("Missing BD, IP or MAC!"); + return -99; + } + + M (ONE_ADD_DEL_NDP_ENTRY, mp); + mp->is_add = is_add; + clib_memcpy (mp->mac, mac, 6); + mp->bd = clib_host_to_net_u32 (bd); + clib_memcpy (mp->ip6, ip6, sizeof (mp->ip6)); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_one_add_del_l2_arp_entry (vat_main_t * vam) { @@ -15464,6 +15640,60 @@ api_one_add_del_l2_arp_entry (vat_main_t * vam) return ret; } +static int +api_one_ndp_bd_get (vat_main_t * vam) +{ + vl_api_one_ndp_bd_get_t *mp; + int ret; + + M (ONE_NDP_BD_GET, mp); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + +static int +api_one_ndp_entries_get (vat_main_t * vam) +{ + vl_api_one_ndp_entries_get_t *mp; + unformat_input_t *input = vam->input; + u8 bd_set = 0; + u32 bd = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "bd %d", &bd)) + bd_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!bd_set) + { + errmsg ("Expected bridge domain!"); + return -99; + } + + M (ONE_NDP_ENTRIES_GET, mp); + mp->bd = clib_host_to_net_u32 (bd); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_one_l2_arp_bd_get (vat_main_t * vam) { @@ -20411,6 +20641,9 @@ _(one_locator_set_dump, "[local | remote]") \ _(one_locator_dump, "ls_index | ls_name ") \ _(one_eid_table_dump, "[eid / | ] [vni] " \ "[local] | [remote]") \ +_(one_add_del_ndp_entry, "[del] mac bd ip6 ") \ +_(one_ndp_bd_get, "") \ +_(one_ndp_entries_get, "bd ") \ _(one_add_del_l2_arp_entry, "[del] mac bd ip4 ") \ _(one_l2_arp_bd_get, "") \ _(one_l2_arp_entries_get, "bd ") \ diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 74597a6b..7aa3b419 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -908,7 +908,11 @@ static void add_l2_arp_bd (BVT (clib_bihash_kv) * kvp, void *arg) { u32 **ht = arg; - u32 bd = (u32) kvp->key[0]; + u32 version = (u32) kvp->key[0]; + if (IP6 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); hash_set (ht[0], bd, 0); } @@ -918,8 +922,31 @@ vnet_lisp_l2_arp_bds_get (void) lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); u32 *bds = 0; - gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, - add_l2_arp_bd, &bds); + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_bd, &bds); + return bds; +} + +static void +add_ndp_bd (BVT (clib_bihash_kv) * kvp, void *arg) +{ + u32 **ht = arg; + u32 version = (u32) kvp->key[0]; + if (IP4 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); + hash_set (ht[0], bd, 0); +} + +u32 * +vnet_lisp_ndp_bds_get (void) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + u32 *bds = 0; + + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_ndp_bd, &bds); return bds; } @@ -927,15 +954,21 @@ typedef struct { void *vector; u32 bd; -} lisp_add_l2_arp_args_t; +} lisp_add_l2_arp_ndp_args_t; static void add_l2_arp_entry (BVT (clib_bihash_kv) * kvp, void *arg) { - lisp_add_l2_arp_args_t *a = arg; + lisp_add_l2_arp_ndp_args_t *a = arg; lisp_api_l2_arp_entry_t **vector = a->vector, e; - if ((u32) kvp->key[0] == a->bd) + u32 version = (u32) kvp->key[0]; + if (IP6 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); + + if (bd == a->bd) { mac_copy (e.mac, (void *) &kvp->value); e.ip4 = (u32) kvp->key[1]; @@ -948,13 +981,48 @@ vnet_lisp_l2_arp_entries_get_by_bd (u32 bd) { lisp_api_l2_arp_entry_t *entries = 0; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); - lisp_add_l2_arp_args_t a; + lisp_add_l2_arp_ndp_args_t a; + + a.vector = &entries; + a.bd = bd; + + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_entry, &a); + return entries; +} + +static void +add_ndp_entry (BVT (clib_bihash_kv) * kvp, void *arg) +{ + lisp_add_l2_arp_ndp_args_t *a = arg; + lisp_api_ndp_entry_t **vector = a->vector, e; + + u32 version = (u32) kvp->key[0]; + if (IP4 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); + + if (bd == a->bd) + { + mac_copy (e.mac, (void *) &kvp->value); + clib_memcpy (e.ip6, &kvp->key[1], 16); + vec_add1 (vector[0], e); + } +} + +lisp_api_ndp_entry_t * +vnet_lisp_ndp_entries_get_by_bd (u32 bd) +{ + lisp_api_ndp_entry_t *entries = 0; + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + lisp_add_l2_arp_ndp_args_t a; a.vector = &entries; a.bd = bd; - gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, - add_l2_arp_entry, &a); + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_ndp_entry, &a); return entries; } @@ -2236,7 +2304,9 @@ vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a) #define foreach_lisp_cp_lookup_error \ _(DROP, "drop") \ _(MAP_REQUESTS_SENT, "map-request sent") \ -_(ARP_REPLY_TX, "ARP replies sent") +_(ARP_REPLY_TX, "ARP replies sent") \ +_(NDP_NEIGHBOR_ADVERTISEMENT_TX, \ + "neighbor advertisement sent") static char *lisp_cp_lookup_error_strings[] = { #define _(sym,string) string, @@ -2255,7 +2325,7 @@ typedef enum typedef enum { LISP_CP_LOOKUP_NEXT_DROP, - LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX, + LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX, LISP_CP_LOOKUP_N_NEXT, } lisp_cp_lookup_next_t; @@ -3069,6 +3139,7 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, { ethernet_header_t *eh; u32 vni = 0; + icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt; memset (src, 0, sizeof (*src)); memset (dst, 0, sizeof (*dst)); @@ -3116,6 +3187,33 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, } else { + if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_IP6) + { + ip6_header_t *ip; + ip = (ip6_header_t *) (eh + 1); + + if (IP_PROTOCOL_ICMP6 == ip->protocol) + { + icmp6_neighbor_solicitation_or_advertisement_header_t *ndh; + ndh = ip6_next_header (ip); + if (ndh->icmp.type == ICMP6_neighbor_solicitation) + { + opt = (void *) (ndh + 1); + if ((opt->header.type != + ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) + || (opt->header.n_data_u64s != 1)) + return; /* source link layer address option not present */ + + gid_address_type (dst) = GID_ADDR_NDP; + gid_address_ndp_bd (dst) = + lisp_get_bd_from_buffer_eth (b); + ip_address_set (&gid_address_arp_ndp_ip (dst), + &ndh->target_address, IP6); + return; + } + } + } + gid_address_type (src) = GID_ADDR_MAC; gid_address_type (dst) = GID_ADDR_MAC; mac_copy (&gid_address_mac (src), eh->src_address); @@ -3151,6 +3249,7 @@ lisp_cp_lookup_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, int overlay) { + icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt; u32 *from, *to_next, di, si; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); u32 pkts_mapped = 0, next_index; @@ -3174,6 +3273,9 @@ lisp_cp_lookup_inline (vlib_main_t * vm, ethernet_arp_header_t *arp0; ethernet_header_t *eth0; vnet_hw_interface_t *hw_if0; + ethernet_header_t *eh0; + icmp6_neighbor_solicitation_or_advertisement_header_t *ndh; + ip6_header_t *ip0; pi0 = from[0]; from += 1; @@ -3190,41 +3292,70 @@ lisp_cp_lookup_inline (vlib_main_t * vm, if (gid_address_type (&dst) == GID_ADDR_ARP) { mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst); - if (GID_LOOKUP_MISS_L2 != mac0) - { - /* send ARP reply */ - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; - - hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); - - eth0 = vlib_buffer_get_current (b0); - arp0 = (ethernet_arp_header_t *) (((u8 *) eth0) - + sizeof (*eth0)); - arp0->opcode = - clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply); - arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0]; - clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, - (u8 *) & mac0, 6); - clib_memcpy (&arp0->ip4_over_ethernet[0].ip4, - &gid_address_arp_ip4 (&dst), 4); - - /* Hardware must be ethernet-like. */ - ASSERT (vec_len (hw_if0->hw_address) == 6); - - clib_memcpy (eth0->dst_address, eth0->src_address, 6); - clib_memcpy (eth0->src_address, hw_if0->hw_address, 6); - - b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX]; - next0 = LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX; - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, - n_left_to_next, pi0, - next0); - continue; - } - goto done; + if (GID_LOOKUP_MISS_L2 == mac0) + goto drop; + + /* send ARP reply */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; + + hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); + + eth0 = vlib_buffer_get_current (b0); + arp0 = (ethernet_arp_header_t *) (((u8 *) eth0) + + sizeof (*eth0)); + arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply); + arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0]; + clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, + (u8 *) & mac0, 6); + clib_memcpy (&arp0->ip4_over_ethernet[0].ip4, + &gid_address_arp_ip4 (&dst), 4); + + /* Hardware must be ethernet-like. */ + ASSERT (vec_len (hw_if0->hw_address) == 6); + + clib_memcpy (eth0->dst_address, eth0->src_address, 6); + clib_memcpy (eth0->src_address, hw_if0->hw_address, 6); + + b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX]; + next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX; + goto enqueue; + } + else if (gid_address_type (&dst) == GID_ADDR_NDP) + { + mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst); + if (GID_LOOKUP_MISS_L2 == mac0) + goto drop; + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; + + eh0 = vlib_buffer_get_current (b0); + ip0 = (ip6_header_t *) (eh0 + 1); + ndh = ip6_next_header (ip0); + int bogus_length; + ip0->dst_address = ip0->src_address; + ip0->src_address = ndh->target_address; + ip0->hop_limit = 255; + opt = (void *) (ndh + 1); + opt->header.type = + ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address; + clib_memcpy (opt->ethernet_address, (u8 *) & mac0, 6); + ndh->icmp.type = ICMP6_neighbor_advertisement; + ndh->advertisement_flags = clib_host_to_net_u32 + (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED | + ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE); + ndh->icmp.checksum = 0; + ndh->icmp.checksum = + ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, + &bogus_length); + clib_memcpy (eh0->dst_address, eh0->src_address, 6); + clib_memcpy (eh0->src_address, (u8 *) & mac0, 6); + b0->error = + node->errors + [LISP_CP_LOOKUP_ERROR_NDP_NEIGHBOR_ADVERTISEMENT_TX]; + next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX; + goto enqueue; } /* if we have remote mapping for destination already in map-chache @@ -3267,8 +3398,10 @@ lisp_cp_lookup_inline (vlib_main_t * vm, pkts_mapped++; } - done: + drop: b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; + next0 = LISP_CP_LOOKUP_NEXT_DROP; + enqueue: if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0, @@ -3281,7 +3414,6 @@ lisp_cp_lookup_inline (vlib_main_t * vm, } gid_address_free (&dst); gid_address_free (&src); - next0 = LISP_CP_LOOKUP_NEXT_DROP; vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, next0); @@ -3339,7 +3471,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3359,7 +3491,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3379,7 +3511,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3399,7 +3531,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h index 12bfcb51..d40f6f53 100644 --- a/src/vnet/lisp-cp/control.h +++ b/src/vnet/lisp-cp/control.h @@ -103,6 +103,12 @@ typedef struct u32 ip4; } lisp_api_l2_arp_entry_t; +typedef struct +{ + u8 mac[6]; + u8 ip6[16]; +} lisp_api_ndp_entry_t; + typedef enum { MR_MODE_DST_ONLY = 0, @@ -395,6 +401,8 @@ int vnet_lisp_map_register_set_ttl (u32 ttl); u32 vnet_lisp_map_register_get_ttl (void); int vnet_lisp_map_register_fallback_threshold_set (u32 value); u32 vnet_lisp_map_register_fallback_threshold_get (void); +u32 *vnet_lisp_ndp_bds_get (void); +lisp_api_ndp_entry_t *vnet_lisp_ndp_entries_get_by_bd (u32 bd); map_records_arg_t *parse_map_reply (vlib_buffer_t * b); diff --git a/src/vnet/lisp-cp/gid_dictionary.c b/src/vnet/lisp-cp/gid_dictionary.c index cf9a741a..c3b93301 100644 --- a/src/vnet/lisp-cp/gid_dictionary.c +++ b/src/vnet/lisp-cp/gid_dictionary.c @@ -139,12 +139,13 @@ gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid, } void -gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb) - (BVT (clib_bihash_kv) * kvp, void *arg), - void *ht) +gid_dict_foreach_l2_arp_ndp_entry (gid_dictionary_t * db, void (*cb) + (BVT (clib_bihash_kv) * kvp, void *arg), + void *ht) { - gid_l2_arp_table_t *tab = &db->arp_table; - BV (clib_bihash_foreach_key_value_pair) (&tab->arp_lookup_table, cb, ht); + gid_l2_arp_ndp_table_t *tab = &db->arp_ndp_table; + BV (clib_bihash_foreach_key_value_pair) (&tab->arp_ndp_lookup_table, cb, + ht); } static void @@ -338,11 +339,19 @@ ip_sd_lookup (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst, } static void -make_arp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip4_address_t * addr) +make_arp_ndp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip_address_t * addr) { - kv->key[0] = (u64) bd; - kv->key[1] = (u64) addr->as_u32; - kv->key[2] = (u64) 0; + kv->key[0] = ((u64) bd << 32) | (u32) ip_addr_version (addr); + if (ip_addr_version (addr) == IP4) + { + kv->key[1] = (u64) addr->ip.v4.as_u32; + kv->key[2] = (u64) 0; + } + else + { + kv->key[1] = (u64) addr->ip.v6.as_u64[0]; + kv->key[2] = (u64) addr->ip.v6.as_u64[1]; + } } static void @@ -354,13 +363,14 @@ make_nsh_key (BVT (clib_bihash_kv) * kv, u32 vni, u32 spi, u8 si) } static u64 -arp_lookup (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key) +arp_ndp_lookup (gid_l2_arp_ndp_table_t * db, u32 bd, ip_address_t * key) { int rv; BVT (clib_bihash_kv) kv, value; - make_arp_key (&kv, bd, key); - rv = BV (clib_bihash_search_inline_2) (&db->arp_lookup_table, &kv, &value); + make_arp_ndp_key (&kv, bd, key); + rv = BV (clib_bihash_search_inline_2) (&db->arp_ndp_lookup_table, &kv, + &value); if (rv == 0) return value.value; @@ -414,8 +424,9 @@ gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) } break; case GID_ADDR_ARP: - return arp_lookup (&db->arp_table, gid_address_arp_bd (key), - &gid_address_arp_ip4 (key)); + case GID_ADDR_NDP: + return arp_ndp_lookup (&db->arp_ndp_table, gid_address_arp_ndp_bd (key), + &gid_address_arp_ndp_ip (key)); case GID_ADDR_NSH: return nsh_lookup (&db->nsh_table, gid_address_vni (key), gid_address_nsh_spi (key), gid_address_nsh_si (key)); @@ -890,25 +901,27 @@ add_del_sd (gid_dictionary_t * db, u32 vni, source_dest_t * key, u32 value, } static u64 -add_del_arp (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key, u64 value, - u8 is_add) +add_del_arp_ndp (gid_l2_arp_ndp_table_t * db, u32 bd, ip_address_t * key, + u64 value, u8 is_add) { BVT (clib_bihash_kv) kv, result; u32 old_val = ~0; - make_arp_key (&kv, bd, key); - if (BV (clib_bihash_search) (&db->arp_lookup_table, &kv, &result) == 0) + make_arp_ndp_key (&kv, bd, key); + if (BV (clib_bihash_search) (&db->arp_ndp_lookup_table, &kv, &result) == 0) old_val = result.value; if (is_add) { kv.value = value; - BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 1 /* is_add */ ); + BV (clib_bihash_add_del) (&db->arp_ndp_lookup_table, &kv, + 1 /* is_add */ ); db->count++; } else { - BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 0 /* is_add */ ); + BV (clib_bihash_add_del) (&db->arp_ndp_lookup_table, &kv, + 0 /* is_add */ ); db->count--; } return old_val; @@ -955,8 +968,10 @@ gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, return add_del_sd (db, gid_address_vni (key), &gid_address_sd (key), (u32) value, is_add); case GID_ADDR_ARP: - return add_del_arp (&db->arp_table, gid_address_arp_bd (key), - &gid_address_arp_ip4 (key), value, is_add); + case GID_ADDR_NDP: + return add_del_arp_ndp (&db->arp_ndp_table, + gid_address_arp_ndp_bd (key), + &gid_address_arp_ndp_ip (key), value, is_add); case GID_ADDR_NSH: return add_del_nsh (&db->nsh_table, gid_address_vni (key), gid_address_nsh_spi (key), gid_address_nsh_si (key), @@ -987,20 +1002,21 @@ mac_lookup_init (gid_mac_table_t * db) } static void -arp_lookup_init (gid_l2_arp_table_t * db) +arp_ndp_lookup_init (gid_l2_arp_ndp_table_t * db) { - if (db->arp_lookup_table_nbuckets == 0) - db->arp_lookup_table_nbuckets = ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; + if (db->arp_ndp_lookup_table_nbuckets == 0) + db->arp_ndp_lookup_table_nbuckets = + ARP_NDP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; - db->arp_lookup_table_nbuckets = - 1 << max_log2 (db->arp_lookup_table_nbuckets); + db->arp_ndp_lookup_table_nbuckets = + 1 << max_log2 (db->arp_ndp_lookup_table_nbuckets); - if (db->arp_lookup_table_size == 0) - db->arp_lookup_table_size = ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; + if (db->arp_ndp_lookup_table_size == 0) + db->arp_ndp_lookup_table_size = ARP_NDP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; - BV (clib_bihash_init) (&db->arp_lookup_table, "arp lookup table", - db->arp_lookup_table_nbuckets, - db->arp_lookup_table_size); + BV (clib_bihash_init) (&db->arp_ndp_lookup_table, "arp ndp lookup table", + db->arp_ndp_lookup_table_nbuckets, + db->arp_ndp_lookup_table_size); } static void @@ -1026,7 +1042,7 @@ gid_dictionary_init (gid_dictionary_t * db) ip4_lookup_init (&db->dst_ip4_table); ip6_lookup_init (&db->dst_ip6_table); mac_lookup_init (&db->sd_mac_table); - arp_lookup_init (&db->arp_table); + arp_ndp_lookup_init (&db->arp_ndp_table); nsh_lookup_init (&db->nsh_table); } diff --git a/src/vnet/lisp-cp/gid_dictionary.h b/src/vnet/lisp-cp/gid_dictionary.h index 51806bd6..3f8500e5 100644 --- a/src/vnet/lisp-cp/gid_dictionary.h +++ b/src/vnet/lisp-cp/gid_dictionary.h @@ -36,9 +36,9 @@ #define MAC_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) #define MAC_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) -/* Default size of the ARP hash table */ -#define ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) -#define ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) +/* Default size of the ARP/NDP hash table */ +#define ARP_NDP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define ARP_NDP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) /* Default size of the NSH hash table */ #define NSH_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) @@ -100,16 +100,16 @@ typedef struct gid_nsh_table typedef struct { - BVT (clib_bihash) arp_lookup_table; - u32 arp_lookup_table_nbuckets; - uword arp_lookup_table_size; + BVT (clib_bihash) arp_ndp_lookup_table; + u32 arp_ndp_lookup_table_nbuckets; + uword arp_ndp_lookup_table_size; u64 count; -} gid_l2_arp_table_t; +} gid_l2_arp_ndp_table_t; typedef struct { - /** L2 ARP table */ - gid_l2_arp_table_t arp_table; + /** L2 ARP/NDP table */ + gid_l2_arp_ndp_table_t arp_ndp_table; /** NSH lookup table */ gid_nsh_table_t nsh_table; @@ -146,9 +146,9 @@ gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid, foreach_subprefix_match_cb_t cb, void *arg); void -gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb) - (BVT (clib_bihash_kv) * kvp, void *arg), - void *ht); +gid_dict_foreach_l2_arp_ndp_entry (gid_dictionary_t * db, void (*cb) + (BVT (clib_bihash_kv) * kvp, void *arg), + void *ht); #endif /* VNET_LISP_GPE_GID_DICTIONARY_H_ */ diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index 622f39af..05f046fa 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -279,8 +279,9 @@ format_gid_address (u8 * s, va_list * args) return format (s, "[%d] %U", gid_address_vni (a), format_mac_address, &gid_address_mac (a)); case GID_ADDR_ARP: - return format (s, "[%d, %U]", gid_address_arp_bd (a), - format_ip4_address, &gid_address_arp_ip4 (a)); + case GID_ADDR_NDP: + return format (s, "[%d, %U]", gid_address_arp_ndp_bd (a), + format_ip_address, &gid_address_arp_ndp_ip (a)); case GID_ADDR_NSH: return format (s, "%U", format_nsh_address, &gid_address_nsh (a)); diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index b17110f6..4a919e79 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -91,6 +91,7 @@ typedef enum GID_ADDR_SRC_DST, GID_ADDR_NSH, GID_ADDR_ARP, + GID_ADDR_NDP, GID_ADDR_NO_ADDRESS, GID_ADDR_TYPES } gid_address_type_t; @@ -172,12 +173,15 @@ typedef struct typedef struct { - ip4_address_t addr; + ip_address_t addr; u32 bd; -} lcaf_arp_t; +} lcaf_arp_ndp_t; -#define lcaf_arp_ip4(_a) (_a)->addr -#define lcaf_arp_bd(_a) (_a)->bd +#define lcaf_arp_ndp_ip(_a) (_a)->addr +#define lcaf_arp_ndp_ip_ver(_a) ip_addr_version(&lcaf_arp_ndp_ip(_a)) +#define lcaf_arp_ndp_ip4(_a) ip_addr_v4(&lcaf_arp_ndp_ip(_a)) +#define lcaf_arp_ndp_ip6(_a) ip_addr_v6(&lcaf_arp_ndp_ip(_a)) +#define lcaf_arp_ndp_bd(_a) (_a)->bd typedef struct { @@ -185,7 +189,7 @@ typedef struct union { source_dest_t sd; - lcaf_arp_t arp; + lcaf_arp_ndp_t arp_ndp; vni_t uni; }; u8 type; @@ -204,7 +208,7 @@ typedef struct _gid_address_t lcaf_t lcaf; u8 mac[6]; source_dest_t sd; - lcaf_arp_t arp; + lcaf_arp_ndp_t arp_ndp; nsh_t nsh; }; u8 type; @@ -275,9 +279,13 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); #define gid_address_sd_dst(_a) sd_dst(&gid_address_sd(_a)) #define gid_address_sd_src_type(_a) sd_src_type(&gid_address_sd(_a)) #define gid_address_sd_dst_type(_a) sd_dst_type(&gid_address_sd(_a)) -#define gid_address_arp(_a) (_a)->arp -#define gid_address_arp_ip4(_a) lcaf_arp_ip4(&gid_address_arp (_a)) -#define gid_address_arp_bd(_a) lcaf_arp_bd(&gid_address_arp (_a)) +#define gid_address_arp_ndp(_a) (_a)->arp_ndp +#define gid_address_arp_ndp_bd(_a) lcaf_arp_ndp_bd(&gid_address_arp_ndp(_a)) +#define gid_address_arp_ndp_ip(_a) lcaf_arp_ndp_ip(&gid_address_arp_ndp(_a)) +#define gid_address_arp_ip4(_a) lcaf_arp_ndp_ip4(&gid_address_arp_ndp(_a)) +#define gid_address_ndp_ip6(_a) lcaf_arp_ndp_ip6(&gid_address_arp_ndp(_a)) +#define gid_address_ndp_bd gid_address_arp_ndp_bd +#define gid_address_arp_bd gid_address_arp_ndp_bd /* 'sub'address functions */ #define foreach_gid_address_type_fcns \ diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index 7c8ba63f..96b3d2c0 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -130,7 +130,9 @@ _(ONE_STATS_FLUSH, one_stats_flush) \ _(ONE_L2_ARP_BD_GET, one_l2_arp_bd_get) \ _(ONE_L2_ARP_ENTRIES_GET, one_l2_arp_entries_get) \ _(ONE_ADD_DEL_L2_ARP_ENTRY, one_add_del_l2_arp_entry) \ - +_(ONE_ADD_DEL_NDP_ENTRY, one_add_del_ndp_entry) \ +_(ONE_NDP_BD_GET, one_ndp_bd_get) \ +_(ONE_NDP_ENTRIES_GET, one_ndp_entries_get) \ static locator_t * unformat_one_locs (vl_api_one_remote_locator_t * rmt_locs, u32 rloc_num) @@ -1563,13 +1565,55 @@ static void gid_address_arp_bd (arp) = clib_net_to_host_u32 (mp->bd); /* vpp keeps ip4 addresses in network byte order */ - clib_memcpy (&gid_address_arp_ip4 (arp), &mp->ip4, 4); + ip_address_set (&gid_address_arp_ndp_ip (arp), &mp->ip4, IP4); rv = vnet_lisp_add_del_l2_arp_entry (arp, mp->mac, mp->is_add); REPLY_MACRO (VL_API_ONE_ADD_DEL_L2_ARP_ENTRY_REPLY); } +static void +vl_api_one_add_del_ndp_entry_t_handler (vl_api_one_add_del_ndp_entry_t * mp) +{ + vl_api_one_add_del_ndp_entry_reply_t *rmp; + int rv = 0; + gid_address_t _g, *g = &_g; + memset (g, 0, sizeof (*g)); + + gid_address_type (g) = GID_ADDR_NDP; + gid_address_ndp_bd (g) = clib_net_to_host_u32 (mp->bd); + ip_address_set (&gid_address_arp_ndp_ip (g), mp->ip6, IP6); + + rv = vnet_lisp_add_del_l2_arp_entry (g, mp->mac, mp->is_add); + + REPLY_MACRO (VL_API_ONE_ADD_DEL_NDP_ENTRY_REPLY); +} + +static void +vl_api_one_ndp_bd_get_t_handler (vl_api_one_ndp_bd_get_t * mp) +{ + vl_api_one_ndp_bd_get_reply_t *rmp; + int rv = 0; + u32 i = 0; + hash_pair_t *p; + + u32 *bds = vnet_lisp_ndp_bds_get (); + u32 size = hash_elts (bds) * sizeof (u32); + + /* *INDENT-OFF* */ + REPLY_MACRO4 (VL_API_ONE_NDP_BD_GET_REPLY, size, + { + rmp->count = clib_host_to_net_u32 (hash_elts (bds)); + hash_foreach_pair (p, bds, + ({ + rmp->bridge_domains[i++] = clib_host_to_net_u32 (p->key); + })); + }); + /* *INDENT-ON* */ + + hash_free (bds); +} + static void vl_api_one_l2_arp_bd_get_t_handler (vl_api_one_l2_arp_bd_get_t * mp) { @@ -1653,6 +1697,35 @@ static void /* *INDENT-ON* */ } +static void +vl_api_one_ndp_entries_get_t_handler (vl_api_one_ndp_entries_get_t * mp) +{ + vl_api_one_ndp_entries_get_reply_t *rmp = 0; + lisp_api_ndp_entry_t *entries = 0, *e; + u32 i = 0; + int rv = 0; + + u32 bd = clib_net_to_host_u32 (mp->bd); + + entries = vnet_lisp_ndp_entries_get_by_bd (bd); + u32 size = vec_len (entries) * sizeof (vl_api_one_ndp_entry_t); + + /* *INDENT-OFF* */ + REPLY_MACRO4 (VL_API_ONE_NDP_ENTRIES_GET_REPLY, size, + { + rmp->count = clib_host_to_net_u32 (vec_len (entries)); + vec_foreach (e, entries) + { + mac_copy (rmp->entries[i].mac, e->mac); + clib_memcpy (rmp->entries[i].ip6, e->ip6, 16); + i++; + } + }); + /* *INDENT-ON* */ + + vec_free (entries); +} + /* * one_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index 3e0c4c0a..1e52c9af 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -376,6 +376,42 @@ VLIB_CLI_COMMAND (one_show_l2_arp_entries_command) = { }; /* *INDENT-ON* */ +static clib_error_t * +lisp_show_ndp_entries_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u32 *ht = vnet_lisp_ndp_bds_get (); + lisp_api_ndp_entry_t *entries, *e; + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, ht, + ({ + entries = vnet_lisp_ndp_entries_get_by_bd (p->key); + vlib_cli_output (vm, "Table: %d", p->key); + + vec_foreach (e, entries) + { + vlib_cli_output (vm, "\t%U -> %U", format_ip6_address, &e->ip6, + format_mac_address, e->mac); + } + vec_free (entries); + })); + /* *INDENT-ON* */ + + hash_free (ht); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_show_ndp_entries_command) = { + .path = "show one ndp entries", + .short_help = "Show ONE NDP entries", + .function = lisp_show_ndp_entries_command_fn, +}; +/* *INDENT-ON* */ + /** * Handler for add/del remote mapping CLI. * -- cgit 1.2.3-korg