aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/cnat/cnat_types.h
blob: d81548d0c30d5d29049a971f6afce1ad7e1a7548 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
 * 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 <vnet/fib/fib_node.h>
#include <vnet/fib/fib_source.h>
#include <vnet/ip/ip_types.h>
#include <vnet/ip/ip.h>

/* 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 <cnat/cnat_error.def>
#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)
{
  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