2 * Copyright (c) 2017 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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 /** Generate typed init functions for multiple hash table styles... */
17 #include <vppinfra/bihash_16_8.h>
18 #include <vppinfra/bihash_template.h>
20 #include <vppinfra/bihash_template.c>
22 #undef __included_bihash_template_h__
24 #include <vppinfra/bihash_48_8.h>
25 #include <vppinfra/bihash_template.h>
27 #include <vppinfra/bihash_template.c>
28 #include <vnet/session/session_lookup.h>
29 #include <vnet/session/session.h>
31 static session_lookup_t session_lookup;
32 extern transport_proto_vft_t *tp_vfts;
36 typedef CLIB_PACKED (struct {
45 /* align by making this 4 octets even though its a 1-bit field
46 * NOTE: avoid key overlap with other transports that use 5 tuples for
47 * session identification.
53 }) v4_connection_key_t;
55 typedef CLIB_PACKED (struct {
70 }) v6_connection_key_t;
73 typedef clib_bihash_kv_16_8_t session_kv4_t;
74 typedef clib_bihash_kv_48_8_t session_kv6_t;
77 make_v4_ss_kv (session_kv4_t * kv, ip4_address_t * lcl, ip4_address_t * rmt,
78 u16 lcl_port, u16 rmt_port, u8 proto)
80 v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
82 key->src.as_u32 = lcl->as_u32;
83 key->dst.as_u32 = rmt->as_u32;
84 key->src_port = lcl_port;
85 key->dst_port = rmt_port;
92 make_v4_listener_kv (session_kv4_t * kv, ip4_address_t * lcl, u16 lcl_port,
95 v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
97 key->src.as_u32 = lcl->as_u32;
99 key->src_port = lcl_port;
107 make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * t)
109 return make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port,
110 t->rmt_port, t->transport_proto);
114 make_v6_ss_kv (session_kv6_t * kv, ip6_address_t * lcl, ip6_address_t * rmt,
115 u16 lcl_port, u16 rmt_port, u8 proto)
117 v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
119 key->src.as_u64[0] = lcl->as_u64[0];
120 key->src.as_u64[1] = lcl->as_u64[1];
121 key->dst.as_u64[0] = rmt->as_u64[0];
122 key->dst.as_u64[1] = rmt->as_u64[1];
123 key->src_port = lcl_port;
124 key->dst_port = rmt_port;
132 make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port,
135 v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
137 key->src.as_u64[0] = lcl->as_u64[0];
138 key->src.as_u64[1] = lcl->as_u64[1];
139 key->dst.as_u64[0] = 0;
140 key->dst.as_u64[1] = 0;
141 key->src_port = lcl_port;
150 make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * t)
152 make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port,
153 t->rmt_port, t->transport_proto);
157 * Session lookup key; (src-ip, dst-ip, src-port, dst-port, session-type)
158 * Value: (owner thread index << 32 | session_index);
161 stream_session_table_add_for_tc (transport_connection_t * tc, u64 value)
163 session_lookup_t *sl = &session_lookup;
169 make_v4_ss_kv_from_tc (&kv4, tc);
171 clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4, 1 /* is_add */ );
175 make_v6_ss_kv_from_tc (&kv6, tc);
177 clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6, 1 /* is_add */ );
182 stream_session_table_add (session_manager_main_t * smm, stream_session_t * s,
185 transport_connection_t *tc;
187 tc = tp_vfts[s->session_type].get_connection (s->connection_index,
189 stream_session_table_add_for_tc (tc, value);
193 stream_session_table_del_for_tc (transport_connection_t * tc)
195 session_lookup_t *sl = &session_lookup;
201 make_v4_ss_kv_from_tc (&kv4, tc);
202 return clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4,
207 make_v6_ss_kv_from_tc (&kv6, tc);
208 return clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6,
216 stream_session_table_del (stream_session_t * s)
218 transport_connection_t *ts;
219 ts = tp_vfts[s->session_type].get_connection (s->connection_index,
221 return stream_session_table_del_for_tc (ts);
226 stream_session_half_open_table_add (transport_connection_t * tc, u64 value)
228 session_lookup_t *sl = &session_lookup;
234 make_v4_ss_kv_from_tc (&kv4, tc);
236 clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
241 make_v6_ss_kv_from_tc (&kv6, tc);
243 clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
249 stream_session_half_open_table_del (transport_connection_t * tc)
251 session_lookup_t *sl = &session_lookup;
257 make_v4_ss_kv_from_tc (&kv4, tc);
258 clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
263 make_v6_ss_kv_from_tc (&kv6, tc);
264 clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
270 stream_session_lookup_listener4 (ip4_address_t * lcl, u16 lcl_port, u8 proto)
272 session_lookup_t *sl = &session_lookup;
276 make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
277 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
279 return session_manager_get_listener (proto, (u32) kv4.value);
281 /* Zero out the lcl ip */
283 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
285 return session_manager_get_listener (proto, (u32) kv4.value);
290 /** Looks up a session based on the 5-tuple passed as argument.
292 * First it tries to find an established session, if this fails, it tries
293 * finding a listener session if this fails, it tries a lookup with a
294 * wildcarded local source (listener bound to all interfaces)
297 stream_session_lookup4 (ip4_address_t * lcl, ip4_address_t * rmt,
298 u16 lcl_port, u16 rmt_port, u8 proto)
300 session_lookup_t *sl = &session_lookup;
305 /* Lookup session amongst established ones */
306 make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
307 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
309 return stream_session_get_from_handle (kv4.value);
311 /* If nothing is found, check if any listener is available */
312 if ((s = stream_session_lookup_listener4 (lcl, lcl_port, proto)))
315 /* Finally, try half-open connections */
316 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
318 return stream_session_get_from_handle (kv4.value);
323 stream_session_lookup_listener6 (ip6_address_t * lcl, u16 lcl_port, u8 proto)
325 session_lookup_t *sl = &session_lookup;
329 make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
330 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
332 return session_manager_get_listener (proto, (u32) kv6.value);
334 /* Zero out the lcl ip */
335 kv6.key[0] = kv6.key[1] = 0;
336 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
338 return session_manager_get_listener (proto, (u32) kv6.value);
343 /* Looks up a session based on the 5-tuple passed as argument.
344 * First it tries to find an established session, if this fails, it tries
345 * finding a listener session if this fails, it tries a lookup with a
346 * wildcarded local source (listener bound to all interfaces) */
348 stream_session_lookup6 (ip6_address_t * lcl, ip6_address_t * rmt,
349 u16 lcl_port, u16 rmt_port, u8 proto)
351 session_lookup_t *sl = &session_lookup;
356 make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
357 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
359 return stream_session_get_from_handle (kv6.value);
361 /* If nothing is found, check if any listener is available */
362 if ((s = stream_session_lookup_listener6 (lcl, lcl_port, proto)))
365 /* Finally, try half-open connections */
366 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
368 return stream_session_get_from_handle (kv6.value);
373 stream_session_lookup_listener (ip46_address_t * lcl, u16 lcl_port, u8 proto)
377 case SESSION_TYPE_IP4_UDP:
378 case SESSION_TYPE_IP4_TCP:
379 return stream_session_lookup_listener4 (&lcl->ip4, lcl_port, proto);
381 case SESSION_TYPE_IP6_UDP:
382 case SESSION_TYPE_IP6_TCP:
383 return stream_session_lookup_listener6 (&lcl->ip6, lcl_port, proto);
390 stream_session_half_open_lookup_handle (ip46_address_t * lcl,
391 ip46_address_t * rmt, u16 lcl_port,
392 u16 rmt_port, u8 proto)
394 session_lookup_t *sl = &session_lookup;
401 case SESSION_TYPE_IP4_UDP:
402 case SESSION_TYPE_IP4_TCP:
403 make_v4_ss_kv (&kv4, &lcl->ip4, &rmt->ip4, lcl_port, rmt_port, proto);
404 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
409 return HALF_OPEN_LOOKUP_INVALID_VALUE;
411 case SESSION_TYPE_IP6_UDP:
412 case SESSION_TYPE_IP6_TCP:
413 make_v6_ss_kv (&kv6, &lcl->ip6, &rmt->ip6, lcl_port, rmt_port, proto);
414 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
419 return HALF_OPEN_LOOKUP_INVALID_VALUE;
422 return HALF_OPEN_LOOKUP_INVALID_VALUE;
425 transport_connection_t *
426 stream_session_half_open_lookup (ip46_address_t * lcl, ip46_address_t * rmt,
427 u16 lcl_port, u16 rmt_port, u8 proto)
431 stream_session_half_open_lookup_handle (lcl, rmt, lcl_port, rmt_port,
433 if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
434 return tp_vfts[proto].get_half_open (handle & 0xFFFFFFFF);
438 always_inline stream_session_t *
439 stream_session_get_tsi (u64 ti_and_si, u32 thread_index)
441 ASSERT ((u32) (ti_and_si >> 32) == thread_index);
442 return pool_elt_at_index (session_manager_main.sessions[thread_index],
443 ti_and_si & 0xFFFFFFFFULL);
446 transport_connection_t *
447 stream_session_lookup_transport_wt4 (ip4_address_t * lcl, ip4_address_t * rmt,
448 u16 lcl_port, u16 rmt_port, u8 proto,
451 session_lookup_t *sl = &session_lookup;
456 /* Lookup session amongst established ones */
457 make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
458 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
461 s = stream_session_get_tsi (kv4.value, my_thread_index);
462 return tp_vfts[s->session_type].get_connection (s->connection_index,
466 /* If nothing is found, check if any listener is available */
467 s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
469 return tp_vfts[s->session_type].get_listener (s->connection_index);
471 /* Finally, try half-open connections */
472 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
474 return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
478 transport_connection_t *
479 stream_session_lookup_transport4 (ip4_address_t * lcl, ip4_address_t * rmt,
480 u16 lcl_port, u16 rmt_port, u8 proto)
482 session_lookup_t *sl = &session_lookup;
487 /* Lookup session amongst established ones */
488 make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
489 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
492 s = stream_session_get_from_handle (kv4.value);
493 return tp_vfts[s->session_type].get_connection (s->connection_index,
497 /* If nothing is found, check if any listener is available */
498 s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
500 return tp_vfts[s->session_type].get_listener (s->connection_index);
502 /* Finally, try half-open connections */
503 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
505 return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
509 transport_connection_t *
510 stream_session_lookup_transport_wt6 (ip6_address_t * lcl, ip6_address_t * rmt,
511 u16 lcl_port, u16 rmt_port, u8 proto,
514 session_lookup_t *sl = &session_lookup;
519 make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
520 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
523 s = stream_session_get_tsi (kv6.value, my_thread_index);
524 return tp_vfts[s->session_type].get_connection (s->connection_index,
528 /* If nothing is found, check if any listener is available */
529 s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
531 return tp_vfts[s->session_type].get_listener (s->connection_index);
533 /* Finally, try half-open connections */
534 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
536 return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
541 transport_connection_t *
542 stream_session_lookup_transport6 (ip6_address_t * lcl, ip6_address_t * rmt,
543 u16 lcl_port, u16 rmt_port, u8 proto)
545 session_lookup_t *sl = &session_lookup;
550 make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
551 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
554 s = stream_session_get_from_handle (kv6.value);
555 return tp_vfts[s->session_type].get_connection (s->connection_index,
559 /* If nothing is found, check if any listener is available */
560 s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
562 return tp_vfts[s->session_type].get_listener (s->connection_index);
564 /* Finally, try half-open connections */
565 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
567 return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
572 #define foreach_hash_table_parameter \
573 _(v4,session,buckets,20000) \
574 _(v4,session,memory,(64<<20)) \
575 _(v6,session,buckets,20000) \
576 _(v6,session,memory,(64<<20)) \
577 _(v4,halfopen,buckets,20000) \
578 _(v4,halfopen,memory,(64<<20)) \
579 _(v6,halfopen,buckets,20000) \
580 _(v6,halfopen,memory,(64<<20))
583 session_lookup_init (void)
585 session_lookup_t *sl = &session_lookup;
587 #define _(af,table,parm,value) \
588 u32 configured_##af##_##table##_table_##parm = value;
589 foreach_hash_table_parameter;
592 #define _(af,table,parm,value) \
593 if (session_manager_main.configured_##af##_##table##_table_##parm) \
594 configured_##af##_##table##_table_##parm = \
595 session_manager_main.configured_##af##_##table##_table_##parm;
596 foreach_hash_table_parameter;
599 clib_bihash_init_16_8 (&sl->v4_session_hash, "v4 session table",
600 configured_v4_session_table_buckets,
601 configured_v4_session_table_memory);
602 clib_bihash_init_48_8 (&sl->v6_session_hash, "v6 session table",
603 configured_v6_session_table_buckets,
604 configured_v6_session_table_memory);
605 clib_bihash_init_16_8 (&sl->v4_half_open_hash, "v4 half-open table",
606 configured_v4_halfopen_table_buckets,
607 configured_v4_halfopen_table_memory);
608 clib_bihash_init_48_8 (&sl->v6_half_open_hash, "v6 half-open table",
609 configured_v6_halfopen_table_buckets,
610 configured_v6_halfopen_table_memory);
614 * fd.io coding-style-patch-verification: ON
617 * eval: (c-set-style "gnu")