/* * Copyright (c) 2020 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef included_ip_vtep_h #define included_ip_vtep_h #include <vppinfra/hash.h> #include <vnet/ip/ip.h> #include <vnet/ip/ip46_address.h> /** * @brief Tunnel endpoint key (IPv4) * * Tunnel modules maintain a set of vtep4_key_t-s to track local IP * addresses that have tunnels established. Bypass node consults the * corresponding set to decide whether a packet should bypass normal * processing and go directly to the tunnel protocol handler node. */ /* *INDENT-OFF* */ typedef CLIB_PACKED (struct { union { struct { ip4_address_t addr; u32 fib_index; }; u64 as_u64; }; }) vtep4_key_t; /* *INDENT-ON* */ /** * @brief Tunnel endpoint key (IPv6) * * Tunnel modules maintain a set of vtep6_key_t-s to track local IP * addresses that have tunnels established. Bypass node consults the * corresponding set to decide whether a packet should bypass normal * processing and go directly to the tunnel protocol handler node. */ /* *INDENT-OFF* */ typedef CLIB_PACKED (struct { ip6_address_t addr; u32 fib_index; }) vtep6_key_t; /* *INDENT-ON* */ typedef struct { uword *vtep4; /* local ip4 VTEPs keyed on their ip4 addr + fib_index */ uword *vtep6; /* local ip6 VTEPs keyed on their ip6 addr + fib_index */ } vtep_table_t; always_inline vtep_table_t vtep_table_create () { vtep_table_t t = { }; t.vtep6 = hash_create_mem (0, sizeof (vtep6_key_t), sizeof (uword)); return t; } uword vtep_addr_ref (vtep_table_t * t, u32 fib_index, ip46_address_t * ip); uword vtep_addr_unref (vtep_table_t * t, u32 fib_index, ip46_address_t * ip); always_inline void vtep4_key_init (vtep4_key_t * k4) { k4->as_u64 = ~((u64) 0); } always_inline void vtep6_key_init (vtep6_key_t * k6) { ip6_address_set_zero (&k6->addr); k6->fib_index = (u32) ~ 0; } enum { VTEP_CHECK_FAIL = 0, VTEP_CHECK_PASS = 1, VTEP_CHECK_PASS_UNCHANGED = 2 }; always_inline u8 vtep4_check (vtep_table_t * t, vlib_buffer_t * b0, ip4_header_t * ip40, vtep4_key_t * last_k4) { vtep4_key_t k4; k4.addr.as_u32 = ip40->dst_address.as_u32; k4.fib_index = vlib_buffer_get_ip4_fib_index (b0); if (PREDICT_TRUE (k4.as_u64 == last_k4->as_u64)) return VTEP_CHECK_PASS_UNCHANGED; if (PREDICT_FALSE (!hash_get (t->vtep4, k4.as_u64))) return VTEP_CHECK_FAIL; last_k4->as_u64 = k4.as_u64; return VTEP_CHECK_PASS; } #ifdef CLIB_HAVE_VEC512 typedef struct { vtep4_key_t vtep4_cache[8]; int idx; } vtep4_cache_t; always_inline u8 vtep4_check_vector (vtep_table_t * t, vlib_buffer_t * b0, ip4_header_t * ip40, vtep4_key_t * last_k4, vtep4_cache_t * vtep4_u512) { vtep4_key_t k4; k4.addr.as_u32 = ip40->dst_address.as_u32; k4.fib_index = vlib_buffer_get_ip4_fib_index (b0); if (PREDICT_TRUE (k4.as_u64 == last_k4->as_u64)) return VTEP_CHECK_PASS_UNCHANGED; u64x8 k4_u64x8 = u64x8_splat (k4.as_u64); u64x8 cache = u64x8_load_unaligned (vtep4_u512->vtep4_cache); u8 result = u64x8_is_equal_mask (cache, k4_u64x8); if (PREDICT_TRUE (result != 0)) { last_k4->as_u64 = vtep4_u512->vtep4_cache[count_trailing_zeros (result)].as_u64; return VTEP_CHECK_PASS_UNCHANGED; } if (PREDICT_FALSE (!hash_get (t->vtep4, k4.as_u64))) return VTEP_CHECK_FAIL; vtep4_u512->vtep4_cache[vtep4_u512->idx].as_u64 = k4.as_u64; vtep4_u512->idx = (vtep4_u512->idx + 1) & 0x7; last_k4->as_u64 = k4.as_u64; return VTEP_CHECK_PASS; } #endif always_inline u8 vtep6_check (vtep_table_t * t, vlib_buffer_t * b0, ip6_header_t * ip60, vtep6_key_t * last_k6) { vtep6_key_t k6; k6.fib_index = vlib_buffer_get_ip6_fib_index (b0); if (PREDICT_TRUE (k6.fib_index == last_k6->fib_index && ip60->dst_address.as_u64[0] == last_k6->addr.as_u64[0] && ip60->dst_address.as_u64[1] == last_k6->addr.as_u64[1])) { return VTEP_CHECK_PASS_UNCHANGED; } k6.addr = ip60->dst_address; if (PREDICT_FALSE (!hash_get_mem (t->vtep6, &k6))) return VTEP_CHECK_FAIL; *last_k6 = k6; return VTEP_CHECK_PASS; } #endif /* included_ip_vtep_h */ /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */