FD.io VPP  v17.10-9-gd594711
Vector Packet Processing
session_lookup.c
Go to the documentation of this file.
1 /*
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>
19 
21 
22 #undef __included_bihash_template_h__
23 
24 #include <vppinfra/bihash_48_8.h>
26 
29 #include <vnet/session/session.h>
30 
33 
34 /* *INDENT-OFF* */
35 /* 16 octets */
36 typedef 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 
55 typedef 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  };
71 /* *INDENT-ON* */
72 
75 
76 always_inline void
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)
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 
91 always_inline void
92 make_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 
106 always_inline void
108 {
109  make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port, t->rmt_port,
110  session_type_from_proto_and_ip (t->transport_proto, 1));
111 }
112 
113 always_inline void
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)
116 {
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 
131 always_inline void
132 make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port,
133  u8 proto)
134 {
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 
149 always_inline void
151 {
152  make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port, t->rmt_port,
153  session_type_from_proto_and_ip (t->transport_proto, 0));
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  */
160 void
162 {
164  session_kv4_t kv4;
165  session_kv6_t kv6;
166 
167  if (tc->is_ip4)
168  {
169  make_v4_ss_kv_from_tc (&kv4, tc);
170  kv4.value = value;
171  clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4, 1 /* is_add */ );
172  }
173  else
174  {
175  make_v6_ss_kv_from_tc (&kv6, tc);
176  kv6.value = value;
177  clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6, 1 /* is_add */ );
178  }
179 }
180 
181 void
183  u64 value)
184 {
186 
187  tc = tp_vfts[s->session_type].get_connection (s->connection_index,
188  s->thread_index);
190 }
191 
192 int
194 {
196  session_kv4_t kv4;
197  session_kv6_t kv6;
198 
199  if (tc->is_ip4)
200  {
201  make_v4_ss_kv_from_tc (&kv4, tc);
202  return clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4,
203  0 /* is_add */ );
204  }
205  else
206  {
207  make_v6_ss_kv_from_tc (&kv6, tc);
208  return clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6,
209  0 /* is_add */ );
210  }
211 
212  return 0;
213 }
214 
215 int
217 {
219  ts = tp_vfts[s->session_type].get_connection (s->connection_index,
220  s->thread_index);
222 }
223 
224 
225 void
227 {
229  session_kv4_t kv4;
230  session_kv6_t kv6;
231 
232  if (tc->is_ip4)
233  {
234  make_v4_ss_kv_from_tc (&kv4, tc);
235  kv4.value = value;
236  (void) clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
237  1 /* is_add */ );
238  }
239  else
240  {
241  make_v6_ss_kv_from_tc (&kv6, tc);
242  kv6.value = value;
243  (void) clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
244  1 /* is_add */ );
245  }
246 }
247 
248 void
250 {
252  session_kv4_t kv4;
253  session_kv6_t kv6;
254 
255  if (tc->is_ip4)
256  {
257  make_v4_ss_kv_from_tc (&kv4, tc);
258  clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
259  0 /* is_add */ );
260  }
261  else
262  {
263  make_v6_ss_kv_from_tc (&kv6, tc);
264  clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
265  0 /* is_add */ );
266  }
267 }
268 
271 {
273  session_kv4_t kv4;
274  int rv;
275 
276  make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
277  rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
278  if (rv == 0)
279  return session_manager_get_listener (proto, (u32) kv4.value);
280 
281  /* Zero out the lcl ip */
282  kv4.key[0] = 0;
283  rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
284  if (rv == 0)
285  return session_manager_get_listener (proto, (u32) kv4.value);
286 
287  return 0;
288 }
289 
290 /** Looks up a session based on the 5-tuple passed as argument.
291  *
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)
295  */
298  u16 lcl_port, u16 rmt_port, u8 proto)
299 {
301  session_kv4_t kv4;
302  stream_session_t *s;
303  int rv;
304 
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);
308  if (rv == 0)
310 
311  /* If nothing is found, check if any listener is available */
312  if ((s = stream_session_lookup_listener4 (lcl, lcl_port, proto)))
313  return s;
314 
315  /* Finally, try half-open connections */
316  rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
317  if (rv == 0)
319  return 0;
320 }
321 
324 {
326  session_kv6_t kv6;
327  int rv;
328 
329  make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
330  rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
331  if (rv == 0)
332  return session_manager_get_listener (proto, (u32) kv6.value);
333 
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);
337  if (rv == 0)
338  return session_manager_get_listener (proto, (u32) kv6.value);
339 
340  return 0;
341 }
342 
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) */
349  u16 lcl_port, u16 rmt_port, u8 proto)
350 {
352  session_kv6_t kv6;
353  stream_session_t *s;
354  int rv;
355 
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);
358  if (rv == 0)
360 
361  /* If nothing is found, check if any listener is available */
362  if ((s = stream_session_lookup_listener6 (lcl, lcl_port, proto)))
363  return s;
364 
365  /* Finally, try half-open connections */
366  rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
367  if (rv == 0)
369  return 0;
370 }
371 
373 stream_session_lookup_listener (ip46_address_t * lcl, u16 lcl_port, u8 proto)
374 {
375  switch (proto)
376  {
377  case SESSION_TYPE_IP4_UDP:
378  case SESSION_TYPE_IP4_TCP:
379  return stream_session_lookup_listener4 (&lcl->ip4, lcl_port, proto);
380  break;
381  case SESSION_TYPE_IP6_UDP:
382  case SESSION_TYPE_IP6_TCP:
383  return stream_session_lookup_listener6 (&lcl->ip6, lcl_port, proto);
384  break;
385  }
386  return 0;
387 }
388 
389 u64
391  ip46_address_t * rmt, u16 lcl_port,
392  u16 rmt_port, u8 proto)
393 {
395  session_kv4_t kv4;
396  session_kv6_t kv6;
397  int rv;
398 
399  switch (proto)
400  {
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);
405 
406  if (rv == 0)
407  return kv4.value;
408 
410  break;
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);
415 
416  if (rv == 0)
417  return kv6.value;
418 
420  break;
421  }
423 }
424 
426 stream_session_half_open_lookup (ip46_address_t * lcl, ip46_address_t * rmt,
427  u16 lcl_port, u16 rmt_port, u8 proto)
428 {
429  u64 handle;
430  handle =
431  stream_session_half_open_lookup_handle (lcl, rmt, lcl_port, rmt_port,
432  proto);
433  if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
434  return tp_vfts[proto].get_half_open (handle & 0xFFFFFFFF);
435  return 0;
436 }
437 
439 stream_session_get_tsi (u64 ti_and_si, u32 thread_index)
440 {
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);
444 }
445 
448  u16 lcl_port, u16 rmt_port, u8 proto,
449  u32 my_thread_index)
450 {
452  session_kv4_t kv4;
453  stream_session_t *s;
454  int rv;
455 
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);
459  if (rv == 0)
460  {
461  s = stream_session_get_tsi (kv4.value, my_thread_index);
462  return tp_vfts[s->session_type].get_connection (s->connection_index,
463  my_thread_index);
464  }
465 
466  /* If nothing is found, check if any listener is available */
467  s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
468  if (s)
469  return tp_vfts[s->session_type].get_listener (s->connection_index);
470 
471  /* Finally, try half-open connections */
472  rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
473  if (rv == 0)
474  return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
475  return 0;
476 }
477 
480  u16 lcl_port, u16 rmt_port, u8 proto)
481 {
483  session_kv4_t kv4;
484  stream_session_t *s;
485  int rv;
486 
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);
490  if (rv == 0)
491  {
493  return tp_vfts[s->session_type].get_connection (s->connection_index,
494  s->thread_index);
495  }
496 
497  /* If nothing is found, check if any listener is available */
498  s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
499  if (s)
500  return tp_vfts[s->session_type].get_listener (s->connection_index);
501 
502  /* Finally, try half-open connections */
503  rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
504  if (rv == 0)
505  return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
506  return 0;
507 }
508 
511  u16 lcl_port, u16 rmt_port, u8 proto,
512  u32 my_thread_index)
513 {
515  stream_session_t *s;
516  session_kv6_t kv6;
517  int rv;
518 
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);
521  if (rv == 0)
522  {
523  s = stream_session_get_tsi (kv6.value, my_thread_index);
524  return tp_vfts[s->session_type].get_connection (s->connection_index,
525  my_thread_index);
526  }
527 
528  /* If nothing is found, check if any listener is available */
529  s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
530  if (s)
531  return tp_vfts[s->session_type].get_listener (s->connection_index);
532 
533  /* Finally, try half-open connections */
534  rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
535  if (rv == 0)
536  return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
537 
538  return 0;
539 }
540 
543  u16 lcl_port, u16 rmt_port, u8 proto)
544 {
546  stream_session_t *s;
547  session_kv6_t kv6;
548  int rv;
549 
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);
552  if (rv == 0)
553  {
555  return tp_vfts[s->session_type].get_connection (s->connection_index,
556  s->thread_index);
557  }
558 
559  /* If nothing is found, check if any listener is available */
560  s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
561  if (s)
562  return tp_vfts[s->session_type].get_listener (s->connection_index);
563 
564  /* Finally, try half-open connections */
565  rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
566  if (rv == 0)
567  return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
568 
569  return 0;
570 }
571 
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))
581 
582 void
584 {
586 
587 #define _(af,table,parm,value) \
588  u32 configured_##af##_##table##_table_##parm = value;
590 #undef _
591 
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;
597 #undef _
598 
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);
611 }
612 
613 /*
614  * fd.io coding-style-patch-verification: ON
615  *
616  * Local Variables:
617  * eval: (c-set-style "gnu")
618  * End:
619  */
static void make_v4_ss_kv_from_tc(session_kv4_t *kv, transport_connection_t *t)
clib_bihash_kv_48_8_t session_kv6_t
struct _transport_connection transport_connection_t
u64 as_u64
Definition: bihash_doc.h:63
u64 as_u64[2]
Definition: ip6_packet.h:51
transport_connection_t * stream_session_lookup_transport6(ip6_address_t *lcl, ip6_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
session_manager_main_t session_manager_main
Definition: session.c:28
struct _transport_proto_vft transport_proto_vft_t
int stream_session_table_del(stream_session_t *s)
int stream_session_table_del_for_tc(transport_connection_t *tc)
static void make_v6_listener_kv(session_kv6_t *kv, ip6_address_t *lcl, u16 lcl_port, u8 proto)
#define foreach_hash_table_parameter
void stream_session_half_open_table_del(transport_connection_t *tc)
static stream_session_t * session_manager_get_listener(u8 type, u32 index)
Definition: session.h:405
#define always_inline
Definition: clib.h:84
transport_proto_vft_t * tp_vfts
Per-type vector of transport protocol virtual function tables.
static void make_v6_ss_kv(session_kv6_t *kv, ip6_address_t *lcl, ip6_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
void stream_session_table_add(session_manager_main_t *smm, stream_session_t *s, u64 value)
unsigned long u64
Definition: types.h:89
transport_connection_t * stream_session_half_open_lookup(ip46_address_t *lcl, ip46_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
struct _stream_session_t stream_session_t
transport_connection_t * stream_session_lookup_transport4(ip4_address_t *lcl, ip4_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
struct _session_lookup session_lookup_t
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:458
static stream_session_t * stream_session_get_tsi(u64 ti_and_si, u32 thread_index)
static void make_v6_ss_kv_from_tc(session_kv6_t *kv, transport_connection_t *t)
transport_connection_t * stream_session_lookup_transport_wt6(ip6_address_t *lcl, ip6_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto, u32 my_thread_index)
stream_session_t * stream_session_lookup_listener6(ip6_address_t *lcl, u16 lcl_port, u8 proto)
struct _session_manager_main session_manager_main_t
Definition: session.h:113
stream_session_t * stream_session_lookup_listener4(ip4_address_t *lcl, u16 lcl_port, u8 proto)
v6_connection_key_t
stream_session_t * stream_session_lookup6(ip6_address_t *lcl, ip6_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
stream_session_t * stream_session_lookup_listener(ip46_address_t *lcl, u16 lcl_port, u8 proto)
void stream_session_half_open_table_add(transport_connection_t *tc, u64 value)
stream_session_t * stream_session_lookup4(ip4_address_t *lcl, ip4_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
Looks up a session based on the 5-tuple passed as argument.
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
void stream_session_table_add_for_tc(transport_connection_t *tc, u64 value)
typedef CLIB_PACKED(struct{union{struct{ip4_address_t src;ip4_address_t dst;u16 src_port;u16 dst_port;u32 proto;};u64 as_u64[2];};})
transport_connection_t * stream_session_lookup_transport_wt4(ip4_address_t *lcl, ip4_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto, u32 my_thread_index)
static void make_v4_listener_kv(session_kv4_t *kv, ip4_address_t *lcl, u16 lcl_port, u8 proto)
session_type_t session_type_from_proto_and_ip(transport_proto_t proto, u8 is_ip4)
Definition: session.c:820
#define HALF_OPEN_LOOKUP_INVALID_VALUE
Definition: session.h:25
unsigned short u16
Definition: types.h:57
void session_lookup_init(void)
unsigned char u8
Definition: types.h:56
static session_lookup_t session_lookup
Generate typed init functions for multiple hash table styles...
u64 stream_session_half_open_lookup_handle(ip46_address_t *lcl, ip46_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
static void make_v4_ss_kv(session_kv4_t *kv, ip4_address_t *lcl, ip4_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
static stream_session_t * stream_session_get_from_handle(u64 handle)
Definition: session.h:262
clib_bihash_kv_16_8_t session_kv4_t