Line data Source code
1 : /*
2 : * det44.h - deterministic NAT definitions
3 : *
4 : * Copyright (c) 2020 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : /**
19 : * @file
20 : * @brief Deterministic NAT (CGN) definitions
21 : */
22 :
23 : #ifndef __included_det44_h__
24 : #define __included_det44_h__
25 :
26 : #include <vnet/vnet.h>
27 : #include <vnet/ip/ip.h>
28 : #include <vnet/ethernet/ethernet.h>
29 : #include <vnet/ip/icmp46_packet.h>
30 : #include <vnet/api_errno.h>
31 : #include <vnet/fib/fib_source.h>
32 : #include <vppinfra/dlist.h>
33 : #include <vppinfra/error.h>
34 : #include <vlibapi/api.h>
35 : #include <vlib/log.h>
36 : #include <vnet/fib/fib_table.h>
37 : #include <vnet/fib/ip4_fib.h>
38 : #include <vnet/ip/reass/ip4_sv_reass.h>
39 :
40 : #include <nat/lib/lib.h>
41 : #include <nat/lib/inlines.h>
42 : #include <nat/lib/ipfix_logging.h>
43 : #include <nat/lib/nat_proto.h>
44 :
45 : /* Session state */
46 : #define foreach_det44_session_state \
47 : _(0, UNKNOWN, "unknown") \
48 : _(1, UDP_ACTIVE, "udp-active") \
49 : _(2, TCP_SYN_SENT, "tcp-syn-sent") \
50 : _(3, TCP_ESTABLISHED, "tcp-established") \
51 : _(4, TCP_FIN_WAIT, "tcp-fin-wait") \
52 : _(5, TCP_CLOSE_WAIT, "tcp-close-wait") \
53 : _(6, TCP_CLOSING, "tcp-closing") \
54 : _(7, TCP_LAST_ACK, "tcp-last-ack") \
55 : _(8, TCP_CLOSED, "tcp-closed") \
56 : _(9, ICMP_ACTIVE, "icmp-active")
57 :
58 : typedef enum
59 : {
60 : #define _(v, N, s) DET44_SESSION_##N = v,
61 : foreach_det44_session_state
62 : #undef _
63 : } det44_session_state_t;
64 :
65 : #define DET44_SES_PER_USER 1000
66 :
67 : typedef struct
68 : {
69 : u16 identifier;
70 : u16 sequence;
71 : } icmp_echo_header_t;
72 :
73 : typedef struct
74 : {
75 : u16 src_port, dst_port;
76 : } tcp_udp_header_t;
77 :
78 : typedef struct
79 : {
80 : u32 cached_sw_if_index;
81 : u32 cached_ip4_address;
82 : } det44_runtime_t;
83 :
84 : /* deterministic session outside key */
85 : typedef struct
86 : {
87 : union
88 : {
89 : struct
90 : {
91 : ip4_address_t ext_host_addr;
92 : u16 ext_host_port;
93 : u16 out_port;
94 : };
95 : u64 as_u64;
96 : };
97 : } snat_det_out_key_t;
98 :
99 : typedef struct
100 : {
101 : /* Inside network port */
102 : u16 in_port;
103 : /* Outside network address and port */
104 : snat_det_out_key_t out;
105 : /* Session state */
106 : u8 state;
107 : /* Expire timeout */
108 : u32 expire;
109 : } snat_det_session_t;
110 :
111 : typedef struct
112 : {
113 : /* inside IP address range */
114 : ip4_address_t in_addr;
115 : u8 in_plen;
116 : /* outside IP address range */
117 : ip4_address_t out_addr;
118 : u8 out_plen;
119 : /* inside IP addresses / outside IP addresses */
120 : u32 sharing_ratio;
121 : /* number of ports available to internal host */
122 : u16 ports_per_host;
123 : /* session counter */
124 : u32 ses_num;
125 : /* vector of sessions */
126 : snat_det_session_t *sessions;
127 : } snat_det_map_t;
128 :
129 : typedef struct
130 : {
131 : u32 sw_if_index;
132 : u8 flags;
133 : } det44_interface_t;
134 :
135 : typedef struct
136 : {
137 : u32 outside_vrf_id;
138 : u32 inside_vrf_id;
139 : } det44_config_t;
140 :
141 : typedef struct
142 : {
143 : u32 fib_index;
144 : u32 refcount;
145 : } det44_fib_t;
146 :
147 : typedef struct det44_main_s
148 : {
149 : det44_config_t config;
150 :
151 : u32 outside_fib_index;
152 : u32 inside_fib_index;
153 :
154 : /* Vector of outside fibs */
155 : det44_fib_t *outside_fibs;
156 :
157 : fib_source_t fib_src_hi;
158 : fib_source_t fib_src_low;
159 :
160 : u32 out2in_node_index;
161 : u32 in2out_node_index;
162 :
163 : /* Deterministic NAT mappings */
164 : snat_det_map_t *det_maps;
165 :
166 : /* TCP MSS clamping */
167 : u16 mss_clamping;
168 :
169 : /* Protocol timeouts */
170 : nat_timeouts_t timeouts;
171 :
172 : /* Expire walk process node index */
173 : u32 expire_walk_node_index;
174 :
175 : u32 enabled;
176 :
177 : /* API message ID base */
178 : u16 msg_id_base;
179 :
180 : /* log class */
181 : vlib_log_class_t log_class;
182 :
183 : det44_interface_t *interfaces;
184 :
185 : /* convenience */
186 : ip4_main_t *ip4_main;
187 : /* required */
188 : vnet_main_t *vnet_main;
189 :
190 : } det44_main_t;
191 :
192 : extern det44_main_t det44_main;
193 :
194 : /* logging */
195 : #define det44_log_err(...) \
196 : vlib_log(VLIB_LOG_LEVEL_ERR, det44_main.log_class, __VA_ARGS__)
197 : #define det44_log_warn(...) \
198 : vlib_log(VLIB_LOG_LEVEL_WARNING, det44_main.log_class, __VA_ARGS__)
199 : #define det44_log_notice(...) \
200 : vlib_log(VLIB_LOG_LEVEL_NOTICE, det44_main.log_class, __VA_ARGS__)
201 : #define det44_log_info(...) \
202 : vlib_log(VLIB_LOG_LEVEL_INFO, det44_main.log_class, __VA_ARGS__)
203 : #define det44_log_debug(...)\
204 : vlib_log(VLIB_LOG_LEVEL_DEBUG, det44_main.log_class, __VA_ARGS__)
205 :
206 : /* Deterministic NAT interface flags */
207 : #define DET44_INTERFACE_FLAG_IS_INSIDE 1
208 : #define DET44_INTERFACE_FLAG_IS_OUTSIDE 2
209 :
210 : /** \brief Check if Deterministic NAT interface is inside.
211 : @param i Deterministic NAT interface
212 : @return 1 if inside interface
213 : */
214 : #define det44_interface_is_inside(i) i->flags & DET44_INTERFACE_FLAG_IS_INSIDE
215 :
216 : /** \brief Check if Deterministic NAT interface is outside.
217 : @param i Deterministic NAT interface
218 : @return 1 if outside interface
219 : */
220 : #define det44_interface_is_outside(i) i->flags & DET44_INTERFACE_FLAG_IS_OUTSIDE
221 :
222 : static_always_inline u8
223 912 : plugin_enabled ()
224 : {
225 912 : det44_main_t *dm = &det44_main;
226 912 : return dm->enabled;
227 : }
228 :
229 : extern vlib_node_registration_t det44_in2out_node;
230 : extern vlib_node_registration_t det44_out2in_node;
231 :
232 : int det44_plugin_enable (det44_config_t);
233 : int det44_plugin_disable ();
234 :
235 : int det44_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del);
236 :
237 : int det44_set_timeouts (nat_timeouts_t * timeouts);
238 : nat_timeouts_t det44_get_timeouts ();
239 : void det44_reset_timeouts ();
240 :
241 : /* format functions */
242 : format_function_t format_det_map_ses;
243 :
244 : int snat_det_add_map (ip4_address_t * in_addr, u8 in_plen,
245 : ip4_address_t * out_addr, u8 out_plen, int is_add);
246 :
247 : /* icmp session match functions */
248 : u32 icmp_match_out2in_det (vlib_node_runtime_t * node,
249 : u32 thread_index, vlib_buffer_t * b0,
250 : ip4_header_t * ip0, ip4_address_t * addr,
251 : u16 * port, u32 * fib_index,
252 : nat_protocol_t * proto, void *d, void *e,
253 : u8 * dont_translate);
254 : u32 icmp_match_in2out_det (vlib_node_runtime_t * node,
255 : u32 thread_index, vlib_buffer_t * b0,
256 : ip4_header_t * ip0, ip4_address_t * addr,
257 : u16 * port, u32 * fib_index,
258 : nat_protocol_t * proto, void *d, void *e,
259 : u8 * dont_translate);
260 : u32 det44_icmp_in2out (vlib_buffer_t * b0, ip4_header_t * ip0,
261 : icmp46_header_t * icmp0, u32 sw_if_index0,
262 : u32 rx_fib_index0, vlib_node_runtime_t * node,
263 : u32 next0, u32 thread_index, void *d, void *e);
264 : u32 det44_icmp_out2in (vlib_buffer_t * b0, ip4_header_t * ip0,
265 : icmp46_header_t * icmp0, u32 sw_if_index0,
266 : u32 rx_fib_index0, vlib_node_runtime_t * node,
267 : u32 next0, u32 thread_index, void *d, void *e);
268 :
269 : static_always_inline int
270 35 : is_addr_in_net (ip4_address_t * addr, ip4_address_t * net, u8 plen)
271 : {
272 35 : if (net->as_u32 == (addr->as_u32 & ip4_main.fib_masks[plen]))
273 35 : return 1;
274 0 : return 0;
275 : }
276 :
277 : static_always_inline snat_det_map_t *
278 21 : snat_det_map_by_user (ip4_address_t * user_addr)
279 : {
280 21 : det44_main_t *dm = &det44_main;
281 : snat_det_map_t *mp;
282 : /* *INDENT-OFF* */
283 21 : pool_foreach (mp, dm->det_maps)
284 : {
285 21 : if (is_addr_in_net(user_addr, &mp->in_addr, mp->in_plen))
286 21 : return mp;
287 : }
288 : /* *INDENT-ON* */
289 0 : return 0;
290 : }
291 :
292 : static_always_inline snat_det_map_t *
293 14 : snat_det_map_by_out (ip4_address_t * out_addr)
294 : {
295 14 : det44_main_t *dm = &det44_main;
296 : snat_det_map_t *mp;
297 : /* *INDENT-OFF* */
298 14 : pool_foreach (mp, dm->det_maps)
299 : {
300 14 : if (is_addr_in_net(out_addr, &mp->out_addr, mp->out_plen))
301 14 : return mp;
302 : }
303 : /* *INDENT-ON* */
304 0 : return 0;
305 : }
306 :
307 : static_always_inline void
308 19 : snat_det_forward (snat_det_map_t * dm, ip4_address_t * in_addr,
309 : ip4_address_t * out_addr, u16 * lo_port)
310 : {
311 : u32 in_offset, out_offset;
312 :
313 19 : in_offset = clib_net_to_host_u32 (in_addr->as_u32) -
314 19 : clib_net_to_host_u32 (dm->in_addr.as_u32);
315 19 : out_offset = in_offset / dm->sharing_ratio;
316 19 : out_addr->as_u32 =
317 19 : clib_host_to_net_u32 (clib_net_to_host_u32 (dm->out_addr.as_u32) +
318 : out_offset);
319 19 : *lo_port = 1024 + dm->ports_per_host * (in_offset % dm->sharing_ratio);
320 19 : }
321 :
322 : static_always_inline void
323 14 : snat_det_reverse (snat_det_map_t * dm, ip4_address_t * out_addr, u16 out_port,
324 : ip4_address_t * in_addr)
325 : {
326 : u32 in_offset1, in_offset2, out_offset;
327 :
328 14 : out_offset = clib_net_to_host_u32 (out_addr->as_u32) -
329 14 : clib_net_to_host_u32 (dm->out_addr.as_u32);
330 14 : in_offset1 = out_offset * dm->sharing_ratio;
331 14 : in_offset2 = (out_port - 1024) / dm->ports_per_host;
332 14 : in_addr->as_u32 =
333 14 : clib_host_to_net_u32 (clib_net_to_host_u32 (dm->in_addr.as_u32) +
334 : in_offset1 + in_offset2);
335 14 : }
336 :
337 : static_always_inline u32
338 53 : snat_det_user_ses_offset (ip4_address_t * addr, u8 plen)
339 : {
340 53 : return (clib_net_to_host_u32 (addr->as_u32) & pow2_mask (32 - plen)) *
341 : DET44_SES_PER_USER;
342 : }
343 :
344 : static_always_inline snat_det_session_t *
345 23 : snat_det_get_ses_by_out (snat_det_map_t * dm, ip4_address_t * in_addr,
346 : u64 out_key)
347 : {
348 : u32 user_offset;
349 : u16 i;
350 :
351 23 : user_offset = snat_det_user_ses_offset (in_addr, dm->in_plen);
352 10026 : for (i = 0; i < DET44_SES_PER_USER; i++)
353 : {
354 10016 : if (dm->sessions[i + user_offset].out.as_u64 == out_key)
355 13 : return &dm->sessions[i + user_offset];
356 : }
357 :
358 10 : return 0;
359 : }
360 :
361 : static_always_inline snat_det_session_t *
362 19 : snat_det_find_ses_by_in (snat_det_map_t * dm, ip4_address_t * in_addr,
363 : u16 in_port, snat_det_out_key_t out_key)
364 : {
365 : snat_det_session_t *ses;
366 : u32 user_offset;
367 : u16 i;
368 :
369 19 : user_offset = snat_det_user_ses_offset (in_addr, dm->in_plen);
370 10019 : for (i = 0; i < DET44_SES_PER_USER; i++)
371 : {
372 10009 : ses = &dm->sessions[i + user_offset];
373 10009 : if (ses->in_port == in_port &&
374 9 : ses->out.ext_host_addr.as_u32 == out_key.ext_host_addr.as_u32 &&
375 9 : ses->out.ext_host_port == out_key.ext_host_port)
376 9 : return &dm->sessions[i + user_offset];
377 : }
378 :
379 10 : return 0;
380 : }
381 :
382 : static_always_inline snat_det_session_t *
383 10 : snat_det_ses_create (u32 thread_index, snat_det_map_t * dm,
384 : ip4_address_t * in_addr, u16 in_port,
385 : snat_det_out_key_t * out)
386 : {
387 : u32 user_offset;
388 : u16 i;
389 :
390 10 : user_offset = snat_det_user_ses_offset (in_addr, dm->in_plen);
391 :
392 16 : for (i = 0; i < DET44_SES_PER_USER; i++)
393 : {
394 16 : if (!dm->sessions[i + user_offset].in_port)
395 : {
396 10 : if (clib_atomic_bool_cmp_and_swap
397 : (&dm->sessions[i + user_offset].in_port, 0, in_port))
398 : {
399 10 : dm->sessions[i + user_offset].out.as_u64 = out->as_u64;
400 10 : dm->sessions[i + user_offset].state = DET44_SESSION_UNKNOWN;
401 10 : dm->sessions[i + user_offset].expire = 0;
402 10 : clib_atomic_add_fetch (&dm->ses_num, 1);
403 10 : return &dm->sessions[i + user_offset];
404 : }
405 : }
406 : }
407 :
408 0 : nat_ipfix_logging_max_entries_per_user (thread_index,
409 : DET44_SES_PER_USER,
410 : in_addr->as_u32);
411 0 : return 0;
412 : }
413 :
414 : static_always_inline void
415 7 : snat_det_ses_close (snat_det_map_t * dm, snat_det_session_t * ses)
416 : {
417 7 : if (clib_atomic_bool_cmp_and_swap (&ses->in_port, ses->in_port, 0))
418 : {
419 7 : ses->out.as_u64 = 0;
420 7 : clib_atomic_add_fetch (&dm->ses_num, -1);
421 : }
422 7 : }
423 :
424 : clib_error_t *det44_api_hookup (vlib_main_t * vm);
425 :
426 : #endif /* __included_det44_h__ */
427 :
428 : /*
429 : * fd.io coding-style-patch-verification: ON
430 : *
431 : * Local Variables:
432 : * eval: (c-set-style "gnu")
433 : * End:
434 : */
|