blob: b3862ee3920ac1b533992e509d3f4306589d71c9 [file] [log] [blame]
Florin Coras04e53442017-07-16 17:12:15 -07001/*
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:
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/** Generate typed init functions for multiple hash table styles... */
17#include <vppinfra/bihash_16_8.h>
18#include <vppinfra/bihash_template.h>
19
20#include <vppinfra/bihash_template.c>
21
22#undef __included_bihash_template_h__
23
24#include <vppinfra/bihash_48_8.h>
25#include <vppinfra/bihash_template.h>
26
27#include <vppinfra/bihash_template.c>
28#include <vnet/session/session_lookup.h>
29#include <vnet/session/session.h>
30
31static session_lookup_t session_lookup;
32extern transport_proto_vft_t *tp_vfts;
33
34/* *INDENT-OFF* */
35/* 16 octets */
36typedef CLIB_PACKED (struct {
37 union
38 {
39 struct
40 {
41 ip4_address_t src;
42 ip4_address_t dst;
43 u16 src_port;
44 u16 dst_port;
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.
48 */
49 u32 proto;
50 };
51 u64 as_u64[2];
52 };
53}) v4_connection_key_t;
54
55typedef CLIB_PACKED (struct {
56 union
57 {
58 struct
59 {
60 /* 48 octets */
61 ip6_address_t src;
62 ip6_address_t dst;
63 u16 src_port;
64 u16 dst_port;
65 u32 proto;
66 u64 unused;
67 };
68 u64 as_u64[6];
69 };
70}) v6_connection_key_t;
71/* *INDENT-ON* */
72
73typedef clib_bihash_kv_16_8_t session_kv4_t;
74typedef clib_bihash_kv_48_8_t session_kv6_t;
75
76always_inline void
77make_v4_ss_kv (session_kv4_t * kv, ip4_address_t * lcl, ip4_address_t * rmt,
78 u16 lcl_port, u16 rmt_port, u8 proto)
79{
80 v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
81
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;
86 key->proto = proto;
87
88 kv->value = ~0ULL;
89}
90
91always_inline void
92make_v4_listener_kv (session_kv4_t * kv, ip4_address_t * lcl, u16 lcl_port,
93 u8 proto)
94{
95 v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
96
97 key->src.as_u32 = lcl->as_u32;
98 key->dst.as_u32 = 0;
99 key->src_port = lcl_port;
100 key->dst_port = 0;
101 key->proto = proto;
102
103 kv->value = ~0ULL;
104}
105
106always_inline void
107make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * t)
108{
109 return make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port,
110 t->rmt_port, t->proto);
111}
112
113always_inline void
114make_v6_ss_kv (session_kv6_t * kv, ip6_address_t * lcl, ip6_address_t * rmt,
115 u16 lcl_port, u16 rmt_port, u8 proto)
116{
117 v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
118
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;
125 key->proto = proto;
126 key->unused = 0;
127
128 kv->value = ~0ULL;
129}
130
131always_inline void
132make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port,
133 u8 proto)
134{
135 v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
136
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;
142 key->dst_port = 0;
143 key->proto = proto;
144 key->unused = 0;
145
146 kv->value = ~0ULL;
147}
148
149always_inline void
150make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * t)
151{
152 make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port,
153 t->rmt_port, t->proto);
154}
155
156/*
157 * Session lookup key; (src-ip, dst-ip, src-port, dst-port, session-type)
158 * Value: (owner thread index << 32 | session_index);
159 */
160void
161stream_session_table_add_for_tc (transport_connection_t * tc, u64 value)
162{
163 session_lookup_t *sl = &session_lookup;
164 session_kv4_t kv4;
165 session_kv6_t kv6;
166
167 switch (tc->proto)
168 {
169 case SESSION_TYPE_IP4_UDP:
170 case SESSION_TYPE_IP4_TCP:
171 make_v4_ss_kv_from_tc (&kv4, tc);
172 kv4.value = value;
173 clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4, 1 /* is_add */ );
174 break;
175 case SESSION_TYPE_IP6_UDP:
176 case SESSION_TYPE_IP6_TCP:
177 make_v6_ss_kv_from_tc (&kv6, tc);
178 kv6.value = value;
179 clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6, 1 /* is_add */ );
180 break;
181 default:
182 clib_warning ("Session type not supported");
183 ASSERT (0);
184 }
185}
186
187void
188stream_session_table_add (session_manager_main_t * smm, stream_session_t * s,
189 u64 value)
190{
191 transport_connection_t *tc;
192
193 tc = tp_vfts[s->session_type].get_connection (s->connection_index,
194 s->thread_index);
195 stream_session_table_add_for_tc (tc, value);
196}
197
198void
199stream_session_half_open_table_add (session_type_t sst,
200 transport_connection_t * tc, u64 value)
201{
202 session_lookup_t *sl = &session_lookup;
203 session_kv4_t kv4;
204 session_kv6_t kv6;
205
206 switch (sst)
207 {
208 case SESSION_TYPE_IP4_UDP:
209 case SESSION_TYPE_IP4_TCP:
210 make_v4_ss_kv_from_tc (&kv4, tc);
211 kv4.value = value;
212 clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
213 1 /* is_add */ );
214 break;
215 case SESSION_TYPE_IP6_UDP:
216 case SESSION_TYPE_IP6_TCP:
217 make_v6_ss_kv_from_tc (&kv6, tc);
218 kv6.value = value;
219 clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
220 1 /* is_add */ );
221 break;
222 default:
223 clib_warning ("Session type not supported");
224 ASSERT (0);
225 }
226}
227
228int
229stream_session_table_del_for_tc (transport_connection_t * tc)
230{
231 session_lookup_t *sl = &session_lookup;
232 session_kv4_t kv4;
233 session_kv6_t kv6;
234 switch (tc->proto)
235 {
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,
240 0 /* is_add */ );
241 break;
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,
246 0 /* is_add */ );
247 break;
248 default:
249 clib_warning ("Session type not supported");
250 ASSERT (0);
251 }
252
253 return 0;
254}
255
256int
257stream_session_table_del (stream_session_t * s)
258{
259 transport_connection_t *ts;
260 ts = tp_vfts[s->session_type].get_connection (s->connection_index,
261 s->thread_index);
262 return stream_session_table_del_for_tc (ts);
263}
264
265void
266stream_session_half_open_table_del (u8 sst, transport_connection_t * tc)
267{
268 session_lookup_t *sl = &session_lookup;
269 session_kv4_t kv4;
270 session_kv6_t kv6;
271
272 switch (sst)
273 {
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,
278 0 /* is_add */ );
279 break;
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,
284 0 /* is_add */ );
285 break;
286 default:
287 clib_warning ("Session type not supported");
288 ASSERT (0);
289 }
290}
291
292stream_session_t *
293stream_session_lookup_listener4 (ip4_address_t * lcl, u16 lcl_port, u8 proto)
294{
295 session_lookup_t *sl = &session_lookup;
296 session_kv4_t kv4;
297 int rv;
298
299 make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
300 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
301 if (rv == 0)
302 return session_manager_get_listener (proto, (u32) kv4.value);
303
304 /* Zero out the lcl ip */
305 kv4.key[0] = 0;
306 rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
307 if (rv == 0)
308 return session_manager_get_listener (proto, (u32) kv4.value);
309
310 return 0;
311}
312
313/** Looks up a session based on the 5-tuple passed as argument.
314 *
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)
318 */
319stream_session_t *
320stream_session_lookup4 (ip4_address_t * lcl, ip4_address_t * rmt,
321 u16 lcl_port, u16 rmt_port, u8 proto)
322{
323 session_lookup_t *sl = &session_lookup;
324 session_kv4_t kv4;
325 stream_session_t *s;
326 int rv;
327
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);
331 if (rv == 0)
332 return stream_session_get_from_handle (kv4.value);
333
334 /* If nothing is found, check if any listener is available */
335 if ((s = stream_session_lookup_listener4 (lcl, lcl_port, proto)))
336 return s;
337
338 /* Finally, try half-open connections */
339 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
340 if (rv == 0)
341 return stream_session_get_from_handle (kv4.value);
342 return 0;
343}
344
345stream_session_t *
346stream_session_lookup_listener6 (ip6_address_t * lcl, u16 lcl_port, u8 proto)
347{
348 session_lookup_t *sl = &session_lookup;
349 session_kv6_t kv6;
350 int rv;
351
352 make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
353 rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
354 if (rv == 0)
355 return session_manager_get_listener (proto, (u32) kv6.value);
356
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);
360 if (rv == 0)
361 return session_manager_get_listener (proto, (u32) kv6.value);
362
363 return 0;
364}
365
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) */
370stream_session_t *
371stream_session_lookup6 (ip6_address_t * lcl, ip6_address_t * rmt,
372 u16 lcl_port, u16 rmt_port, u8 proto)
373{
374 session_lookup_t *sl = &session_lookup;
375 session_kv6_t kv6;
376 stream_session_t *s;
377 int rv;
378
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);
381 if (rv == 0)
382 return stream_session_get_from_handle (kv6.value);
383
384 /* If nothing is found, check if any listener is available */
385 if ((s = stream_session_lookup_listener6 (lcl, lcl_port, proto)))
386 return s;
387
388 /* Finally, try half-open connections */
389 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
390 if (rv == 0)
391 return stream_session_get_from_handle (kv6.value);
392 return 0;
393}
394
395stream_session_t *
396stream_session_lookup_listener (ip46_address_t * lcl, u16 lcl_port, u8 proto)
397{
398 switch (proto)
399 {
400 case SESSION_TYPE_IP4_UDP:
401 case SESSION_TYPE_IP4_TCP:
402 return stream_session_lookup_listener4 (&lcl->ip4, lcl_port, proto);
403 break;
404 case SESSION_TYPE_IP6_UDP:
405 case SESSION_TYPE_IP6_TCP:
406 return stream_session_lookup_listener6 (&lcl->ip6, lcl_port, proto);
407 break;
408 }
409 return 0;
410}
411
412u64
413stream_session_half_open_lookup_handle (ip46_address_t * lcl,
414 ip46_address_t * rmt, u16 lcl_port,
415 u16 rmt_port, u8 proto)
416{
417 session_lookup_t *sl = &session_lookup;
418 session_kv4_t kv4;
419 session_kv6_t kv6;
420 int rv;
421
422 switch (proto)
423 {
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);
428
429 if (rv == 0)
430 return kv4.value;
431
432 return HALF_OPEN_LOOKUP_INVALID_VALUE;
433 break;
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);
438
439 if (rv == 0)
440 return kv6.value;
441
442 return HALF_OPEN_LOOKUP_INVALID_VALUE;
443 break;
444 }
445 return HALF_OPEN_LOOKUP_INVALID_VALUE;
446}
447
448transport_connection_t *
449stream_session_half_open_lookup (ip46_address_t * lcl, ip46_address_t * rmt,
450 u16 lcl_port, u16 rmt_port, u8 proto)
451{
452 u64 handle;
453 handle =
454 stream_session_half_open_lookup_handle (lcl, rmt, lcl_port, rmt_port,
455 proto);
456 if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
457 return tp_vfts[proto].get_half_open (handle & 0xFFFFFFFF);
458 return 0;
459}
460
461always_inline stream_session_t *
462stream_session_get_tsi (u64 ti_and_si, u32 thread_index)
463{
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);
467}
468
469transport_connection_t *
470stream_session_lookup_transport_wt4 (ip4_address_t * lcl, ip4_address_t * rmt,
471 u16 lcl_port, u16 rmt_port, u8 proto,
472 u32 my_thread_index)
473{
474 session_lookup_t *sl = &session_lookup;
475 session_kv4_t kv4;
476 stream_session_t *s;
477 int rv;
478
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);
482 if (rv == 0)
483 {
484 s = stream_session_get_tsi (kv4.value, my_thread_index);
485 return tp_vfts[s->session_type].get_connection (s->connection_index,
486 my_thread_index);
487 }
488
489 /* If nothing is found, check if any listener is available */
490 s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
491 if (s)
492 return tp_vfts[s->session_type].get_listener (s->connection_index);
493
494 /* Finally, try half-open connections */
495 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
496 if (rv == 0)
497 return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
498 return 0;
499}
500
501transport_connection_t *
502stream_session_lookup_transport4 (ip4_address_t * lcl, ip4_address_t * rmt,
503 u16 lcl_port, u16 rmt_port, u8 proto)
504{
505 session_lookup_t *sl = &session_lookup;
506 session_kv4_t kv4;
507 stream_session_t *s;
508 int rv;
509
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);
513 if (rv == 0)
514 {
515 s = stream_session_get_from_handle (kv4.value);
516 return tp_vfts[s->session_type].get_connection (s->connection_index,
517 s->thread_index);
518 }
519
520 /* If nothing is found, check if any listener is available */
521 s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
522 if (s)
523 return tp_vfts[s->session_type].get_listener (s->connection_index);
524
525 /* Finally, try half-open connections */
526 rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
527 if (rv == 0)
528 return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
529 return 0;
530}
531
532transport_connection_t *
533stream_session_lookup_transport_wt6 (ip6_address_t * lcl, ip6_address_t * rmt,
534 u16 lcl_port, u16 rmt_port, u8 proto,
535 u32 my_thread_index)
536{
537 session_lookup_t *sl = &session_lookup;
538 stream_session_t *s;
539 session_kv6_t kv6;
540 int rv;
541
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);
544 if (rv == 0)
545 {
546 s = stream_session_get_tsi (kv6.value, my_thread_index);
547 return tp_vfts[s->session_type].get_connection (s->connection_index,
548 my_thread_index);
549 }
550
551 /* If nothing is found, check if any listener is available */
552 s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
553 if (s)
554 return tp_vfts[s->session_type].get_listener (s->connection_index);
555
556 /* Finally, try half-open connections */
557 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
558 if (rv == 0)
559 return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
560
561 return 0;
562}
563
564transport_connection_t *
565stream_session_lookup_transport6 (ip6_address_t * lcl, ip6_address_t * rmt,
566 u16 lcl_port, u16 rmt_port, u8 proto)
567{
568 session_lookup_t *sl = &session_lookup;
569 stream_session_t *s;
570 session_kv6_t kv6;
571 int rv;
572
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);
575 if (rv == 0)
576 {
577 s = stream_session_get_from_handle (kv6.value);
578 return tp_vfts[s->session_type].get_connection (s->connection_index,
579 s->thread_index);
580 }
581
582 /* If nothing is found, check if any listener is available */
583 s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
584 if (s)
585 return tp_vfts[s->session_type].get_listener (s->connection_index);
586
587 /* Finally, try half-open connections */
588 rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
589 if (rv == 0)
590 return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
591
592 return 0;
593}
594
595void
596session_lookup_init (void)
597{
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 */ );
605
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 */ );
612}
613
614/*
615 * fd.io coding-style-patch-verification: ON
616 *
617 * Local Variables:
618 * eval: (c-set-style "gnu")
619 * End:
620 */