cnat: Add support for SNat ICMP
[vpp.git] / src / plugins / cnat / cnat_types.h
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #ifndef __CNAT_TYPES_H__
17 #define __CNAT_TYPES_H__
18
19 #include <vnet/fib/fib_node.h>
20 #include <vnet/fib/fib_source.h>
21 #include <vnet/ip/ip_types.h>
22 #include <vnet/ip/ip.h>
23
24 /* only in the default table for v4 and v6 */
25 #define CNAT_FIB_TABLE 0
26
27 /* default lifetime of NAT sessions (seconds) */
28 #define CNAT_DEFAULT_SESSION_MAX_AGE 30
29 /* lifetime of TCP conn NAT sessions after SYNACK (seconds) */
30 #define CNAT_DEFAULT_TCP_MAX_AGE 3600
31 /* lifetime of TCP conn NAT sessions after RST/FIN (seconds) */
32 #define CNAT_DEFAULT_TCP_RST_TIMEOUT 5
33 #define CNAT_DEFAULT_SCANNER_TIMEOUT (1.0)
34
35 #define CNAT_DEFAULT_SESSION_BUCKETS     1024
36 #define CNAT_DEFAULT_TRANSLATION_BUCKETS 1024
37 #define CNAT_DEFAULT_SNAT_BUCKETS        1024
38
39 #define CNAT_DEFAULT_SESSION_MEMORY      (1 << 20)
40 #define CNAT_DEFAULT_TRANSLATION_MEMORY  (256 << 10)
41 #define CNAT_DEFAULT_SNAT_MEMORY         (64 << 20)
42
43 /* This should be strictly lower than FIB_SOURCE_INTERFACE
44  * from fib_source.h */
45 #define CNAT_FIB_SOURCE_PRIORITY  0x02
46
47 /* Initial refcnt for timestamps (2 : session & rsession) */
48 #define CNAT_TIMESTAMP_INIT_REFCNT 2
49
50 #define MIN_SRC_PORT ((u16) 0xC000)
51
52 typedef enum
53 {
54   CNAT_SPORT_PROTO_TCP,
55   CNAT_SPORT_PROTO_UDP,
56   CNAT_SPORT_PROTO_ICMP,
57   CNAT_SPORT_PROTO_ICMP6,
58   CNAT_N_SPORT_PROTO
59 } cnat_sport_proto_t;
60
61 typedef struct cnat_endpoint_t_
62 {
63   ip_address_t ce_ip;
64   u16 ce_port;
65 } cnat_endpoint_t;
66
67 typedef struct cnat_endpoint_tuple_t_
68 {
69   cnat_endpoint_t dst_ep;
70   cnat_endpoint_t src_ep;
71 } cnat_endpoint_tuple_t;
72
73 typedef struct
74 {
75   u16 identifier;
76   u16 sequence;
77 } cnat_echo_header_t;
78
79 typedef struct
80 {
81   u32 dst_address_length_refcounts[129];
82   u16 *prefix_lengths_in_search_order;
83   uword *non_empty_dst_address_length_bitmap;
84 } cnat_snat_pfx_table_meta_t;
85
86 typedef struct
87 {
88   /* Stores (ip family, prefix & mask) */
89   clib_bihash_24_8_t ip_hash;
90   /* family dependant cache */
91   cnat_snat_pfx_table_meta_t meta[2];
92   /* Precomputed ip masks (ip4 & ip6) */
93   ip6_address_t ip_masks[129];
94 } cnat_snat_pfx_table_t;
95
96 typedef struct cnat_src_port_allocator_
97 {
98   /* Source ports bitmap for snat */
99   clib_bitmap_t *bmap;
100
101   /* Lock for src_ports access */
102   clib_spinlock_t lock;
103 } cnat_src_port_allocator_t;
104
105 typedef struct cnat_main_
106 {
107   /* Memory size of the session bihash */
108   uword session_hash_memory;
109
110   /* Number of buckets of the  session bihash */
111   u32 session_hash_buckets;
112
113   /* Memory size of the translation bihash */
114   uword translation_hash_memory;
115
116   /* Number of buckets of the  translation bihash */
117   u32 translation_hash_buckets;
118
119   /* Memory size of the source NAT prefix bihash */
120   uword snat_hash_memory;
121
122   /* Number of buckets of the  source NAT prefix bihash */
123   u32 snat_hash_buckets;
124
125   /* Timeout after which to clear sessions (in seconds) */
126   u32 session_max_age;
127
128   /* Timeout after which to clear an established TCP
129    * session (in seconds) */
130   u32 tcp_max_age;
131
132   /* delay in seconds between two scans of session/clients tables */
133   f64 scanner_timeout;
134
135   /* Lock for the timestamp pool */
136   clib_rwlock_t ts_lock;
137
138   /* Per proto source ports allocator for snat */
139   cnat_src_port_allocator_t *src_ports;
140
141   /* Ip4 Address to use for source NATing */
142   ip4_address_t snat_ip4;
143
144   /* Ip6 Address to use for source NATing */
145   ip6_address_t snat_ip6;
146
147   /* Longest prefix Match table for source NATing */
148   cnat_snat_pfx_table_t snat_pfx_table;
149
150   /* Index of the scanner process node */
151   uword scanner_node_index;
152
153   /* Did we do lazy init ? */
154   u8 lazy_init_done;
155
156   /* Enable or Disable the scanner on startup */
157   u8 default_scanner_state;
158 } cnat_main_t;
159
160 typedef struct cnat_timestamp_t_
161 {
162   /* Last time said session was seen */
163   f64 last_seen;
164   /* expire after N seconds */
165   u16 lifetime;
166   /* Users refcount, initially 3 (session, rsession, dpo) */
167   u16 refcnt;
168 } cnat_timestamp_t;
169
170 typedef struct cnat_node_ctx_t_
171 {
172   f64 now;
173   u64 seed;
174   u32 thread_index;
175   ip_address_family_t af;
176   u8 do_trace;
177 } cnat_node_ctx_t;
178
179 extern u8 *format_cnat_endpoint (u8 * s, va_list * args);
180 extern uword unformat_cnat_ep_tuple (unformat_input_t * input,
181                                      va_list * args);
182 extern uword unformat_cnat_ep (unformat_input_t * input, va_list * args);
183 extern cnat_timestamp_t *cnat_timestamps;
184 extern fib_source_t cnat_fib_source;
185 extern cnat_main_t cnat_main;
186 extern throttle_t cnat_throttle;
187
188 extern char *cnat_error_strings[];
189
190 typedef enum
191 {
192 #define cnat_error(n,s) CNAT_ERROR_##n,
193 #include <cnat/cnat_error.def>
194 #undef cnat_error
195   CNAT_N_ERROR,
196 } cnat_error_t;
197
198 typedef enum cnat_scanner_cmd_t_
199 {
200   CNAT_SCANNER_OFF,
201   CNAT_SCANNER_ON,
202 } cnat_scanner_cmd_t;
203
204 /**
205  * Lazy initialization when first adding a translation
206  * or using snat
207  */
208 extern void cnat_lazy_init ();
209
210 /**
211  * Enable/Disable session cleanup
212  */
213 extern void cnat_enable_disable_scanner (cnat_scanner_cmd_t event_type);
214
215 /*
216   Dataplane functions
217 */
218
219 always_inline u32
220 cnat_timestamp_new (f64 t)
221 {
222   u32 index;
223   cnat_timestamp_t *ts;
224   clib_rwlock_writer_lock (&cnat_main.ts_lock);
225   pool_get (cnat_timestamps, ts);
226   ts->last_seen = t;
227   ts->lifetime = cnat_main.session_max_age;
228   ts->refcnt = CNAT_TIMESTAMP_INIT_REFCNT;
229   index = ts - cnat_timestamps;
230   clib_rwlock_writer_unlock (&cnat_main.ts_lock);
231   return index;
232 }
233
234 always_inline void
235 cnat_timestamp_inc_refcnt (u32 index)
236 {
237   clib_rwlock_reader_lock (&cnat_main.ts_lock);
238   cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index);
239   ts->refcnt++;
240   clib_rwlock_reader_unlock (&cnat_main.ts_lock);
241 }
242
243 always_inline void
244 cnat_timestamp_update (u32 index, f64 t)
245 {
246   clib_rwlock_reader_lock (&cnat_main.ts_lock);
247   cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index);
248   ts->last_seen = t;
249   clib_rwlock_reader_unlock (&cnat_main.ts_lock);
250 }
251
252 always_inline void
253 cnat_timestamp_set_lifetime (u32 index, u16 lifetime)
254 {
255   clib_rwlock_reader_lock (&cnat_main.ts_lock);
256   cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index);
257   ts->lifetime = lifetime;
258   clib_rwlock_reader_unlock (&cnat_main.ts_lock);
259 }
260
261 always_inline f64
262 cnat_timestamp_exp (u32 index)
263 {
264   f64 t;
265   if (INDEX_INVALID == index)
266     return -1;
267   clib_rwlock_reader_lock (&cnat_main.ts_lock);
268   cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index);
269   t = ts->last_seen + (f64) ts->lifetime;
270   clib_rwlock_reader_unlock (&cnat_main.ts_lock);
271   return t;
272 }
273
274 always_inline void
275 cnat_timestamp_free (u32 index)
276 {
277   if (INDEX_INVALID == index)
278     return;
279   clib_rwlock_writer_lock (&cnat_main.ts_lock);
280   cnat_timestamp_t *ts = pool_elt_at_index (cnat_timestamps, index);
281   ts->refcnt--;
282   if (0 == ts->refcnt)
283     pool_put (cnat_timestamps, ts);
284   clib_rwlock_writer_unlock (&cnat_main.ts_lock);
285 }
286
287 always_inline cnat_src_port_allocator_t *
288 cnat_get_src_port_allocator (ip_protocol_t iproto)
289 {
290   cnat_main_t *cm = &cnat_main;
291   switch (iproto)
292     {
293     case IP_PROTOCOL_TCP:
294       return &cm->src_ports[CNAT_SPORT_PROTO_TCP];
295     case IP_PROTOCOL_UDP:
296       return &cm->src_ports[CNAT_SPORT_PROTO_UDP];
297     case IP_PROTOCOL_ICMP:
298       return &cm->src_ports[CNAT_SPORT_PROTO_ICMP];
299     case IP_PROTOCOL_ICMP6:
300       return &cm->src_ports[CNAT_SPORT_PROTO_ICMP6];
301     default:
302       return 0;
303     }
304 }
305
306 always_inline void
307 cnat_free_port (u16 port, ip_protocol_t iproto)
308 {
309   cnat_src_port_allocator_t *ca;
310   ca = cnat_get_src_port_allocator (iproto);
311   if (!ca)
312     return;
313   clib_spinlock_lock (&ca->lock);
314   clib_bitmap_set_no_check (ca->bmap, port, 0);
315   clib_spinlock_unlock (&ca->lock);
316 }
317
318 always_inline int
319 cnat_allocate_port (u16 * port, ip_protocol_t iproto)
320 {
321   *port = clib_net_to_host_u16 (*port);
322   if (*port == 0)
323     *port = MIN_SRC_PORT;
324   cnat_src_port_allocator_t *ca;
325   ca = cnat_get_src_port_allocator (iproto);
326   if (!ca)
327     return -1;
328   clib_spinlock_lock (&ca->lock);
329   if (clib_bitmap_get_no_check (ca->bmap, *port))
330     {
331       *port = clib_bitmap_next_clear (ca->bmap, *port);
332       if (PREDICT_FALSE (*port >= UINT16_MAX))
333         *port = clib_bitmap_next_clear (ca->bmap, MIN_SRC_PORT);
334       if (PREDICT_FALSE (*port >= UINT16_MAX))
335         return -1;
336     }
337   clib_bitmap_set_no_check (ca->bmap, *port, 1);
338   *port = clib_host_to_net_u16 (*port);
339   clib_spinlock_unlock (&ca->lock);
340   return 0;
341 }
342
343 /*
344  * fd.io coding-style-patch-verification: ON
345  *
346  * Local Variables:
347  * eval: (c-set-style "gnu")
348  * End:
349  */
350
351 #endif