virtio: enable the interrupt support for uio_pci_generic
[vpp.git] / src / plugins / nat / nat44 / ed_inlines.h
1 /*
2  * simple nat plugin
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 #ifndef __included_ed_inlines_h__
19 #define __included_ed_inlines_h__
20
21 #include <float.h>
22 #include <vppinfra/clib.h>
23 #include <nat/nat.h>
24 #include <nat/nat_inlines.h>
25
26 static_always_inline int
27 nat_ed_lru_insert (snat_main_per_thread_data_t * tsm,
28                    snat_session_t * s, f64 now, u8 proto)
29 {
30   dlist_elt_t *lru_list_elt;
31   pool_get (tsm->lru_pool, lru_list_elt);
32   s->lru_index = lru_list_elt - tsm->lru_pool;
33   switch (proto)
34     {
35     case IP_PROTOCOL_UDP:
36       s->lru_head_index = tsm->udp_lru_head_index;
37       break;
38     case IP_PROTOCOL_TCP:
39       s->lru_head_index = tsm->tcp_trans_lru_head_index;
40       break;
41     case IP_PROTOCOL_ICMP:
42       s->lru_head_index = tsm->icmp_lru_head_index;
43       break;
44     default:
45       s->lru_head_index = tsm->unk_proto_lru_head_index;
46       break;
47     }
48   clib_dlist_addtail (tsm->lru_pool, s->lru_head_index, s->lru_index);
49   lru_list_elt->value = s - tsm->sessions;
50   s->last_lru_update = now;
51   return 1;
52 }
53
54 static_always_inline void
55 nat_6t_flow_to_ed_k (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f)
56 {
57   init_ed_k (kv, f->match.saddr, f->match.sport, f->match.daddr,
58              f->match.dport, f->match.fib_index, f->match.proto);
59 }
60
61 static_always_inline void
62 nat_6t_flow_to_ed_kv (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f,
63                       u32 thread_idx, u32 session_idx)
64 {
65   init_ed_kv (kv, f->match.saddr, f->match.sport, f->match.daddr,
66               f->match.dport, f->match.fib_index, f->match.proto, thread_idx,
67               session_idx);
68 }
69
70 static_always_inline int
71 nat_ed_ses_i2o_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
72                                   snat_session_t *s, int is_add)
73 {
74   snat_main_per_thread_data_t *tsm =
75     vec_elt_at_index (sm->per_thread_data, thread_idx);
76   clib_bihash_kv_16_8_t kv;
77   if (0 == is_add)
78     {
79       nat_6t_flow_to_ed_k (&kv, &s->i2o);
80     }
81   else
82     {
83       nat_6t_flow_to_ed_kv (&kv, &s->i2o, thread_idx, s - tsm->sessions);
84       nat_6t_l3_l4_csum_calc (&s->i2o);
85     }
86   return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
87 }
88
89 static_always_inline int
90 nat_ed_ses_o2i_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
91                                   snat_session_t *s, int is_add)
92 {
93   snat_main_per_thread_data_t *tsm =
94     vec_elt_at_index (sm->per_thread_data, thread_idx);
95   clib_bihash_kv_16_8_t kv;
96   if (0 == is_add)
97     {
98       nat_6t_flow_to_ed_k (&kv, &s->o2i);
99     }
100   else
101     {
102       nat_6t_flow_to_ed_kv (&kv, &s->o2i, thread_idx, s - tsm->sessions);
103       nat_6t_l3_l4_csum_calc (&s->o2i);
104     }
105   return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
106 }
107
108 always_inline void
109 nat_ed_session_delete (snat_main_t * sm, snat_session_t * ses,
110                        u32 thread_index, int lru_delete
111                        /* delete from global LRU list */ )
112 {
113   snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
114                                                        thread_index);
115
116   if (lru_delete)
117     {
118       clib_dlist_remove (tsm->lru_pool, ses->lru_index);
119     }
120   pool_put_index (tsm->lru_pool, ses->lru_index);
121   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, ses, 0))
122     nat_elog_warn ("flow hash del failed");
123   if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, ses, 0))
124     nat_elog_warn ("flow hash del failed");
125   pool_put (tsm->sessions, ses);
126   vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
127                            pool_elts (tsm->sessions));
128
129 }
130
131 static_always_inline int
132 nat_lru_free_one_with_head (snat_main_t * sm, int thread_index,
133                             f64 now, u32 head_index)
134 {
135   snat_session_t *s = NULL;
136   dlist_elt_t *oldest_elt;
137   f64 sess_timeout_time;
138   u32 oldest_index;
139   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
140   oldest_index = clib_dlist_remove_head (tsm->lru_pool, head_index);
141   if (~0 != oldest_index)
142     {
143       oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);
144       s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
145
146       sess_timeout_time =
147         s->last_heard + (f64) nat44_session_get_timeout (sm, s);
148       if (now >= sess_timeout_time
149           || (s->tcp_closed_timestamp && now >= s->tcp_closed_timestamp))
150         {
151           nat_free_session_data (sm, s, thread_index, 0);
152           nat_ed_session_delete (sm, s, thread_index, 0);
153           return 1;
154         }
155       else
156         {
157           clib_dlist_addhead (tsm->lru_pool, head_index, oldest_index);
158         }
159     }
160   return 0;
161 }
162
163 static_always_inline int
164 nat_lru_free_one (snat_main_t * sm, int thread_index, f64 now)
165 {
166   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
167   int rc = 0;
168 #define _(p)                                                       \
169   if ((rc = nat_lru_free_one_with_head (sm, thread_index, now,     \
170                                         tsm->p##_lru_head_index))) \
171     {                                                              \
172       return rc;                                                   \
173     }
174   _(tcp_trans);
175   _(udp);
176   _(unk_proto);
177   _(icmp);
178   _(tcp_estab);
179 #undef _
180   return 0;
181 }
182
183 static_always_inline snat_session_t *
184 nat_ed_session_alloc (snat_main_t * sm, u32 thread_index, f64 now, u8 proto)
185 {
186   snat_session_t *s;
187   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
188
189   nat_lru_free_one (sm, thread_index, now);
190
191   pool_get (tsm->sessions, s);
192   clib_memset (s, 0, sizeof (*s));
193
194   nat_ed_lru_insert (tsm, s, now, proto);
195
196   s->ha_last_refreshed = now;
197   vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
198                            pool_elts (tsm->sessions));
199   return s;
200 }
201
202 // slow path
203 static_always_inline void
204 per_vrf_sessions_cleanup (u32 thread_index)
205 {
206   snat_main_t *sm = &snat_main;
207   snat_main_per_thread_data_t *tsm =
208     vec_elt_at_index (sm->per_thread_data, thread_index);
209   per_vrf_sessions_t *per_vrf_sessions;
210   u32 *to_free = 0, *i;
211
212   vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
213   {
214     if (per_vrf_sessions->expired)
215       {
216         if (per_vrf_sessions->ses_count == 0)
217           {
218             vec_add1 (to_free, per_vrf_sessions - tsm->per_vrf_sessions_vec);
219           }
220       }
221   }
222
223   if (vec_len (to_free))
224     {
225       vec_foreach (i, to_free)
226       {
227         vec_del1 (tsm->per_vrf_sessions_vec, *i);
228       }
229     }
230
231   vec_free (to_free);
232 }
233
234 // slow path
235 static_always_inline void
236 per_vrf_sessions_register_session (snat_session_t * s, u32 thread_index)
237 {
238   snat_main_t *sm = &snat_main;
239   snat_main_per_thread_data_t *tsm =
240     vec_elt_at_index (sm->per_thread_data, thread_index);
241   per_vrf_sessions_t *per_vrf_sessions;
242
243   per_vrf_sessions_cleanup (thread_index);
244
245   // s->per_vrf_sessions_index == ~0 ... reuse of old session
246
247   vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
248   {
249     // ignore already expired registrations
250     if (per_vrf_sessions->expired)
251       continue;
252
253     if ((s->in2out.fib_index == per_vrf_sessions->rx_fib_index) &&
254         (s->out2in.fib_index == per_vrf_sessions->tx_fib_index))
255       {
256         goto done;
257       }
258     if ((s->in2out.fib_index == per_vrf_sessions->tx_fib_index) &&
259         (s->out2in.fib_index == per_vrf_sessions->rx_fib_index))
260       {
261         goto done;
262       }
263   }
264
265   // create a new registration
266   vec_add2 (tsm->per_vrf_sessions_vec, per_vrf_sessions, 1);
267   clib_memset (per_vrf_sessions, 0, sizeof (*per_vrf_sessions));
268
269   per_vrf_sessions->rx_fib_index = s->in2out.fib_index;
270   per_vrf_sessions->tx_fib_index = s->out2in.fib_index;
271
272 done:
273   s->per_vrf_sessions_index = per_vrf_sessions - tsm->per_vrf_sessions_vec;
274   per_vrf_sessions->ses_count++;
275 }
276
277 // fast path
278 static_always_inline void
279 per_vrf_sessions_unregister_session (snat_session_t * s, u32 thread_index)
280 {
281   snat_main_t *sm = &snat_main;
282   snat_main_per_thread_data_t *tsm;
283   per_vrf_sessions_t *per_vrf_sessions;
284
285   ASSERT (s->per_vrf_sessions_index != ~0);
286
287   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
288   per_vrf_sessions =
289     vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
290
291   ASSERT (per_vrf_sessions->ses_count != 0);
292
293   per_vrf_sessions->ses_count--;
294   s->per_vrf_sessions_index = ~0;
295 }
296
297 // fast path
298 static_always_inline u8
299 per_vrf_sessions_is_expired (snat_session_t * s, u32 thread_index)
300 {
301   snat_main_t *sm = &snat_main;
302   snat_main_per_thread_data_t *tsm;
303   per_vrf_sessions_t *per_vrf_sessions;
304
305   ASSERT (s->per_vrf_sessions_index != ~0);
306
307   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
308   per_vrf_sessions =
309     vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
310   return per_vrf_sessions->expired;
311 }
312
313 static_always_inline void
314 nat_6t_flow_init (nat_6t_flow_t *f, u32 thread_idx, ip4_address_t saddr,
315                   u16 sport, ip4_address_t daddr, u16 dport, u32 fib_index,
316                   u8 proto, u32 session_idx)
317 {
318   clib_memset (f, 0, sizeof (*f));
319   f->match.saddr = saddr;
320   f->match.sport = sport;
321   f->match.daddr = daddr;
322   f->match.dport = dport;
323   f->match.proto = proto;
324   f->match.fib_index = fib_index;
325 }
326
327 static_always_inline void
328 nat_6t_i2o_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
329                       ip4_address_t saddr, u16 sport, ip4_address_t daddr,
330                       u16 dport, u32 fib_index, u8 proto)
331 {
332   snat_main_per_thread_data_t *tsm =
333     vec_elt_at_index (sm->per_thread_data, thread_idx);
334   nat_6t_flow_init (&s->i2o, thread_idx, saddr, sport, daddr, dport, fib_index,
335                     proto, s - tsm->sessions);
336 }
337
338 static_always_inline void
339 nat_6t_o2i_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
340                       ip4_address_t saddr, u16 sport, ip4_address_t daddr,
341                       u16 dport, u32 fib_index, u8 proto)
342 {
343   snat_main_per_thread_data_t *tsm =
344     vec_elt_at_index (sm->per_thread_data, thread_idx);
345   nat_6t_flow_init (&s->o2i, thread_idx, saddr, sport, daddr, dport, fib_index,
346                     proto, s - tsm->sessions);
347 }
348
349 static_always_inline int
350 nat_6t_flow_match (nat_6t_flow_t *f, vlib_buffer_t *b, ip4_address_t saddr,
351                    u16 sport, ip4_address_t daddr, u16 dport, u8 protocol,
352                    u32 fib_index)
353 {
354   return f->match.daddr.as_u32 == daddr.as_u32 &&
355          f->match.dport == vnet_buffer (b)->ip.reass.l4_dst_port &&
356          f->match.proto == protocol && f->match.fib_index == fib_index &&
357          f->match.saddr.as_u32 == saddr.as_u32 &&
358          f->match.sport == vnet_buffer (b)->ip.reass.l4_src_port;
359 }
360
361 #endif