From 29f3c7d2ecac2f9d80bb33e91bd5d1f9d434768a Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 19 May 2020 07:17:19 +0000 Subject: cnat: Destination based NAT Type: feature Signed-off-by: Neale Ranns Change-Id: I64a99a4fbc674212944247793fd5c1fb701408cb --- src/plugins/cnat/cnat_types.h | 281 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 src/plugins/cnat/cnat_types.h (limited to 'src/plugins/cnat/cnat_types.h') diff --git a/src/plugins/cnat/cnat_types.h b/src/plugins/cnat/cnat_types.h new file mode 100644 index 00000000000..8659aa5e9fd --- /dev/null +++ b/src/plugins/cnat/cnat_types.h @@ -0,0 +1,281 @@ +/* + * 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 __CNAT_TYPES_H__ +#define __CNAT_TYPES_H__ + +#include +#include +#include +#include + +/* only in the default table for v4 and v6 */ +#define CNAT_FIB_TABLE 0 + +/* default lifetime of NAT sessions (seconds) */ +#define CNAT_DEFAULT_SESSION_MAX_AGE 30 +/* lifetime of TCP conn NAT sessions after SYNACK (seconds) */ +#define CNAT_DEFAULT_TCP_MAX_AGE 3600 +/* lifetime of TCP conn NAT sessions after RST/FIN (seconds) */ +#define CNAT_DEFAULT_TCP_RST_TIMEOUT 5 +#define CNAT_DEFAULT_SCANNER_TIMEOUT (1.0) + +#define CNAT_DEFAULT_SESSION_BUCKETS 1024 +#define CNAT_DEFAULT_TRANSLATION_BUCKETS 1024 +#define CNAT_DEFAULT_SNAT_BUCKETS 1024 + +#define CNAT_DEFAULT_SESSION_MEMORY (1 << 20) +#define CNAT_DEFAULT_TRANSLATION_MEMORY (256 << 10) +#define CNAT_DEFAULT_SNAT_MEMORY (64 << 20) + +/* This should be strictly lower than FIB_SOURCE_INTERFACE + * from fib_source.h */ +#define CNAT_FIB_SOURCE_PRIORITY 0x02 + +/* Initial refcnt for timestamps (2 : session & rsession) */ +#define CNAT_TIMESTAMP_INIT_REFCNT 2 + +#define MIN_SRC_PORT ((u16) 0xC000) + +typedef struct cnat_endpoint_t_ +{ + ip_address_t ce_ip; + u16 ce_port; +} cnat_endpoint_t; + +typedef struct cnat_endpoint_tuple_t_ +{ + cnat_endpoint_t dst_ep; + cnat_endpoint_t src_ep; +} cnat_endpoint_tuple_t; + + + +typedef struct +{ + u32 dst_address_length_refcounts[129]; + u16 *prefix_lengths_in_search_order; + uword *non_empty_dst_address_length_bitmap; +} cnat_snat_pfx_table_meta_t; + +typedef struct +{ + /* Stores (ip family, prefix & mask) */ + clib_bihash_24_8_t ip_hash; + /* family dependant cache */ + cnat_snat_pfx_table_meta_t meta[2]; + /* Precomputed ip masks (ip4 & ip6) */ + ip6_address_t ip_masks[129]; +} cnat_snat_pfx_table_t; + +typedef struct cnat_main_ +{ + /* Memory size of the session bihash */ + uword session_hash_memory; + + /* Number of buckets of the session bihash */ + u32 session_hash_buckets; + + /* Memory size of the translation bihash */ + uword translation_hash_memory; + + /* Number of buckets of the translation bihash */ + u32 translation_hash_buckets; + + /* Memory size of the source NAT prefix bihash */ + uword snat_hash_memory; + + /* Number of buckets of the source NAT prefix bihash */ + u32 snat_hash_buckets; + + /* Timeout after which to clear sessions (in seconds) */ + u32 session_max_age; + + /* Timeout after which to clear an established TCP + * session (in seconds) */ + u32 tcp_max_age; + + /* delay in seconds between two scans of session/clients tables */ + f64 scanner_timeout; + + /* Lock for the timestamp pool */ + clib_rwlock_t ts_lock; + + /* Source ports bitmap for snat */ + clib_bitmap_t *src_ports; + + /* Lock for src_ports access */ + clib_spinlock_t src_ports_lock; + + /* Ip4 Address to use for source NATing */ + ip4_address_t snat_ip4; + + /* Ip6 Address to use for source NATing */ + ip6_address_t snat_ip6; + + /* Longest prefix Match table for source NATing */ + cnat_snat_pfx_table_t snat_pfx_table; +} cnat_main_t; + +typedef struct cnat_timestamp_t_ +{ + /* Last time said session was seen */ + f64 last_seen; + /* expire after N seconds */ + u16 lifetime; + /* Users refcount, initially 3 (session, rsession, dpo) */ + u16 refcnt; +} cnat_timestamp_t; + +typedef struct cnat_node_ctx_t_ +{ + f64 now; + u64 seed; + u32 thread_index; + ip_address_family_t af; + u8 do_trace; +} cnat_node_ctx_t; + +extern u8 *format_cnat_endpoint (u8 * s, va_list * args); +extern uword unformat_cnat_ep_tuple (unformat_input_t * input, + va_list * args); +extern uword unformat_cnat_ep (unformat_input_t * input, va_list * args); +extern cnat_timestamp_t *cnat_timestamps; +extern fib_source_t cnat_fib_source; +extern cnat_main_t cnat_main; +extern throttle_t cnat_throttle; + +extern char *cnat_error_strings[]; + +typedef enum +{ +#define cnat_error(n,s) CNAT_ERROR_##n, +#include +#undef cnat_error + CNAT_N_ERROR, +} cnat_error_t; + +/* + Dataplane functions +*/ + +always_inline u32 +cnat_timestamp_new (f64 t) +{ + u32 index; + cnat_timestamp_t *ts; + clib_rwlock_writer_lock (&cnat_main.ts_lock); + pool_get (cnat_timestamps, ts); + ts->last_seen = t; + ts->lifetime = cnat_main.session_max_age; + ts->refcnt = CNAT_TIMESTAMP_INIT_REFCNT; + index = ts - cnat_timestamps; + clib_rwlock_writer_unlock (&cnat_main.ts_lock); + return index; +} + +always_inline void +cnat_timestamp_inc_refcnt (u32 index) +{ + clib_rwlock_reader_lock (&cnat_main.ts_lock); + cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index); + ts->refcnt++; + clib_rwlock_reader_unlock (&cnat_main.ts_lock); +} + +always_inline void +cnat_timestamp_update (u32 index, f64 t) +{ + return; + clib_rwlock_reader_lock (&cnat_main.ts_lock); + cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index); + ts->last_seen = t; + clib_rwlock_reader_unlock (&cnat_main.ts_lock); +} + +always_inline void +cnat_timestamp_set_lifetime (u32 index, u16 lifetime) +{ + clib_rwlock_reader_lock (&cnat_main.ts_lock); + cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index); + ts->lifetime = lifetime; + clib_rwlock_reader_unlock (&cnat_main.ts_lock); +} + +always_inline f64 +cnat_timestamp_exp (u32 index) +{ + f64 t; + if (INDEX_INVALID == index) + return -1; + clib_rwlock_reader_lock (&cnat_main.ts_lock); + cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index); + t = ts->last_seen + (f64) ts->lifetime; + clib_rwlock_reader_unlock (&cnat_main.ts_lock); + return t; +} + +always_inline void +cnat_timestamp_free (u32 index) +{ + if (INDEX_INVALID == index) + return; + clib_rwlock_writer_lock (&cnat_main.ts_lock); + cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index); + ts->refcnt--; + if (0 == ts->refcnt) + pool_put (cnat_timestamps, ts); + clib_rwlock_writer_unlock (&cnat_main.ts_lock); +} + +always_inline void +cnat_free_port (u16 port) +{ + cnat_main_t *cm = &cnat_main; + clib_spinlock_lock (&cm->src_ports_lock); + clib_bitmap_set_no_check (cm->src_ports, port, 0); + clib_spinlock_unlock (&cm->src_ports_lock); +} + +always_inline int +cnat_allocate_port (cnat_main_t * cm, u16 * port) +{ + *port = clib_net_to_host_u16 (*port); + if (*port == 0) + *port = MIN_SRC_PORT; + clib_spinlock_lock (&cm->src_ports_lock); + if (clib_bitmap_get_no_check (cm->src_ports, *port)) + { + *port = clib_bitmap_next_clear (cm->src_ports, *port); + if (PREDICT_FALSE (*port >= UINT16_MAX)) + *port = clib_bitmap_next_clear (cm->src_ports, MIN_SRC_PORT); + if (PREDICT_FALSE (*port >= UINT16_MAX)) + return -1; + } + clib_bitmap_set_no_check (cm->src_ports, *port, 1); + *port = clib_host_to_net_u16 (*port); + clib_spinlock_unlock (&cm->src_ports_lock); + return 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ + +#endif -- cgit 1.2.3-korg