Line data Source code
1 : /*
2 : * Copyright (c) 2016 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 :
17 : /* ICMPv4 invert type for stateful ACL */
18 : static const u8 icmp4_invmap[] = {
19 : [ICMP4_echo_request] = ICMP4_echo_reply + 1,
20 : [ICMP4_timestamp_request] = ICMP4_timestamp_reply + 1,
21 : [ICMP4_information_request] = ICMP4_information_reply + 1,
22 : [ICMP4_address_mask_request] = ICMP4_address_mask_reply + 1
23 : };
24 :
25 : /* Supported ICMPv4 messages for session creation */
26 : static const u8 icmp4_valid_new[] = {
27 : [ICMP4_echo_request] = 1,
28 : [ICMP4_timestamp_request] = 1,
29 : [ICMP4_information_request] = 1,
30 : [ICMP4_address_mask_request] = 1
31 : };
32 :
33 : /* ICMPv6 invert type for stateful ACL */
34 : static const u8 icmp6_invmap[] = {
35 : [ICMP6_echo_request - 128] = ICMP6_echo_reply + 1,
36 : [ICMP6_node_information_request - 128] = ICMP6_node_information_response + 1
37 : };
38 :
39 : /* Supported ICMPv6 messages for session creation */
40 : static const u8 icmp6_valid_new[] = {
41 : [ICMP6_echo_request - 128] = 1,
42 : [ICMP6_node_information_request - 128] = 1
43 : };
44 :
45 : /* IP4 and IP6 protocol numbers of ICMP */
46 : static u8 icmp_protos[] = { IP_PROTOCOL_ICMP, IP_PROTOCOL_ICMP6 };
47 :
48 :
49 :
50 : always_inline int
51 : acl_fa_ifc_has_sessions (acl_main_t * am, int sw_if_index0)
52 : {
53 : return am->fa_sessions_hash_is_initialized;
54 : }
55 :
56 : always_inline int
57 323 : acl_fa_ifc_has_in_acl (acl_main_t * am, int sw_if_index0)
58 : {
59 323 : int it_has = clib_bitmap_get (am->fa_in_acl_on_sw_if_index, sw_if_index0);
60 323 : return it_has;
61 : }
62 :
63 : always_inline int
64 234 : acl_fa_ifc_has_out_acl (acl_main_t * am, int sw_if_index0)
65 : {
66 234 : int it_has = clib_bitmap_get (am->fa_out_acl_on_sw_if_index, sw_if_index0);
67 234 : return it_has;
68 : }
69 :
70 : always_inline int
71 952 : fa_session_get_timeout_type (acl_main_t * am, fa_session_t * sess)
72 : {
73 : /* seen both SYNs and ACKs but not FINs means we are in established state */
74 952 : u16 masked_flags =
75 952 : sess->tcp_flags_seen.as_u16 & ((TCP_FLAGS_RSTFINACKSYN << 8) +
76 : TCP_FLAGS_RSTFINACKSYN);
77 952 : switch (sess->info.l4.proto)
78 : {
79 23 : case IPPROTO_TCP:
80 23 : if (((TCP_FLAGS_ACKSYN << 8) + TCP_FLAGS_ACKSYN) == masked_flags)
81 : {
82 0 : return ACL_TIMEOUT_TCP_IDLE;
83 : }
84 : else
85 : {
86 23 : return ACL_TIMEOUT_TCP_TRANSIENT;
87 : }
88 : break;
89 726 : case IPPROTO_UDP:
90 726 : return ACL_TIMEOUT_UDP_IDLE;
91 : break;
92 203 : default:
93 203 : return ACL_TIMEOUT_UDP_IDLE;
94 : }
95 : }
96 :
97 : /*
98 : * Get the idle timeout of a session.
99 : */
100 :
101 : always_inline u64
102 744 : fa_session_get_timeout (acl_main_t * am, fa_session_t * sess)
103 : {
104 744 : u64 timeout = (am->vlib_main->clib_time.clocks_per_second);
105 744 : if (sess->link_list_id == ACL_TIMEOUT_PURGATORY)
106 : {
107 252 : timeout /= (1000000 / SESSION_PURGATORY_TIMEOUT_USEC);
108 : }
109 : else
110 : {
111 492 : int timeout_type = fa_session_get_timeout_type (am, sess);
112 492 : timeout *= am->session_timeout_sec[timeout_type];
113 : }
114 744 : return timeout;
115 : }
116 :
117 : always_inline fa_session_t *
118 227 : get_session_ptr_no_check (acl_main_t * am, u16 thread_index,
119 : u32 session_index)
120 : {
121 227 : acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index];
122 227 : return pool_elt_at_index (pw->fa_sessions_pool, session_index);
123 : }
124 :
125 :
126 : always_inline fa_session_t *
127 1494 : get_session_ptr (acl_main_t * am, u16 thread_index, u32 session_index)
128 : {
129 1494 : acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index];
130 :
131 1494 : if (PREDICT_FALSE (session_index >= vec_len (pw->fa_sessions_pool)))
132 0 : return 0;
133 :
134 1494 : return pool_elt_at_index (pw->fa_sessions_pool, session_index);
135 : }
136 :
137 : always_inline int
138 : is_valid_session_ptr (acl_main_t * am, u16 thread_index, fa_session_t * sess)
139 : {
140 : acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index];
141 : return ((sess != 0)
142 : && ((sess - pw->fa_sessions_pool) <
143 : pool_len (pw->fa_sessions_pool)));
144 : }
145 :
146 : always_inline void
147 208 : acl_fa_conn_list_add_session (acl_main_t * am, fa_full_session_id_t sess_id,
148 : u64 now)
149 : {
150 : fa_session_t *sess =
151 208 : get_session_ptr (am, sess_id.thread_index, sess_id.session_index);
152 208 : u8 list_id =
153 208 : sess->deleted ? ACL_TIMEOUT_PURGATORY : fa_session_get_timeout_type (am,
154 : sess);
155 208 : uword thread_index = os_get_thread_index ();
156 208 : acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index];
157 : /* the retrieved session thread index must be necessarily the same as the one in the key */
158 208 : ASSERT (sess->thread_index == sess_id.thread_index);
159 : /* the retrieved session thread index must be the same as current thread */
160 208 : ASSERT (sess->thread_index == thread_index);
161 208 : sess->link_enqueue_time = now;
162 208 : sess->link_list_id = list_id;
163 208 : sess->link_next_idx = FA_SESSION_BOGUS_INDEX;
164 208 : sess->link_prev_idx = pw->fa_conn_list_tail[list_id];
165 208 : if (FA_SESSION_BOGUS_INDEX != pw->fa_conn_list_tail[list_id])
166 : {
167 : fa_session_t *prev_sess =
168 145 : get_session_ptr (am, thread_index, pw->fa_conn_list_tail[list_id]);
169 145 : prev_sess->link_next_idx = sess_id.session_index;
170 : /* We should never try to link with a session on another thread */
171 145 : ASSERT (prev_sess->thread_index == sess->thread_index);
172 : }
173 208 : pw->fa_conn_list_tail[list_id] = sess_id.session_index;
174 :
175 : #ifdef FA_NODE_VERBOSE_DEBUG
176 : clib_warning
177 : ("FA-SESSION-DEBUG: add session id %d on thread %d sw_if_index %d",
178 : sess_id.session_index, thread_index, sess->sw_if_index);
179 : #endif
180 208 : pw->serviced_sw_if_index_bitmap =
181 208 : clib_bitmap_set (pw->serviced_sw_if_index_bitmap, sess->sw_if_index, 1);
182 :
183 208 : if (FA_SESSION_BOGUS_INDEX == pw->fa_conn_list_head[list_id])
184 : {
185 63 : pw->fa_conn_list_head[list_id] = sess_id.session_index;
186 : /* set the head expiry time because it is the first element */
187 63 : pw->fa_conn_list_head_expiry_time[list_id] =
188 63 : now + fa_session_get_timeout (am, sess);
189 : }
190 208 : }
191 :
192 : static int
193 208 : acl_fa_conn_list_delete_session (acl_main_t * am,
194 : fa_full_session_id_t sess_id, u64 now)
195 : {
196 208 : uword thread_index = os_get_thread_index ();
197 208 : acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index];
198 208 : if (thread_index != sess_id.thread_index)
199 : {
200 : /* If another thread attempts to delete the session, fail it. */
201 : #ifdef FA_NODE_VERBOSE_DEBUG
202 : clib_warning ("thread id in key %d != curr thread index, not deleting");
203 : #endif
204 0 : return 0;
205 : }
206 : fa_session_t *sess =
207 208 : get_session_ptr (am, sess_id.thread_index, sess_id.session_index);
208 208 : u64 next_expiry_time = ~0ULL;
209 : /* we should never try to delete the session with another thread index */
210 208 : if (sess->thread_index != os_get_thread_index ())
211 : {
212 0 : clib_error
213 : ("Attempting to delete session belonging to thread %d by thread %d",
214 : sess->thread_index, thread_index);
215 : }
216 208 : if (FA_SESSION_BOGUS_INDEX != sess->link_prev_idx)
217 : {
218 : fa_session_t *prev_sess =
219 0 : get_session_ptr (am, thread_index, sess->link_prev_idx);
220 : /* the previous session must be in the same list as this one */
221 0 : ASSERT (prev_sess->link_list_id == sess->link_list_id);
222 0 : prev_sess->link_next_idx = sess->link_next_idx;
223 : }
224 208 : if (FA_SESSION_BOGUS_INDEX != sess->link_next_idx)
225 : {
226 : fa_session_t *next_sess =
227 145 : get_session_ptr (am, thread_index, sess->link_next_idx);
228 : /* The next session must be in the same list as the one we are deleting */
229 145 : ASSERT (next_sess->link_list_id == sess->link_list_id);
230 145 : next_sess->link_prev_idx = sess->link_prev_idx;
231 145 : next_expiry_time = now + fa_session_get_timeout (am, next_sess);
232 : }
233 208 : if (pw->fa_conn_list_head[sess->link_list_id] == sess_id.session_index)
234 : {
235 208 : pw->fa_conn_list_head[sess->link_list_id] = sess->link_next_idx;
236 208 : pw->fa_conn_list_head_expiry_time[sess->link_list_id] =
237 : next_expiry_time;
238 : }
239 208 : if (pw->fa_conn_list_tail[sess->link_list_id] == sess_id.session_index)
240 : {
241 63 : pw->fa_conn_list_tail[sess->link_list_id] = sess->link_prev_idx;
242 : }
243 208 : return 1;
244 : }
245 :
246 : always_inline int
247 0 : acl_fa_restart_timer_for_session (acl_main_t * am, u64 now,
248 : fa_full_session_id_t sess_id)
249 : {
250 0 : if (acl_fa_conn_list_delete_session (am, sess_id, now))
251 : {
252 0 : acl_fa_conn_list_add_session (am, sess_id, now);
253 0 : return 1;
254 : }
255 : else
256 : {
257 : /*
258 : * Our thread does not own this connection, so we can not requeue
259 : * The session. So we post the signal to the owner.
260 : */
261 0 : aclp_post_session_change_request (am, sess_id.thread_index,
262 : sess_id.session_index,
263 : ACL_FA_REQ_SESS_RESCHEDULE);
264 0 : return 0;
265 : }
266 : }
267 :
268 : always_inline int
269 : is_ip6_5tuple (fa_5tuple_t * p5t)
270 : {
271 : return (p5t->l3_zero_pad[0] | p5t->
272 : l3_zero_pad[1] | p5t->l3_zero_pad[2] | p5t->l3_zero_pad[3] | p5t->
273 : l3_zero_pad[4] | p5t->l3_zero_pad[5]) != 0;
274 : }
275 :
276 : always_inline u8
277 168 : acl_fa_track_session (acl_main_t * am, int is_input, u32 sw_if_index, u64 now,
278 : fa_session_t * sess, fa_5tuple_t * pkt_5tuple,
279 : u32 pkt_len)
280 : {
281 168 : sess->last_active_time = now;
282 168 : u8 old_flags = sess->tcp_flags_seen.as_u8[is_input];
283 168 : u8 new_flags = old_flags | pkt_5tuple->pkt.tcp_flags;
284 :
285 336 : int flags_need_update = pkt_5tuple->pkt.tcp_flags_valid
286 168 : && (old_flags != new_flags);
287 168 : if (PREDICT_FALSE (flags_need_update))
288 : {
289 3 : sess->tcp_flags_seen.as_u8[is_input] = new_flags;
290 : }
291 168 : return 3;
292 : }
293 :
294 : always_inline u64
295 134 : reverse_l4_u64_fastpath (u64 l4, int is_ip6)
296 : {
297 134 : fa_session_l4_key_t l4i = {.as_u64 = l4 };
298 : fa_session_l4_key_t l4o;
299 :
300 134 : l4o.port[1] = l4i.port[0];
301 134 : l4o.port[0] = l4i.port[1];
302 :
303 134 : l4o.non_port_l4_data = l4i.non_port_l4_data;
304 134 : l4o.l4_flags = l4i.l4_flags ^ FA_SK_L4_FLAG_IS_INPUT;
305 134 : return l4o.as_u64;
306 : }
307 :
308 : always_inline int
309 34 : reverse_l4_u64_slowpath_valid (u64 l4, int is_ip6, u64 * out)
310 : {
311 34 : fa_session_l4_key_t l4i = {.as_u64 = l4 };
312 : fa_session_l4_key_t l4o;
313 :
314 34 : if (l4i.proto == icmp_protos[is_ip6])
315 : {
316 : static const u8 *icmp_invmap[] = { icmp4_invmap, icmp6_invmap };
317 : static const u8 *icmp_valid_new[] =
318 : { icmp4_valid_new, icmp6_valid_new };
319 : static const u8 icmp_invmap_size[] = { sizeof (icmp4_invmap),
320 : sizeof (icmp6_invmap)
321 : };
322 : static const u8 icmp_valid_new_size[] = { sizeof (icmp4_valid_new),
323 : sizeof (icmp6_valid_new)
324 : };
325 34 : int type = is_ip6 ? l4i.port[0] - 128 : l4i.port[0];
326 :
327 34 : l4o.non_port_l4_data = l4i.non_port_l4_data;
328 34 : l4o.port[0] = l4i.port[0];
329 34 : l4o.port[1] = l4i.port[1];
330 :
331 :
332 : /*
333 : * ONLY ICMP messages defined in icmp4_valid_new/icmp6_valid_new table
334 : * are allowed to create stateful ACL.
335 : * The other messages will be forwarded without creating a reverse session.
336 : */
337 :
338 34 : int valid_reverse_sess = (type >= 0
339 34 : && (type <= icmp_valid_new_size[is_ip6])
340 34 : && (icmp_valid_new[is_ip6][type])
341 34 : && (type <= icmp_invmap_size[is_ip6])
342 68 : && icmp_invmap[is_ip6][type]);
343 34 : if (valid_reverse_sess)
344 : {
345 34 : l4o.l4_flags = l4i.l4_flags ^ FA_SK_L4_FLAG_IS_INPUT;
346 34 : l4o.port[0] = icmp_invmap[is_ip6][type] - 1;
347 : }
348 :
349 34 : *out = l4o.as_u64;
350 34 : return valid_reverse_sess;
351 : }
352 : else
353 0 : *out = reverse_l4_u64_fastpath (l4, is_ip6);
354 :
355 0 : return 1;
356 : }
357 :
358 : always_inline void
359 80 : reverse_session_add_del_ip6 (acl_main_t * am,
360 : clib_bihash_kv_40_8_t * pkv, int is_add)
361 : {
362 : clib_bihash_kv_40_8_t kv2;
363 80 : kv2.key[0] = pkv->key[2];
364 80 : kv2.key[1] = pkv->key[3];
365 80 : kv2.key[2] = pkv->key[0];
366 80 : kv2.key[3] = pkv->key[1];
367 : /* the last u64 needs special treatment (ports, etc.) so we do it last */
368 80 : kv2.value = pkv->value;
369 80 : if (PREDICT_FALSE (is_session_l4_key_u64_slowpath (pkv->key[4])))
370 : {
371 16 : if (reverse_l4_u64_slowpath_valid (pkv->key[4], 1, &kv2.key[4]))
372 16 : clib_bihash_add_del_40_8 (&am->fa_ip6_sessions_hash, &kv2, is_add);
373 : }
374 : else
375 : {
376 64 : kv2.key[4] = reverse_l4_u64_fastpath (pkv->key[4], 1);
377 64 : clib_bihash_add_del_40_8 (&am->fa_ip6_sessions_hash, &kv2, is_add);
378 : }
379 80 : }
380 :
381 : always_inline void
382 88 : reverse_session_add_del_ip4 (acl_main_t * am,
383 : clib_bihash_kv_16_8_t * pkv, int is_add)
384 : {
385 : clib_bihash_kv_16_8_t kv2;
386 88 : kv2.key[0] =
387 88 : ((pkv->key[0] & 0xffffffff) << 32) | ((pkv->key[0] >> 32) & 0xffffffff);
388 : /* the last u64 needs special treatment (ports, etc.) so we do it last */
389 88 : kv2.value = pkv->value;
390 88 : if (PREDICT_FALSE (is_session_l4_key_u64_slowpath (pkv->key[1])))
391 : {
392 18 : if (reverse_l4_u64_slowpath_valid (pkv->key[1], 0, &kv2.key[1]))
393 18 : clib_bihash_add_del_16_8 (&am->fa_ip4_sessions_hash, &kv2, is_add);
394 : }
395 : else
396 : {
397 70 : kv2.key[1] = reverse_l4_u64_fastpath (pkv->key[1], 0);
398 70 : clib_bihash_add_del_16_8 (&am->fa_ip4_sessions_hash, &kv2, is_add);
399 : }
400 88 : }
401 :
402 : always_inline void
403 84 : acl_fa_deactivate_session (acl_main_t * am, u32 sw_if_index,
404 : fa_full_session_id_t sess_id)
405 : {
406 : fa_session_t *sess =
407 84 : get_session_ptr (am, sess_id.thread_index, sess_id.session_index);
408 84 : ASSERT (sess->thread_index == os_get_thread_index ());
409 84 : if (sess->is_ip6)
410 : {
411 40 : clib_bihash_add_del_40_8 (&am->fa_ip6_sessions_hash,
412 : &sess->info.kv_40_8, 0);
413 40 : reverse_session_add_del_ip6 (am, &sess->info.kv_40_8, 0);
414 : }
415 : else
416 : {
417 44 : clib_bihash_add_del_16_8 (&am->fa_ip4_sessions_hash,
418 : &sess->info.kv_16_8, 0);
419 44 : reverse_session_add_del_ip4 (am, &sess->info.kv_16_8, 0);
420 : }
421 :
422 84 : sess->deleted = 1;
423 84 : clib_atomic_fetch_add (&am->fa_session_total_deactivations, 1);
424 84 : }
425 :
426 : always_inline void
427 84 : acl_fa_put_session (acl_main_t * am, u32 sw_if_index,
428 : fa_full_session_id_t sess_id)
429 : {
430 84 : if (sess_id.thread_index != os_get_thread_index ())
431 : {
432 0 : clib_error
433 : ("Attempting to delete session belonging to thread %d by thread %d",
434 : sess_id.thread_index, os_get_thread_index ());
435 : }
436 84 : acl_fa_per_worker_data_t *pw = &am->per_worker_data[sess_id.thread_index];
437 84 : pool_put_index (pw->fa_sessions_pool, sess_id.session_index);
438 : /* Deleting from timer structures not needed,
439 : as the caller must have dealt with the timers. */
440 84 : vec_validate (pw->fa_session_dels_by_sw_if_index, sw_if_index);
441 84 : pw->fa_session_dels_by_sw_if_index[sw_if_index]++;
442 84 : clib_atomic_fetch_add (&am->fa_session_total_dels, 1);
443 84 : }
444 :
445 : always_inline int
446 168 : acl_fa_two_stage_delete_session (acl_main_t * am, u32 sw_if_index,
447 : fa_full_session_id_t sess_id, u64 now)
448 : {
449 : fa_session_t *sess =
450 168 : get_session_ptr (am, sess_id.thread_index, sess_id.session_index);
451 168 : if (sess->deleted)
452 : {
453 84 : acl_fa_put_session (am, sw_if_index, sess_id);
454 84 : return 1;
455 : }
456 : else
457 : {
458 84 : acl_fa_deactivate_session (am, sw_if_index, sess_id);
459 84 : acl_fa_conn_list_add_session (am, sess_id, now);
460 84 : return 0;
461 : }
462 : }
463 :
464 : always_inline int
465 168 : acl_fa_can_add_session (acl_main_t * am, int is_input, u32 sw_if_index)
466 : {
467 : u64 curr_sess_count;
468 168 : curr_sess_count = am->fa_session_total_adds - am->fa_session_total_dels;
469 168 : return (curr_sess_count + vlib_get_n_threads () <
470 168 : am->fa_conn_table_max_entries);
471 : }
472 :
473 :
474 : always_inline void
475 0 : acl_fa_try_recycle_session (acl_main_t * am, int is_input, u16 thread_index,
476 : u32 sw_if_index, u64 now)
477 : {
478 : /* try to recycle a TCP transient session */
479 0 : acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index];
480 : fa_full_session_id_t volatile sess_id;
481 0 : int n_recycled = 0;
482 :
483 : /* clean up sessions from purgatory, if we can */
484 0 : sess_id.session_index = pw->fa_conn_list_head[ACL_TIMEOUT_PURGATORY];
485 0 : while ((FA_SESSION_BOGUS_INDEX != sess_id.session_index)
486 0 : && n_recycled < am->fa_max_deleted_sessions_per_interval)
487 : {
488 0 : sess_id.thread_index = thread_index;
489 : fa_session_t *sess =
490 0 : get_session_ptr (am, sess_id.thread_index, sess_id.session_index);
491 0 : if (sess->link_enqueue_time + fa_session_get_timeout (am, sess) < now)
492 : {
493 0 : acl_fa_conn_list_delete_session (am, sess_id, now);
494 : /* interface that needs the sessions may not be the interface of the session. */
495 0 : acl_fa_put_session (am, sess->sw_if_index, sess_id);
496 0 : n_recycled++;
497 : }
498 : else
499 0 : break; /* too early to try to recycle from here, bail out */
500 0 : sess_id.session_index = pw->fa_conn_list_head[ACL_TIMEOUT_PURGATORY];
501 : }
502 0 : sess_id.session_index = pw->fa_conn_list_head[ACL_TIMEOUT_TCP_TRANSIENT];
503 0 : if (FA_SESSION_BOGUS_INDEX != sess_id.session_index)
504 : {
505 0 : sess_id.thread_index = thread_index;
506 0 : acl_fa_conn_list_delete_session (am, sess_id, now);
507 0 : acl_fa_deactivate_session (am, sw_if_index, sess_id);
508 : /* this goes to purgatory list */
509 0 : acl_fa_conn_list_add_session (am, sess_id, now);
510 : }
511 0 : }
512 :
513 :
514 : always_inline fa_full_session_id_t
515 84 : acl_fa_add_session (acl_main_t * am, int is_input, int is_ip6,
516 : u32 sw_if_index, u64 now, fa_5tuple_t * p5tuple,
517 : u16 current_policy_epoch)
518 : {
519 : fa_full_session_id_t f_sess_id;
520 84 : uword thread_index = os_get_thread_index ();
521 84 : acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index];
522 :
523 84 : f_sess_id.thread_index = thread_index;
524 : fa_session_t *sess;
525 :
526 84 : if (f_sess_id.as_u64 == ~0)
527 : {
528 0 : clib_error ("Adding session with invalid value");
529 : }
530 :
531 84 : pool_get_aligned (pw->fa_sessions_pool, sess, CLIB_CACHE_LINE_BYTES);
532 84 : f_sess_id.session_index = sess - pw->fa_sessions_pool;
533 84 : f_sess_id.intf_policy_epoch = current_policy_epoch;
534 :
535 84 : if (is_ip6)
536 : {
537 40 : sess->info.kv_40_8.key[0] = p5tuple->kv_40_8.key[0];
538 40 : sess->info.kv_40_8.key[1] = p5tuple->kv_40_8.key[1];
539 40 : sess->info.kv_40_8.key[2] = p5tuple->kv_40_8.key[2];
540 40 : sess->info.kv_40_8.key[3] = p5tuple->kv_40_8.key[3];
541 40 : sess->info.kv_40_8.key[4] = p5tuple->kv_40_8.key[4];
542 40 : sess->info.kv_40_8.value = f_sess_id.as_u64;
543 : }
544 : else
545 : {
546 44 : sess->info.kv_16_8.key[0] = p5tuple->kv_16_8.key[0];
547 44 : sess->info.kv_16_8.key[1] = p5tuple->kv_16_8.key[1];
548 44 : sess->info.kv_16_8.value = f_sess_id.as_u64;
549 : }
550 :
551 84 : sess->last_active_time = now;
552 84 : sess->sw_if_index = sw_if_index;
553 84 : sess->tcp_flags_seen.as_u16 = 0;
554 84 : sess->thread_index = thread_index;
555 84 : sess->link_list_id = ACL_TIMEOUT_UNUSED;
556 84 : sess->link_prev_idx = FA_SESSION_BOGUS_INDEX;
557 84 : sess->link_next_idx = FA_SESSION_BOGUS_INDEX;
558 84 : sess->deleted = 0;
559 84 : sess->is_ip6 = is_ip6;
560 :
561 84 : acl_fa_conn_list_add_session (am, f_sess_id, now);
562 :
563 84 : ASSERT (am->fa_sessions_hash_is_initialized == 1);
564 84 : if (is_ip6)
565 : {
566 40 : reverse_session_add_del_ip6 (am, &sess->info.kv_40_8, 1);
567 40 : clib_bihash_add_del_40_8 (&am->fa_ip6_sessions_hash,
568 40 : &sess->info.kv_40_8, 1);
569 : }
570 : else
571 : {
572 44 : reverse_session_add_del_ip4 (am, &sess->info.kv_16_8, 1);
573 44 : clib_bihash_add_del_16_8 (&am->fa_ip4_sessions_hash,
574 44 : &sess->info.kv_16_8, 1);
575 : }
576 :
577 84 : vec_validate (pw->fa_session_adds_by_sw_if_index, sw_if_index);
578 84 : pw->fa_session_adds_by_sw_if_index[sw_if_index]++;
579 84 : clib_atomic_fetch_add (&am->fa_session_total_adds, 1);
580 84 : return f_sess_id;
581 : }
582 :
583 : always_inline int
584 : acl_fa_find_session (acl_main_t * am, int is_ip6, u32 sw_if_index0,
585 : fa_5tuple_t * p5tuple, u64 * pvalue_sess)
586 : {
587 : int res = 0;
588 : if (is_ip6)
589 : {
590 : clib_bihash_kv_40_8_t kv_result;
591 : res = (clib_bihash_search_inline_2_40_8
592 : (&am->fa_ip6_sessions_hash, &p5tuple->kv_40_8, &kv_result) == 0);
593 : *pvalue_sess = kv_result.value;
594 : }
595 : else
596 : {
597 : clib_bihash_kv_16_8_t kv_result;
598 : res = (clib_bihash_search_inline_2_16_8
599 : (&am->fa_ip4_sessions_hash, &p5tuple->kv_16_8, &kv_result) == 0);
600 : *pvalue_sess = kv_result.value;
601 : }
602 : return res;
603 : }
604 :
605 : always_inline u64
606 9498 : acl_fa_make_session_hash (acl_main_t * am, int is_ip6, u32 sw_if_index0,
607 : fa_5tuple_t * p5tuple)
608 : {
609 9498 : if (is_ip6)
610 1266 : return clib_bihash_hash_40_8 (&p5tuple->kv_40_8);
611 : else
612 8232 : return clib_bihash_hash_16_8 (&p5tuple->kv_16_8);
613 : }
614 :
615 : always_inline void
616 8152 : acl_fa_prefetch_session_bucket_for_hash (acl_main_t * am, int is_ip6,
617 : u64 hash)
618 : {
619 8152 : if (is_ip6)
620 863 : clib_bihash_prefetch_bucket_40_8 (&am->fa_ip6_sessions_hash, hash);
621 : else
622 7289 : clib_bihash_prefetch_bucket_16_8 (&am->fa_ip4_sessions_hash, hash);
623 8152 : }
624 :
625 : always_inline void
626 8665 : acl_fa_prefetch_session_data_for_hash (acl_main_t * am, int is_ip6, u64 hash)
627 : {
628 8665 : if (is_ip6)
629 1012 : clib_bihash_prefetch_data_40_8 (&am->fa_ip6_sessions_hash, hash);
630 : else
631 7653 : clib_bihash_prefetch_data_16_8 (&am->fa_ip4_sessions_hash, hash);
632 8665 : }
633 :
634 : always_inline int
635 9498 : acl_fa_find_session_with_hash (acl_main_t * am, int is_ip6, u32 sw_if_index0,
636 : u64 hash, fa_5tuple_t * p5tuple,
637 : u64 * pvalue_sess)
638 : {
639 9498 : int res = 0;
640 9498 : if (is_ip6)
641 : {
642 : clib_bihash_kv_40_8_t kv_result;
643 1266 : kv_result.value = ~0ULL;
644 1266 : res = (clib_bihash_search_inline_2_with_hash_40_8
645 : (&am->fa_ip6_sessions_hash, hash, &p5tuple->kv_40_8,
646 1266 : &kv_result) == 0);
647 1266 : *pvalue_sess = kv_result.value;
648 : }
649 : else
650 : {
651 : clib_bihash_kv_16_8_t kv_result;
652 8232 : kv_result.value = ~0ULL;
653 8232 : res = (clib_bihash_search_inline_2_with_hash_16_8
654 : (&am->fa_ip4_sessions_hash, hash, &p5tuple->kv_16_8,
655 8232 : &kv_result) == 0);
656 8232 : *pvalue_sess = kv_result.value;
657 : }
658 9498 : return res;
659 : }
660 :
661 :
662 : /*
663 : * fd.io coding-style-patch-verification: ON
664 : *
665 : * Local Variables:
666 : * eval: (c-set-style "gnu")
667 : * End:
668 : */
|