nat: user deletion function & extra metrics
[vpp.git] / src / plugins / nat / nat44 / inlines.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  * @brief The NAT44 inline functions
17  */
18
19 #ifndef included_nat44_inlines_h__
20 #define included_nat44_inlines_h__
21
22 #include <vnet/fib/ip4_fib.h>
23 #include <nat/nat.h>
24
25 static_always_inline u8
26 nat44_maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index)
27 {
28   if (pool_elts (sm->per_thread_data[thread_index].sessions) >=
29       sm->max_translations)
30     return 1;
31   return 0;
32 }
33
34 static_always_inline void
35 nat44_session_cleanup (snat_session_t * s, u32 thread_index)
36 {
37   snat_main_t *sm = &snat_main;
38
39   nat_free_session_data (sm, s, thread_index, 0);
40   nat44_delete_session (sm, s, thread_index);
41 }
42
43 static_always_inline void
44 nat44_user_del_sessions (snat_user_t * u, u32 thread_index)
45 {
46   dlist_elt_t *elt;
47   snat_session_t *s;
48
49   snat_main_t *sm = &snat_main;
50   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
51
52   // get head
53   elt = pool_elt_at_index (tsm->list_pool,
54                            u->sessions_per_user_list_head_index);
55   // get first element
56   elt = pool_elt_at_index (tsm->list_pool, elt->next);
57
58   while (elt->value != ~0)
59     {
60       s = pool_elt_at_index (tsm->sessions, elt->value);
61       elt = pool_elt_at_index (tsm->list_pool, elt->next);
62       nat44_session_cleanup (s, thread_index);
63     }
64 }
65
66 static_always_inline int
67 nat44_user_del (ip4_address_t * addr, u32 fib_index)
68 {
69   int rv = 1;
70
71   snat_main_t *sm = &snat_main;
72   snat_main_per_thread_data_t *tsm;
73
74   snat_user_key_t user_key;
75   clib_bihash_kv_8_8_t kv, value;
76
77   user_key.addr.as_u32 = addr->as_u32;
78   user_key.fib_index = fib_index;
79   kv.key = user_key.as_u64;
80
81   if (sm->num_workers > 1)
82     {
83       /* *INDENT-OFF* */
84       vec_foreach (tsm, sm->per_thread_data)
85         {
86           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
87             {
88               nat44_user_del_sessions (
89                   pool_elt_at_index (tsm->users, value.value),
90                   tsm->thread_index);
91               rv = 0;
92               break;
93             }
94         }
95       /* *INDENT-ON* */
96     }
97   else
98     {
99       tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
100       if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
101         {
102           nat44_user_del_sessions (pool_elt_at_index
103                                    (tsm->users, value.value),
104                                    tsm->thread_index);
105           rv = 0;
106         }
107     }
108   return rv;
109 }
110
111 static_always_inline void
112 nat44_user_try_cleanup (snat_user_t * u, u32 thread_index, f64 now)
113 {
114   dlist_elt_t *elt;
115   snat_session_t *s;
116   u64 sess_timeout_time;
117
118   snat_main_t *sm = &snat_main;
119   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
120
121   // get head
122   elt = pool_elt_at_index (tsm->list_pool,
123                            u->sessions_per_user_list_head_index);
124   // get first element
125   elt = pool_elt_at_index (tsm->list_pool, elt->next);
126
127   while (elt->value != ~0)
128     {
129       s = pool_elt_at_index (tsm->sessions, elt->value);
130       elt = pool_elt_at_index (tsm->list_pool, elt->next);
131
132       sess_timeout_time = s->last_heard +
133         (f64) nat44_session_get_timeout (sm, s);
134
135       if (now < sess_timeout_time)
136         {
137           tsm->min_session_timeout =
138             clib_min (sess_timeout_time, tsm->min_session_timeout);
139           continue;
140         }
141
142       nat44_session_cleanup (s, thread_index);
143     }
144 }
145
146 static_always_inline void
147 nat44_session_try_cleanup (ip4_address_t * addr,
148                            u32 fib_index, u32 thread_index, f64 now)
149 {
150   snat_user_t *u = 0;
151   snat_user_key_t user_key;
152   clib_bihash_kv_8_8_t kv, value;
153
154   snat_main_t *sm = &snat_main;
155   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
156
157   user_key.addr.as_u32 = addr->as_u32;
158   user_key.fib_index = fib_index;
159   kv.key = user_key.as_u64;
160
161   // lookup user for this traffic
162   if (PREDICT_FALSE (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)))
163     {
164       // there is still place and a new user can be created
165       if (PREDICT_TRUE (pool_elts (tsm->sessions) < sm->max_translations))
166         return;
167
168       if (now >= tsm->min_session_timeout)
169         {
170           tsm->min_session_timeout = ~0;
171           // there is no place so we try to cleanup all users in this thread
172           /* *INDENT-OFF* */
173           pool_foreach (u, tsm->users,
174                         ({ nat44_user_try_cleanup (u, thread_index, now); }));
175           /* *INDENT-ON* */
176           if (~0 == tsm->min_session_timeout)
177             {
178               tsm->min_session_timeout = 0;
179             }
180         }
181       return;
182     }
183
184   if (now >= tsm->min_session_timeout)
185     {
186       tsm->min_session_timeout = ~0;
187       // each time user creates a new session we try to cleanup expired sessions
188       nat44_user_try_cleanup (pool_elt_at_index (tsm->users, value.value),
189                               thread_index, now);
190       if (~0 == tsm->min_session_timeout)
191         {
192           tsm->min_session_timeout = 0;
193         }
194     }
195 }
196
197 static_always_inline void
198 nat44_force_session_cleanup (void)
199 {
200   snat_user_t *u = 0;
201
202   snat_main_t *sm = &snat_main;
203   snat_main_per_thread_data_t *tsm;
204
205   vlib_main_t *vm = vlib_get_main ();
206   f64 now = vlib_time_now (vm);
207
208   // TODO: consider own timeouts
209
210   if (sm->num_workers > 1)
211     {
212       /* *INDENT-OFF* */
213       vec_foreach (tsm, sm->per_thread_data)
214         {
215           pool_foreach (u, tsm->users,
216           ({
217             nat44_user_try_cleanup (u, tsm->thread_index, now);
218           }));
219         }
220       /* *INDENT-ON* */
221     }
222   else
223     {
224       tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
225       /* *INDENT-OFF* */
226       pool_foreach (u, tsm->users,
227       ({
228         nat44_user_try_cleanup (u, tsm->thread_index, now);
229       }));
230       /* *INDENT-ON* */
231     }
232 }
233
234 #endif /* included_nat44_inlines_h__ */
235
236 /*
237  * fd.io coding-style-patch-verification: ON
238  *
239  * Local Variables:
240  * eval: (c-set-style "gnu")
241  * End:
242  */