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->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->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 case SESSION_TYPE_IP4_UDP:
170 case SESSION_TYPE_IP4_TCP:
171 make_v4_ss_kv_from_tc (&kv4, tc);
173 clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4, 1 /* is_add */ );
175 case SESSION_TYPE_IP6_UDP:
176 case SESSION_TYPE_IP6_TCP:
177 make_v6_ss_kv_from_tc (&kv6, tc);
179 clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6, 1 /* is_add */ );
182 clib_warning ("Session type not supported");
188 stream_session_table_add (session_manager_main_t * smm, stream_session_t * s,
191 transport_connection_t *tc;
193 tc = tp_vfts[s->session_type].get_connection (s->connection_index,
195 stream_session_table_add_for_tc (tc, value);
199 stream_session_half_open_table_add (session_type_t sst,
200 transport_connection_t * tc, u64 value)
202 session_lookup_t *sl = &session_lookup;
208 case SESSION_TYPE_IP4_UDP:
209 case SESSION_TYPE_IP4_TCP:
210 make_v4_ss_kv_from_tc (&kv4, tc);
212 clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
215 case SESSION_TYPE_IP6_UDP:
216 case SESSION_TYPE_IP6_TCP:
217 make_v6_ss_kv_from_tc (&kv6, tc);
219 clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
223 clib_warning ("Session type not supported");
229 stream_session_table_del_for_tc (transport_connection_t * tc)
231 session_lookup_t *sl = &session_lookup;
236 case SESSION_TYPE_IP4_UDP:
237 case SESSION_TYPE_IP4_TCP:
238 make_v4_ss_kv_from_tc (&kv4, tc);
239 return clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4,
242 case SESSION_TYPE_IP6_UDP:
243 case SESSION_TYPE_IP6_TCP:
244 make_v6_ss_kv_from_tc (&kv6, tc);
245 return clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6,
249 clib_warning ("Session type not supported");
257 stream_session_table_del (stream_session_t * s)
259 transport_connection_t *ts;
260 ts = tp_vfts[s->session_type].get_connection (s->connection_index,
262 return stream_session_table_del_for_tc (ts);
266 stream_session_half_open_table_del (u8 sst, transport_connection_t * tc)
268 session_lookup_t *sl = &session_lookup;
274 case SESSION_TYPE_IP4_UDP:
275 case SESSION_TYPE_IP4_TCP:
276 make_v4_ss_kv_from_tc (&kv4, tc);
277 clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
280 case SESSION_TYPE_IP6_UDP:
281 case SESSION_TYPE_IP6_TCP:
282 make_v6_ss_kv_from_tc (&kv6, tc);
283 clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
287 clib_warning ("Session type not supported");
293 stream_session_lookup_listener4 (ip4_address_t * lcl, u16 lcl_port, u8 proto)
295 session_lookup_t *sl = &session_lookup;
299 make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
300 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
302 return session_manager_get_listener (proto, (u32) kv4.value);
304 /* Zero out the lcl ip */
306 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
308 return session_manager_get_listener (proto, (u32) kv4.value);
313 /** Looks up a session based on the 5-tuple passed as argument.
315 * First it tries to find an established session, if this fails, it tries
316 * finding a listener session if this fails, it tries a lookup with a
317 * wildcarded local source (listener bound to all interfaces)
320 stream_session_lookup4 (ip4_address_t * lcl, ip4_address_t * rmt,
321 u16 lcl_port, u16 rmt_port, u8 proto)
323 session_lookup_t *sl = &session_lookup;
328 /* Lookup session amongst established ones */
329 make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
330 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
332 return stream_session_get_from_handle (kv4.value);
334 /* If nothing is found, check if any listener is available */
335 if ((s = stream_session_lookup_listener4 (lcl, lcl_port, proto)))
338 /* Finally, try half-open connections */
339 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
341 return stream_session_get_from_handle (kv4.value);
346 stream_session_lookup_listener6 (ip6_address_t * lcl, u16 lcl_port, u8 proto)
348 session_lookup_t *sl = &session_lookup;
352 make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
353 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
355 return session_manager_get_listener (proto, (u32) kv6.value);
357 /* Zero out the lcl ip */
358 kv6.key[0] = kv6.key[1] = 0;
359 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
361 return session_manager_get_listener (proto, (u32) kv6.value);
366 /* Looks up a session based on the 5-tuple passed as argument.
367 * First it tries to find an established session, if this fails, it tries
368 * finding a listener session if this fails, it tries a lookup with a
369 * wildcarded local source (listener bound to all interfaces) */
371 stream_session_lookup6 (ip6_address_t * lcl, ip6_address_t * rmt,
372 u16 lcl_port, u16 rmt_port, u8 proto)
374 session_lookup_t *sl = &session_lookup;
379 make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
380 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
382 return stream_session_get_from_handle (kv6.value);
384 /* If nothing is found, check if any listener is available */
385 if ((s = stream_session_lookup_listener6 (lcl, lcl_port, proto)))
388 /* Finally, try half-open connections */
389 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
391 return stream_session_get_from_handle (kv6.value);
396 stream_session_lookup_listener (ip46_address_t * lcl, u16 lcl_port, u8 proto)
400 case SESSION_TYPE_IP4_UDP:
401 case SESSION_TYPE_IP4_TCP:
402 return stream_session_lookup_listener4 (&lcl->ip4, lcl_port, proto);
404 case SESSION_TYPE_IP6_UDP:
405 case SESSION_TYPE_IP6_TCP:
406 return stream_session_lookup_listener6 (&lcl->ip6, lcl_port, proto);
413 stream_session_half_open_lookup_handle (ip46_address_t * lcl,
414 ip46_address_t * rmt, u16 lcl_port,
415 u16 rmt_port, u8 proto)
417 session_lookup_t *sl = &session_lookup;
424 case SESSION_TYPE_IP4_UDP:
425 case SESSION_TYPE_IP4_TCP:
426 make_v4_ss_kv (&kv4, &lcl->ip4, &rmt->ip4, lcl_port, rmt_port, proto);
427 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
432 return HALF_OPEN_LOOKUP_INVALID_VALUE;
434 case SESSION_TYPE_IP6_UDP:
435 case SESSION_TYPE_IP6_TCP:
436 make_v6_ss_kv (&kv6, &lcl->ip6, &rmt->ip6, lcl_port, rmt_port, proto);
437 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
442 return HALF_OPEN_LOOKUP_INVALID_VALUE;
445 return HALF_OPEN_LOOKUP_INVALID_VALUE;
448 transport_connection_t *
449 stream_session_half_open_lookup (ip46_address_t * lcl, ip46_address_t * rmt,
450 u16 lcl_port, u16 rmt_port, u8 proto)
454 stream_session_half_open_lookup_handle (lcl, rmt, lcl_port, rmt_port,
456 if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
457 return tp_vfts[proto].get_half_open (handle & 0xFFFFFFFF);
461 always_inline stream_session_t *
462 stream_session_get_tsi (u64 ti_and_si, u32 thread_index)
464 ASSERT ((u32) (ti_and_si >> 32) == thread_index);
465 return pool_elt_at_index (session_manager_main.sessions[thread_index],
466 ti_and_si & 0xFFFFFFFFULL);
469 transport_connection_t *
470 stream_session_lookup_transport_wt4 (ip4_address_t * lcl, ip4_address_t * rmt,
471 u16 lcl_port, u16 rmt_port, u8 proto,
474 session_lookup_t *sl = &session_lookup;
479 /* Lookup session amongst established ones */
480 make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
481 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
484 s = stream_session_get_tsi (kv4.value, my_thread_index);
485 return tp_vfts[s->session_type].get_connection (s->connection_index,
489 /* If nothing is found, check if any listener is available */
490 s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
492 return tp_vfts[s->session_type].get_listener (s->connection_index);
494 /* Finally, try half-open connections */
495 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
497 return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
501 transport_connection_t *
502 stream_session_lookup_transport4 (ip4_address_t * lcl, ip4_address_t * rmt,
503 u16 lcl_port, u16 rmt_port, u8 proto)
505 session_lookup_t *sl = &session_lookup;
510 /* Lookup session amongst established ones */
511 make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
512 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
515 s = stream_session_get_from_handle (kv4.value);
516 return tp_vfts[s->session_type].get_connection (s->connection_index,
520 /* If nothing is found, check if any listener is available */
521 s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
523 return tp_vfts[s->session_type].get_listener (s->connection_index);
525 /* Finally, try half-open connections */
526 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
528 return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
532 transport_connection_t *
533 stream_session_lookup_transport_wt6 (ip6_address_t * lcl, ip6_address_t * rmt,
534 u16 lcl_port, u16 rmt_port, u8 proto,
537 session_lookup_t *sl = &session_lookup;
542 make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
543 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
546 s = stream_session_get_tsi (kv6.value, my_thread_index);
547 return tp_vfts[s->session_type].get_connection (s->connection_index,
551 /* If nothing is found, check if any listener is available */
552 s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
554 return tp_vfts[s->session_type].get_listener (s->connection_index);
556 /* Finally, try half-open connections */
557 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
559 return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
564 transport_connection_t *
565 stream_session_lookup_transport6 (ip6_address_t * lcl, ip6_address_t * rmt,
566 u16 lcl_port, u16 rmt_port, u8 proto)
568 session_lookup_t *sl = &session_lookup;
573 make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
574 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
577 s = stream_session_get_from_handle (kv6.value);
578 return tp_vfts[s->session_type].get_connection (s->connection_index,
582 /* If nothing is found, check if any listener is available */
583 s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
585 return tp_vfts[s->session_type].get_listener (s->connection_index);
587 /* Finally, try half-open connections */
588 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
590 return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
596 session_lookup_init (void)
598 session_lookup_t *sl = &session_lookup;
599 clib_bihash_init_16_8 (&sl->v4_session_hash, "v4 session table",
600 200000 /* $$$$ config parameter nbuckets */ ,
601 (64 << 20) /*$$$ config parameter table size */ );
602 clib_bihash_init_48_8 (&sl->v6_session_hash, "v6 session table",
603 200000 /* $$$$ config parameter nbuckets */ ,
604 (64 << 20) /*$$$ config parameter table size */ );
606 clib_bihash_init_16_8 (&sl->v4_half_open_hash, "v4 half-open table",
607 200000 /* $$$$ config parameter nbuckets */ ,
608 (64 << 20) /*$$$ config parameter table size */ );
609 clib_bihash_init_48_8 (&sl->v6_half_open_hash, "v6 half-open table",
610 200000 /* $$$$ config parameter nbuckets */ ,
611 (64 << 20) /*$$$ config parameter table size */ );
615 * fd.io coding-style-patch-verification: ON
618 * eval: (c-set-style "gnu")