FD.io VPP  v19.04.4-rc0-5-ge88582fac
Vector Packet Processing
session_lookup.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2019 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>
31 
32 /**
33  * Network namespace index (i.e., fib index) to session lookup table. We
34  * should have one per network protocol type but for now we only support IP4/6
35  */
37 
38 /* *INDENT-OFF* */
39 /* 16 octets */
40 typedef CLIB_PACKED (struct {
41  union
42  {
43  struct
44  {
47  u16 src_port;
48  u16 dst_port;
49  /* align by making this 4 octets even though its a 1-bit field
50  * NOTE: avoid key overlap with other transports that use 5 tuples for
51  * session identification.
52  */
53  u32 proto;
54  };
55  u64 as_u64[2];
56  };
57 }) v4_connection_key_t;
58 
59 typedef CLIB_PACKED (struct {
60  union
61  {
62  struct
63  {
64  /* 48 octets */
67  u16 src_port;
68  u16 dst_port;
69  u32 proto;
70  u64 unused;
71  };
72  u64 as_u64[6];
73  };
75 /* *INDENT-ON* */
76 
79 
80 always_inline void
81 make_v4_ss_kv (session_kv4_t * kv, ip4_address_t * lcl, ip4_address_t * rmt,
82  u16 lcl_port, u16 rmt_port, u8 proto)
83 {
84  kv->key[0] = (u64) rmt->as_u32 << 32 | (u64) lcl->as_u32;
85  kv->key[1] = (u64) proto << 32 | (u64) rmt_port << 16 | (u64) lcl_port;
86  kv->value = ~0ULL;
87 }
88 
89 always_inline void
90 make_v4_listener_kv (session_kv4_t * kv, ip4_address_t * lcl, u16 lcl_port,
91  u8 proto)
92 {
93  kv->key[0] = (u64) lcl->as_u32;
94  kv->key[1] = (u64) proto << 32 | (u64) lcl_port;
95  kv->value = ~0ULL;
96 }
97 
98 always_inline void
99 make_v4_proxy_kv (session_kv4_t * kv, ip4_address_t * lcl, u8 proto)
100 {
101  kv->key[0] = (u64) lcl->as_u32;
102  kv->key[1] = (u64) proto << 32;
103  kv->value = ~0ULL;
104 }
105 
106 always_inline void
108 {
109  make_v4_ss_kv (kv, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port,
110  tc->rmt_port, tc->proto);
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 {
117  kv->key[0] = lcl->as_u64[0];
118  kv->key[1] = lcl->as_u64[1];
119  kv->key[2] = rmt->as_u64[0];
120  kv->key[3] = rmt->as_u64[1];
121  kv->key[4] = (u64) proto << 32 | (u64) rmt_port << 16 | (u64) lcl_port;
122  kv->key[5] = 0;
123  kv->value = ~0ULL;
124 }
125 
126 always_inline void
127 make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port,
128  u8 proto)
129 {
130  kv->key[0] = lcl->as_u64[0];
131  kv->key[1] = lcl->as_u64[1];
132  kv->key[2] = 0;
133  kv->key[3] = 0;
134  kv->key[4] = (u64) proto << 32 | (u64) lcl_port;
135  kv->key[5] = 0;
136  kv->value = ~0ULL;
137 }
138 
139 always_inline void
140 make_v6_proxy_kv (session_kv6_t * kv, ip6_address_t * lcl, u8 proto)
141 {
142  kv->key[0] = lcl->as_u64[0];
143  kv->key[1] = lcl->as_u64[1];
144  kv->key[2] = 0;
145  kv->key[3] = 0;
146  kv->key[4] = (u64) proto << 32;
147  kv->key[5] = 0;
148  kv->value = ~0ULL;
149 }
150 
151 always_inline void
153 {
154  make_v6_ss_kv (kv, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port,
155  tc->rmt_port, tc->proto);
156 }
157 
158 static session_table_t *
159 session_table_get_or_alloc (u8 fib_proto, u8 fib_index)
160 {
161  session_table_t *st;
162  u32 table_index;
163  if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
164  {
165  st = session_table_alloc ();
166  table_index = session_table_index (st);
167  vec_validate (fib_index_to_table_index[fib_proto], fib_index);
168  fib_index_to_table_index[fib_proto][fib_index] = table_index;
169  st->active_fib_proto = fib_proto;
170  session_table_init (st, fib_proto);
171  return st;
172  }
173  else
174  {
175  table_index = fib_index_to_table_index[fib_proto][fib_index];
176  return session_table_get (table_index);
177  }
178 }
179 
180 static session_table_t *
182 {
183  u32 fib_proto;
184  fib_proto = transport_connection_fib_proto (tc);
185  return session_table_get_or_alloc (fib_proto, tc->fib_index);
186 }
187 
188 static session_table_t *
190 {
191  u32 fib_proto = transport_connection_fib_proto (tc);
192  if (vec_len (fib_index_to_table_index[fib_proto]) <= tc->fib_index)
193  return 0;
194  return
195  session_table_get (fib_index_to_table_index[fib_proto][tc->fib_index]);
196 }
197 
198 static session_table_t *
200 {
201  if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
202  return 0;
203  return session_table_get (fib_index_to_table_index[fib_proto][fib_index]);
204 }
205 
206 u32
208 {
209  if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
211  return fib_index_to_table_index[fib_proto][fib_index];
212 }
213 
214 /**
215  * Add transport connection to a session table
216  *
217  * Session lookup 5-tuple (src-ip, dst-ip, src-port, dst-port, session-type)
218  * is added to requested session table.
219  *
220  * @param tc transport connection to be added
221  * @param value value to be stored
222  *
223  * @return non-zero if failure
224  */
225 int
227 {
228  session_table_t *st;
229  session_kv4_t kv4;
230  session_kv6_t kv6;
231 
233  if (!st)
234  return -1;
235  if (tc->is_ip4)
236  {
237  make_v4_ss_kv_from_tc (&kv4, tc);
238  kv4.value = value;
239  return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4,
240  1 /* is_add */ );
241  }
242  else
243  {
244  make_v6_ss_kv_from_tc (&kv6, tc);
245  kv6.value = value;
246  return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6,
247  1 /* is_add */ );
248  }
249 }
250 
251 int
253  session_endpoint_t * sep, u64 value)
254 {
255  session_table_t *st;
256  session_kv4_t kv4;
257  session_kv6_t kv6;
258 
259  st = session_table_get (table_index);
260  if (!st)
261  return -1;
262  if (sep->is_ip4)
263  {
264  make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
265  sep->transport_proto);
266  kv4.value = value;
267  return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4, 1);
268  }
269  else
270  {
271  make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
272  sep->transport_proto);
273  kv6.value = value;
274  return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6, 1);
275  }
276 }
277 
278 int
280  session_endpoint_t * sep)
281 {
282  session_table_t *st;
283  session_kv4_t kv4;
284  session_kv6_t kv6;
285 
286  st = session_table_get (table_index);
287  if (!st)
288  return -1;
289  if (sep->is_ip4)
290  {
291  make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
292  sep->transport_proto);
293  return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4, 0);
294  }
295  else
296  {
297  make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
298  sep->transport_proto);
299  return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6, 0);
300  }
301 }
302 
303 /**
304  * Delete transport connection from session table
305  *
306  * @param table_index session table index
307  * @param tc transport connection to be removed
308  *
309  * @return non-zero if failure
310  */
311 int
313 {
314  session_table_t *st;
315  session_kv4_t kv4;
316  session_kv6_t kv6;
317 
319  if (!st)
320  return -1;
321  if (tc->is_ip4)
322  {
323  make_v4_ss_kv_from_tc (&kv4, tc);
324  return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4,
325  0 /* is_add */ );
326  }
327  else
328  {
329  make_v6_ss_kv_from_tc (&kv6, tc);
330  return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6,
331  0 /* is_add */ );
332  }
333 }
334 
335 int
337 {
341  return session_lookup_del_connection (ts);
342 }
343 
344 static u8
346 {
347  if (action_index == SESSION_RULES_TABLE_ACTION_ALLOW
348  || action_index == SESSION_RULES_TABLE_INVALID_INDEX)
349  return 0;
350  return 1;
351 }
352 
353 static u64
355 {
356  switch (action_index)
357  {
359  return SESSION_DROP_HANDLE;
362  return SESSION_INVALID_HANDLE;
363  default:
364  /* application index */
365  return action_index;
366  }
367 }
368 
369 static session_t *
371  u8 transport_proto)
372 {
373  application_t *app;
374  app = application_get_if_valid (app_index);
375  if (!app)
376  return 0;
377 
379  fib_proto, transport_proto);
380 }
381 
382 static session_t *
383 session_lookup_action_to_session (u32 action_index, u8 fib_proto,
384  u8 transport_proto)
385 {
386  u32 app_index;
387  app_index = session_lookup_action_to_handle (action_index);
388  /* Nothing sophisticated for now, action index is app index */
389  return session_lookup_app_listen_session (app_index, fib_proto,
390  transport_proto);
391 }
392 
393 /** UNUSED */
394 session_t *
396  ip4_address_t * lcl, u16 lcl_port,
397  ip4_address_t * rmt, u16 rmt_port)
398 {
399  session_rules_table_t *srt = &st->session_rules[proto];
400  u32 action_index, app_index;
401  action_index = session_rules_table_lookup4 (srt, lcl, rmt, lcl_port,
402  rmt_port);
403  app_index = session_lookup_action_to_handle (action_index);
404  /* Nothing sophisticated for now, action index is app index */
406  proto);
407 }
408 
409 /** UNUSED */
410 session_t *
412  ip6_address_t * lcl, u16 lcl_port,
413  ip6_address_t * rmt, u16 rmt_port)
414 {
415  session_rules_table_t *srt = &st->session_rules[proto];
416  u32 action_index, app_index;
417  action_index = session_rules_table_lookup6 (srt, lcl, rmt, lcl_port,
418  rmt_port);
419  app_index = session_lookup_action_to_handle (action_index);
421  proto);
422 }
423 
424 /**
425  * Lookup listener for session endpoint in table
426  *
427  * @param table_index table where the endpoint should be looked up
428  * @param sep session endpoint to be looked up
429  * @param use_rules flag that indicates if the session rules of the table
430  * should be used
431  * @return invalid handle if nothing is found, the handle of a valid listener
432  * or an action derived handle if a rule is hit
433  */
434 u64
436  u8 use_rules)
437 {
439  session_table_t *st;
440  u32 ai;
441  int rv;
442 
443  st = session_table_get (table_index);
444  if (!st)
445  return SESSION_INVALID_HANDLE;
446  if (sep->is_ip4)
447  {
448  session_kv4_t kv4;
449  ip4_address_t lcl4;
450 
451  make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
452  sep->transport_proto);
453  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
454  if (rv == 0)
455  return kv4.value;
456  if (use_rules)
457  {
458  clib_memset (&lcl4, 0, sizeof (lcl4));
459  srt = &st->session_rules[sep->transport_proto];
460  ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
461  sep->port);
464  }
465  }
466  else
467  {
468  session_kv6_t kv6;
469  ip6_address_t lcl6;
470 
471  make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
472  sep->transport_proto);
473  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
474  if (rv == 0)
475  return kv6.value;
476 
477  if (use_rules)
478  {
479  clib_memset (&lcl6, 0, sizeof (lcl6));
480  srt = &st->session_rules[sep->transport_proto];
481  ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
482  sep->port);
485  }
486  }
487  return SESSION_INVALID_HANDLE;
488 }
489 
490 /**
491  * Look up endpoint in local session table
492  *
493  * The result, for now, is an application index and it may in the future
494  * be extended to a more complicated "action object". The only action we
495  * emulate now is "drop" and for that we return a special app index.
496  *
497  * Lookup logic is to check in order:
498  * - the rules in the table (connect acls)
499  * - session sub-table for a listener
500  * - session sub-table for a local listener (zeroed addr)
501  *
502  * @param table_index table where the lookup should be done
503  * @param sep session endpoint to be looked up
504  * @return session handle that can be interpreted as an adjacency
505  */
506 u64
508 {
510  session_table_t *st;
511  u32 ai;
512  int rv;
513 
514  st = session_table_get (table_index);
515  if (!st)
516  return SESSION_INVALID_INDEX;
517  ASSERT (st->is_local);
518 
519  if (sep->is_ip4)
520  {
521  session_kv4_t kv4;
522  ip4_address_t lcl4;
523 
524  /*
525  * Check if endpoint has special rules associated
526  */
527  clib_memset (&lcl4, 0, sizeof (lcl4));
528  srt = &st->session_rules[sep->transport_proto];
529  ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
530  sep->port);
533 
534  /*
535  * Check if session endpoint is a listener
536  */
537  make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
538  sep->transport_proto);
539  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
540  if (rv == 0)
541  return kv4.value;
542 
543  /*
544  * Zero out the ip. Logic is that connect to local ips, say
545  * 127.0.0.1:port, can match 0.0.0.0:port
546  */
547  if (ip4_is_local_host (&sep->ip.ip4))
548  {
549  kv4.key[0] = 0;
550  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
551  if (rv == 0)
552  return kv4.value;
553  }
554  else
555  {
556  kv4.key[0] = 0;
557  }
558 
559  /*
560  * Zero out the port and check if we have proxy
561  */
562  kv4.key[1] = 0;
563  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
564  if (rv == 0)
565  return kv4.value;
566  }
567  else
568  {
569  session_kv6_t kv6;
570  ip6_address_t lcl6;
571 
572  clib_memset (&lcl6, 0, sizeof (lcl6));
573  srt = &st->session_rules[sep->transport_proto];
574  ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
575  sep->port);
578 
579  make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
580  sep->transport_proto);
581  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
582  if (rv == 0)
583  return kv6.value;
584 
585  /*
586  * Zero out the ip. Same logic as above.
587  */
588 
589  if (ip6_is_local_host (&sep->ip.ip6))
590  {
591  kv6.key[0] = kv6.key[1] = 0;
592  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
593  if (rv == 0)
594  return kv6.value;
595  }
596  else
597  {
598  kv6.key[0] = kv6.key[1] = 0;
599  }
600 
601  /*
602  * Zero out the port. Same logic as above.
603  */
604  kv6.key[4] = kv6.key[5] = 0;
605  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
606  if (rv == 0)
607  return kv6.value;
608  }
609  return SESSION_INVALID_HANDLE;
610 }
611 
612 static inline session_t *
614  u16 lcl_port, u8 proto, u8 use_wildcard)
615 {
616  session_kv4_t kv4;
617  int rv;
618 
619  /*
620  * First, try a fully formed listener
621  */
622  make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
623  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
624  if (rv == 0)
625  return listen_session_get ((u32) kv4.value);
626 
627  /*
628  * Zero out the lcl ip and check if any 0/0 port binds have been done
629  */
630  if (use_wildcard)
631  {
632  kv4.key[0] = 0;
633  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
634  if (rv == 0)
635  return listen_session_get ((u32) kv4.value);
636  }
637  else
638  {
639  kv4.key[0] = 0;
640  }
641 
642  /*
643  * Zero out port and check if we have a proxy set up for our ip
644  */
645  make_v4_proxy_kv (&kv4, lcl, proto);
646  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
647  if (rv == 0)
648  return listen_session_get ((u32) kv4.value);
649 
650  return 0;
651 }
652 
653 session_t *
654 session_lookup_listener4 (u32 fib_index, ip4_address_t * lcl, u16 lcl_port,
655  u8 proto)
656 {
657  session_table_t *st;
659  if (!st)
660  return 0;
661  return session_lookup_listener4_i (st, lcl, lcl_port, proto, 0);
662 }
663 
664 static session_t *
666  u16 lcl_port, u8 proto, u8 ip_wildcard)
667 {
668  session_kv6_t kv6;
669  int rv;
670 
671  make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
672  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
673  if (rv == 0)
674  return listen_session_get ((u32) kv6.value);
675 
676  /* Zero out the lcl ip */
677  if (ip_wildcard)
678  {
679  kv6.key[0] = kv6.key[1] = 0;
680  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
681  if (rv == 0)
682  return listen_session_get ((u32) kv6.value);
683  }
684  else
685  {
686  kv6.key[0] = kv6.key[1] = 0;
687  }
688 
689  make_v6_proxy_kv (&kv6, lcl, proto);
690  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
691  if (rv == 0)
692  return listen_session_get ((u32) kv6.value);
693  return 0;
694 }
695 
696 session_t *
697 session_lookup_listener6 (u32 fib_index, ip6_address_t * lcl, u16 lcl_port,
698  u8 proto)
699 {
700  session_table_t *st;
702  if (!st)
703  return 0;
704  return session_lookup_listener6_i (st, lcl, lcl_port, proto, 1);
705 }
706 
707 /**
708  * Lookup listener, exact or proxy (inaddr_any:0) match
709  */
710 session_t *
712 {
713  session_table_t *st;
714  st = session_table_get (table_index);
715  if (!st)
716  return 0;
717  if (sep->is_ip4)
718  return session_lookup_listener4_i (st, &sep->ip.ip4, sep->port,
719  sep->transport_proto, 0);
720  else
721  return session_lookup_listener6_i (st, &sep->ip.ip6, sep->port,
722  sep->transport_proto, 0);
723  return 0;
724 }
725 
726 /**
727  * Lookup listener wildcard match
728  */
729 session_t *
731 {
732  session_table_t *st;
733  st = session_table_get (table_index);
734  if (!st)
735  return 0;
736  if (sep->is_ip4)
737  return session_lookup_listener4_i (st, &sep->ip.ip4, sep->port,
738  sep->transport_proto,
739  1 /* use_wildcard */ );
740  else
741  return session_lookup_listener6_i (st, &sep->ip.ip6, sep->port,
742  sep->transport_proto,
743  1 /* use_wildcard */ );
744  return 0;
745 }
746 
747 int
749 {
750  session_table_t *st;
751  session_kv4_t kv4;
752  session_kv6_t kv6;
753 
755  if (!st)
756  return 0;
757  if (tc->is_ip4)
758  {
759  make_v4_ss_kv_from_tc (&kv4, tc);
760  kv4.value = value;
761  return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
762  1 /* is_add */ );
763  }
764  else
765  {
766  make_v6_ss_kv_from_tc (&kv6, tc);
767  kv6.value = value;
768  return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
769  1 /* is_add */ );
770  }
771 }
772 
773 int
775 {
776  session_table_t *st;
777  session_kv4_t kv4;
778  session_kv6_t kv6;
779 
781  if (!st)
782  return -1;
783  if (tc->is_ip4)
784  {
785  make_v4_ss_kv_from_tc (&kv4, tc);
786  return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
787  0 /* is_add */ );
788  }
789  else
790  {
791  make_v6_ss_kv_from_tc (&kv6, tc);
792  return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
793  0 /* is_add */ );
794  }
795 }
796 
797 u64
799 {
800  session_table_t *st;
801  session_kv4_t kv4;
802  session_kv6_t kv6;
803  int rv;
804 
806  tc->fib_index);
807  if (!st)
809  if (tc->is_ip4)
810  {
811  make_v4_ss_kv (&kv4, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port,
812  tc->rmt_port, tc->proto);
813  rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
814  if (rv == 0)
815  return kv4.value;
816  }
817  else
818  {
819  make_v6_ss_kv (&kv6, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port,
820  tc->rmt_port, tc->proto);
821  rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
822  if (rv == 0)
823  return kv6.value;
824  }
826 }
827 
830 {
831  if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
832  {
833  u32 sst = session_type_from_proto_and_ip (proto, is_ip4);
834  return transport_get_half_open (sst, handle & 0xFFFFFFFF);
835  }
836  return 0;
837 }
838 
839 /**
840  * Lookup connection with ip4 and transport layer information
841  *
842  * This is used on the fast path so it needs to be fast. Thereby,
843  * duplication of code and 'hacks' allowed.
844  *
845  * The lookup is incremental and returns whenever something is matched. The
846  * steps are:
847  * - Try to find an established session
848  * - Try to find a half-open connection
849  * - Try session rules table
850  * - Try to find a fully-formed or local source wildcarded (listener bound to
851  * all interfaces) listener session
852  * - return 0
853  *
854  * @param fib_index index of fib wherein the connection was received
855  * @param lcl local ip4 address
856  * @param rmt remote ip4 address
857  * @param lcl_port local port
858  * @param rmt_port remote port
859  * @param proto transport protocol (e.g., tcp, udp)
860  * @param thread_index thread index for request
861  * @param is_filtered return flag that indicates if connection was filtered.
862  *
863  * @return pointer to transport connection, if one is found, 0 otherwise
864  */
867  ip4_address_t * rmt, u16 lcl_port,
868  u16 rmt_port, u8 proto, u32 thread_index,
869  u8 * result)
870 {
871  session_table_t *st;
872  session_kv4_t kv4;
873  session_t *s;
874  u32 action_index;
875  int rv;
876 
878  if (PREDICT_FALSE (!st))
879  return 0;
880 
881  /*
882  * Lookup session amongst established ones
883  */
884  make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
885  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
886  if (rv == 0)
887  {
888  if (PREDICT_FALSE ((u32) (kv4.value >> 32) != thread_index))
889  {
891  return 0;
892  }
893  s = session_get (kv4.value & 0xFFFFFFFFULL, thread_index);
894  return transport_get_connection (proto, s->connection_index,
895  thread_index);
896  }
897 
898  /*
899  * Try half-open connections
900  */
901  rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
902  if (rv == 0)
903  return transport_get_half_open (proto, kv4.value & 0xFFFFFFFF);
904 
905  /*
906  * Check the session rules table
907  */
908  action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
909  rmt, lcl_port, rmt_port);
910  if (session_lookup_action_index_is_valid (action_index))
911  {
912  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
913  {
915  return 0;
916  }
917  if ((s = session_lookup_action_to_session (action_index,
918  FIB_PROTOCOL_IP4, proto)))
919  return transport_get_listener (proto, s->connection_index);
920  return 0;
921  }
922 
923  /*
924  * If nothing is found, check if any listener is available
925  */
926  s = session_lookup_listener4_i (st, lcl, lcl_port, proto, 1);
927  if (s)
928  return transport_get_listener (proto, s->connection_index);
929 
930  return 0;
931 }
932 
933 /**
934  * Lookup connection with ip4 and transport layer information
935  *
936  * Not optimized. Lookup logic is identical to that of
937  * @ref session_lookup_connection_wt4
938  *
939  * @param fib_index index of the fib wherein the connection was received
940  * @param lcl local ip4 address
941  * @param rmt remote ip4 address
942  * @param lcl_port local port
943  * @param rmt_port remote port
944  * @param proto transport protocol (e.g., tcp, udp)
945  *
946  * @return pointer to transport connection, if one is found, 0 otherwise
947  */
950  ip4_address_t * rmt, u16 lcl_port, u16 rmt_port,
951  u8 proto)
952 {
953  session_table_t *st;
954  session_kv4_t kv4;
955  session_t *s;
956  u32 action_index;
957  int rv;
958 
960  if (PREDICT_FALSE (!st))
961  return 0;
962 
963  /*
964  * Lookup session amongst established ones
965  */
966  make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
967  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
968  if (rv == 0)
969  {
970  s = session_get_from_handle (kv4.value);
971  return transport_get_connection (proto, s->connection_index,
972  s->thread_index);
973  }
974 
975  /*
976  * Try half-open connections
977  */
978  rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
979  if (rv == 0)
980  return transport_get_half_open (proto, kv4.value & 0xFFFFFFFF);
981 
982  /*
983  * Check the session rules table
984  */
985  action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
986  rmt, lcl_port, rmt_port);
987  if (session_lookup_action_index_is_valid (action_index))
988  {
989  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
990  return 0;
991  if ((s = session_lookup_action_to_session (action_index,
992  FIB_PROTOCOL_IP4, proto)))
993  return transport_get_listener (proto, s->connection_index);
994  return 0;
995  }
996 
997  /*
998  * If nothing is found, check if any listener is available
999  */
1000  s = session_lookup_listener4_i (st, lcl, lcl_port, proto, 1);
1001  if (s)
1002  return transport_get_listener (proto, s->connection_index);
1003 
1004  return 0;
1005 }
1006 
1007 /**
1008  * Lookup session with ip4 and transport layer information
1009  *
1010  * Important note: this may look into another thread's pool table and
1011  * register as 'peeker'. Caller should call @ref session_pool_remove_peeker as
1012  * if needed as soon as possible.
1013  *
1014  * Lookup logic is similar to that of @ref session_lookup_connection_wt4 but
1015  * this returns a session as opposed to a transport connection and it does not
1016  * try to lookup half-open sessions.
1017  *
1018  * Typically used by dgram connections
1019  */
1020 session_t *
1022  u16 lcl_port, u16 rmt_port, u8 proto)
1023 {
1024  session_table_t *st;
1025  session_kv4_t kv4;
1026  session_t *s;
1027  u32 action_index;
1028  int rv;
1029 
1031  if (PREDICT_FALSE (!st))
1032  return 0;
1033 
1034  /*
1035  * Lookup session amongst established ones
1036  */
1037  make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
1038  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
1039  if (rv == 0)
1040  return session_get_from_handle_safe (kv4.value);
1041 
1042  /*
1043  * Check the session rules table
1044  */
1045  action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
1046  rmt, lcl_port, rmt_port);
1047  if (session_lookup_action_index_is_valid (action_index))
1048  {
1049  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1050  return 0;
1051  return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
1052  proto);
1053  }
1054 
1055  /*
1056  * If nothing is found, check if any listener is available
1057  */
1058  if ((s = session_lookup_listener4_i (st, lcl, lcl_port, proto, 1)))
1059  return s;
1060 
1061  return 0;
1062 }
1063 
1064 /**
1065  * Lookup connection with ip6 and transport layer information
1066  *
1067  * This is used on the fast path so it needs to be fast. Thereby,
1068  * duplication of code and 'hacks' allowed.
1069  *
1070  * The lookup is incremental and returns whenever something is matched. The
1071  * steps are:
1072  * - Try to find an established session
1073  * - Try to find a half-open connection
1074  * - Try session rules table
1075  * - Try to find a fully-formed or local source wildcarded (listener bound to
1076  * all interfaces) listener session
1077  * - return 0
1078  *
1079  * @param fib_index index of the fib wherein the connection was received
1080  * @param lcl local ip6 address
1081  * @param rmt remote ip6 address
1082  * @param lcl_port local port
1083  * @param rmt_port remote port
1084  * @param proto transport protocol (e.g., tcp, udp)
1085  * @param thread_index thread index for request
1086  *
1087  * @return pointer to transport connection, if one is found, 0 otherwise
1088  */
1091  ip6_address_t * rmt, u16 lcl_port,
1092  u16 rmt_port, u8 proto, u32 thread_index,
1093  u8 * result)
1094 {
1095  session_table_t *st;
1096  session_t *s;
1097  session_kv6_t kv6;
1098  u32 action_index;
1099  int rv;
1100 
1102  if (PREDICT_FALSE (!st))
1103  return 0;
1104 
1105  make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1106  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1107  if (rv == 0)
1108  {
1109  ASSERT ((u32) (kv6.value >> 32) == thread_index);
1110  if (PREDICT_FALSE ((u32) (kv6.value >> 32) != thread_index))
1111  {
1113  return 0;
1114  }
1115  s = session_get (kv6.value & 0xFFFFFFFFULL, thread_index);
1116  return transport_get_connection (proto, s->connection_index,
1117  thread_index);
1118  }
1119 
1120  /* Try half-open connections */
1121  rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
1122  if (rv == 0)
1123  return transport_get_half_open (proto, kv6.value & 0xFFFFFFFF);
1124 
1125  /* Check the session rules table */
1126  action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
1127  rmt, lcl_port, rmt_port);
1128  if (session_lookup_action_index_is_valid (action_index))
1129  {
1130  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1131  {
1133  return 0;
1134  }
1135  if ((s = session_lookup_action_to_session (action_index,
1136  FIB_PROTOCOL_IP6, proto)))
1137  return transport_get_listener (proto, s->connection_index);
1138  return 0;
1139  }
1140 
1141  /* If nothing is found, check if any listener is available */
1142  s = session_lookup_listener6_i (st, lcl, lcl_port, proto, 1);
1143  if (s)
1144  return transport_get_listener (proto, s->connection_index);
1145 
1146  return 0;
1147 }
1148 
1149 /**
1150  * Lookup connection with ip6 and transport layer information
1151  *
1152  * Not optimized. This is used on the fast path so it needs to be fast.
1153  * Thereby, duplication of code and 'hacks' allowed. Lookup logic is identical
1154  * to that of @ref session_lookup_connection_wt4
1155  *
1156  * @param fib_index index of the fib wherein the connection was received
1157  * @param lcl local ip6 address
1158  * @param rmt remote ip6 address
1159  * @param lcl_port local port
1160  * @param rmt_port remote port
1161  * @param proto transport protocol (e.g., tcp, udp)
1162  *
1163  * @return pointer to transport connection, if one is found, 0 otherwise
1164  */
1167  ip6_address_t * rmt, u16 lcl_port, u16 rmt_port,
1168  u8 proto)
1169 {
1170  session_table_t *st;
1171  session_t *s;
1172  session_kv6_t kv6;
1173  u32 action_index;
1174  int rv;
1175 
1177  if (PREDICT_FALSE (!st))
1178  return 0;
1179 
1180  make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1181  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1182  if (rv == 0)
1183  {
1184  s = session_get_from_handle (kv6.value);
1185  return transport_get_connection (proto, s->connection_index,
1186  s->thread_index);
1187  }
1188 
1189  /* Try half-open connections */
1190  rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
1191  if (rv == 0)
1192  return transport_get_half_open (proto, kv6.value & 0xFFFFFFFF);
1193 
1194  /* Check the session rules table */
1195  action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
1196  rmt, lcl_port, rmt_port);
1197  if (session_lookup_action_index_is_valid (action_index))
1198  {
1199  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1200  return 0;
1201  if ((s = session_lookup_action_to_session (action_index,
1202  FIB_PROTOCOL_IP6, proto)))
1203  return transport_get_listener (proto, s->connection_index);
1204  return 0;
1205  }
1206 
1207  /* If nothing is found, check if any listener is available */
1208  s = session_lookup_listener6_i (st, lcl, lcl_port, proto, 1);
1209  if (s)
1210  return transport_get_listener (proto, s->connection_index);
1211 
1212  return 0;
1213 }
1214 
1215 /**
1216  * Lookup session with ip6 and transport layer information
1217  *
1218  * Important note: this may look into another thread's pool table and
1219  * register as 'peeker'. Caller should call @ref session_pool_remove_peeker as
1220  * if needed as soon as possible.
1221  *
1222  * Lookup logic is similar to that of @ref session_lookup_connection_wt6 but
1223  * this returns a session as opposed to a transport connection and it does not
1224  * try to lookup half-open sessions.
1225  *
1226  * Typically used by dgram connections
1227  */
1228 session_t *
1230  u16 lcl_port, u16 rmt_port, u8 proto)
1231 {
1232  session_table_t *st;
1233  session_kv6_t kv6;
1234  session_t *s;
1235  u32 action_index;
1236  int rv;
1237 
1239  if (PREDICT_FALSE (!st))
1240  return 0;
1241 
1242  make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1243  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1244  if (rv == 0)
1245  return session_get_from_handle_safe (kv6.value);
1246 
1247  /* Check the session rules table */
1248  action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
1249  rmt, lcl_port, rmt_port);
1250  if (session_lookup_action_index_is_valid (action_index))
1251  {
1252  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1253  return 0;
1254  return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP6,
1255  proto);
1256  }
1257 
1258  /* If nothing is found, check if any listener is available */
1259  if ((s = session_lookup_listener6_i (st, lcl, lcl_port, proto, 1)))
1260  return s;
1261  return 0;
1262 }
1263 
1264 int
1266 {
1267  app_namespace_t *app_ns = app_namespace_get (args->appns_index);
1268  session_rules_table_t *srt;
1269  session_table_t *st;
1270  u32 fib_index;
1271  u8 fib_proto;
1272  int rv = 0;
1273 
1274  if (!app_ns)
1275  return VNET_API_ERROR_APP_INVALID_NS;
1276 
1277  if (args->scope > 3)
1278  return VNET_API_ERROR_INVALID_VALUE;
1279 
1280  if (args->transport_proto != TRANSPORT_PROTO_TCP
1281  && args->transport_proto != TRANSPORT_PROTO_UDP)
1282  return VNET_API_ERROR_INVALID_VALUE;
1283 
1284  if ((args->scope & SESSION_RULE_SCOPE_GLOBAL) || args->scope == 0)
1285  {
1286  fib_proto = args->table_args.rmt.fp_proto;
1287  fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1288  st = session_table_get_for_fib_index (fib_proto, fib_index);
1289  srt = &st->session_rules[args->transport_proto];
1290  if ((rv = session_rules_table_add_del (srt, &args->table_args)))
1291  return rv;
1292  }
1293  if (args->scope & SESSION_RULE_SCOPE_LOCAL)
1294  {
1295  clib_memset (&args->table_args.lcl, 0, sizeof (args->table_args.lcl));
1296  args->table_args.lcl.fp_proto = args->table_args.rmt.fp_proto;
1297  args->table_args.lcl_port = 0;
1298  st = app_namespace_get_local_table (app_ns);
1299  srt = &st->session_rules[args->transport_proto];
1300  rv = session_rules_table_add_del (srt, &args->table_args);
1301  }
1302  return rv;
1303 }
1304 
1305 /**
1306  * Mark (global) tables as pertaining to app ns
1307  */
1308 void
1310 {
1311  session_table_t *st;
1312  u32 fib_index;
1313  u8 fp;
1314 
1315  for (fp = 0; fp < ARRAY_LEN (fib_index_to_table_index); fp++)
1316  {
1317  fib_index = app_namespace_get_fib_index (app_ns, fp);
1318  st = session_table_get_for_fib_index (fp, fib_index);
1319  if (st)
1320  st->appns_index = app_namespace_index (app_ns);
1321  }
1322 }
1323 
1324 u8 *
1325 format_ip4_session_lookup_kvp (u8 * s, va_list * args)
1326 {
1327  clib_bihash_kv_16_8_t *kvp = va_arg (*args, clib_bihash_kv_16_8_t *);
1328  u32 is_local = va_arg (*args, u32);
1329  v4_connection_key_t *key = (v4_connection_key_t *) kvp->key;
1330  session_t *session;
1331  app_worker_t *app_wrk;
1332  const u8 *app_name;
1333  u8 *str = 0;
1334 
1335  if (!is_local)
1336  {
1337  session = session_get_from_handle (kvp->value);
1338  app_wrk = app_worker_get (session->app_wrk_index);
1339  app_name = application_name_from_index (app_wrk->app_index);
1340  str = format (0, "[%U] %U:%d->%U:%d", format_transport_proto_short,
1341  key->proto, format_ip4_address, &key->src,
1342  clib_net_to_host_u16 (key->src_port), format_ip4_address,
1343  &key->dst, clib_net_to_host_u16 (key->dst_port));
1344  s = format (s, "%-40v%-30v", str, app_name);
1345  }
1346  else
1347  {
1348  session = session_get_from_handle (kvp->value);
1349  app_wrk = app_worker_get (session->app_wrk_index);
1350  app_name = application_name_from_index (app_wrk->app_index);
1351  str = format (0, "[%U] %U:%d", format_transport_proto_short, key->proto,
1352  format_ip4_address, &key->src,
1353  clib_net_to_host_u16 (key->src_port));
1354  s = format (s, "%-30v%-30v", str, app_name);
1355  }
1356  return s;
1357 }
1358 
1359 typedef struct _ip4_session_table_show_ctx_t
1360 {
1361  vlib_main_t *vm;
1362  u8 is_local;
1364 
1365 static int
1367 {
1369  vlib_cli_output (ctx->vm, "%U", format_ip4_session_lookup_kvp, kvp,
1370  ctx->is_local);
1371  return 1;
1372 }
1373 
1374 void
1376  u8 type, u8 is_local)
1377 {
1379  .vm = vm,
1380  .is_local = is_local,
1381  };
1382  if (!is_local)
1383  vlib_cli_output (vm, "%-40s%-30s", "Session", "Application");
1384  else
1385  vlib_cli_output (vm, "%-30s%-30s", "Listener", "Application");
1386  switch (type)
1387  {
1388  /* main table v4 */
1389  case 0:
1390  ip4_session_table_walk (&table->v4_session_hash, ip4_session_table_show,
1391  &ctx);
1392  break;
1393  default:
1394  clib_warning ("not supported");
1395  }
1396 }
1397 
1398 static clib_error_t *
1400  vlib_cli_command_t * cmd)
1401 {
1402  u32 proto = ~0, lcl_port, rmt_port, action = 0, lcl_plen = 0, rmt_plen = 0;
1403  u32 appns_index, scope = 0;
1404  ip46_address_t lcl_ip, rmt_ip;
1405  u8 is_ip4 = 1, conn_set = 0;
1406  u8 fib_proto, is_add = 1, *ns_id = 0;
1407  u8 *tag = 0;
1408  app_namespace_t *app_ns;
1409  int rv;
1410 
1411  clib_memset (&lcl_ip, 0, sizeof (lcl_ip));
1412  clib_memset (&rmt_ip, 0, sizeof (rmt_ip));
1413  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1414  {
1415  if (unformat (input, "del"))
1416  is_add = 0;
1417  else if (unformat (input, "add"))
1418  ;
1419  else if (unformat (input, "appns %_%v%_", &ns_id))
1420  ;
1421  else if (unformat (input, "scope global"))
1422  scope = SESSION_RULE_SCOPE_GLOBAL;
1423  else if (unformat (input, "scope local"))
1424  scope = SESSION_RULE_SCOPE_LOCAL;
1425  else if (unformat (input, "scope all"))
1427  else if (unformat (input, "proto %U", unformat_transport_proto, &proto))
1428  ;
1429  else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address,
1430  &lcl_ip.ip4, &lcl_plen, &lcl_port,
1431  unformat_ip4_address, &rmt_ip.ip4, &rmt_plen,
1432  &rmt_port))
1433  {
1434  is_ip4 = 1;
1435  conn_set = 1;
1436  }
1437  else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address,
1438  &lcl_ip.ip6, &lcl_plen, &lcl_port,
1439  unformat_ip6_address, &rmt_ip.ip6, &rmt_plen,
1440  &rmt_port))
1441  {
1442  is_ip4 = 0;
1443  conn_set = 1;
1444  }
1445  else if (unformat (input, "action %d", &action))
1446  ;
1447  else if (unformat (input, "tag %_%v%_", &tag))
1448  ;
1449  else
1450  return clib_error_return (0, "unknown input `%U'",
1451  format_unformat_error, input);
1452  }
1453 
1454  if (proto == ~0)
1455  {
1456  vlib_cli_output (vm, "proto must be set");
1457  return 0;
1458  }
1459  if (is_add && !conn_set && action == ~0)
1460  {
1461  vlib_cli_output (vm, "connection and action must be set for add");
1462  return 0;
1463  }
1464  if (!is_add && !tag && !conn_set)
1465  {
1466  vlib_cli_output (vm, "connection or tag must be set for delete");
1467  return 0;
1468  }
1469  if (vec_len (tag) > SESSION_RULE_TAG_MAX_LEN)
1470  {
1471  vlib_cli_output (vm, "tag too long (max u64)");
1472  return 0;
1473  }
1474 
1475  if (ns_id)
1476  {
1477  app_ns = app_namespace_get_from_id (ns_id);
1478  if (!app_ns)
1479  {
1480  vlib_cli_output (vm, "namespace %v does not exist", ns_id);
1481  return 0;
1482  }
1483  }
1484  else
1485  {
1486  app_ns = app_namespace_get_default ();
1487  }
1488  appns_index = app_namespace_index (app_ns);
1489 
1490  fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
1492  .transport_proto = proto,
1493  .table_args.lcl.fp_addr = lcl_ip,
1494  .table_args.lcl.fp_len = lcl_plen,
1495  .table_args.lcl.fp_proto = fib_proto,
1496  .table_args.rmt.fp_addr = rmt_ip,
1497  .table_args.rmt.fp_len = rmt_plen,
1498  .table_args.rmt.fp_proto = fib_proto,
1499  .table_args.lcl_port = lcl_port,
1500  .table_args.rmt_port = rmt_port,
1501  .table_args.action_index = action,
1502  .table_args.is_add = is_add,
1503  .table_args.tag = tag,
1504  .appns_index = appns_index,
1505  .scope = scope,
1506  };
1507  if ((rv = vnet_session_rule_add_del (&args)))
1508  return clib_error_return (0, "rule add del returned %u", rv);
1509 
1510  vec_free (tag);
1511  return 0;
1512 }
1513 
1514 /* *INDENT-OFF* */
1515 VLIB_CLI_COMMAND (session_rule_command, static) =
1516 {
1517  .path = "session rule",
1518  .short_help = "session rule [add|del] appns <ns_id> proto <proto> "
1519  "<lcl-ip/plen> <lcl-port> <rmt-ip/plen> <rmt-port> action <action>",
1520  .function = session_rule_command_fn,
1521 };
1522 /* *INDENT-ON* */
1523 
1524 void
1526  u8 transport_proto)
1527 {
1529  session_rules_table_t *srt;
1530  session_table_t *st;
1531  st = session_table_get_for_fib_index (fib_index, fib_proto);
1532  srt = &st->session_rules[transport_proto];
1533  session_rules_table_cli_dump (vm, srt, fib_proto);
1534 }
1535 
1536 void
1538  u8 transport_proto)
1539 {
1541  session_rules_table_t *srt;
1542  session_table_t *st;
1543  st = session_table_get (table_index);
1544  srt = &st->session_rules[transport_proto];
1545  session_rules_table_cli_dump (vm, srt, fib_proto);
1546 }
1547 
1548 static clib_error_t *
1550  vlib_cli_command_t * cmd)
1551 {
1552  u32 transport_proto = ~0, lcl_port, rmt_port, lcl_plen, rmt_plen;
1553  u32 fib_index, scope = 0;
1554  ip46_address_t lcl_ip, rmt_ip;
1555  u8 is_ip4 = 1, show_one = 0;
1556  app_namespace_t *app_ns;
1557  session_rules_table_t *srt;
1558  session_table_t *st;
1559  u8 *ns_id = 0, fib_proto;
1560 
1561  clib_memset (&lcl_ip, 0, sizeof (lcl_ip));
1562  clib_memset (&rmt_ip, 0, sizeof (rmt_ip));
1563  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1564  {
1565  if (unformat (input, "%U", unformat_transport_proto, &transport_proto))
1566  ;
1567  else if (unformat (input, "appns %_%v%_", &ns_id))
1568  ;
1569  else if (unformat (input, "scope global"))
1570  scope = 1;
1571  else if (unformat (input, "scope local"))
1572  scope = 2;
1573  else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address,
1574  &lcl_ip.ip4, &lcl_plen, &lcl_port,
1575  unformat_ip4_address, &rmt_ip.ip4, &rmt_plen,
1576  &rmt_port))
1577  {
1578  is_ip4 = 1;
1579  show_one = 1;
1580  }
1581  else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address,
1582  &lcl_ip.ip6, &lcl_plen, &lcl_port,
1583  unformat_ip6_address, &rmt_ip.ip6, &rmt_plen,
1584  &rmt_port))
1585  {
1586  is_ip4 = 0;
1587  show_one = 1;
1588  }
1589  else
1590  return clib_error_return (0, "unknown input `%U'",
1591  format_unformat_error, input);
1592  }
1593 
1594  if (transport_proto == ~0)
1595  {
1596  vlib_cli_output (vm, "transport proto must be set");
1597  return 0;
1598  }
1599 
1600  if (ns_id)
1601  {
1602  app_ns = app_namespace_get_from_id (ns_id);
1603  if (!app_ns)
1604  {
1605  vlib_cli_output (vm, "appns %v doesn't exist", ns_id);
1606  return 0;
1607  }
1608  }
1609  else
1610  {
1611  app_ns = app_namespace_get_default ();
1612  }
1613 
1614  if (scope == 1 || scope == 0)
1615  {
1616  fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
1617  fib_index = is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
1618  st = session_table_get_for_fib_index (fib_proto, fib_index);
1619  }
1620  else
1621  {
1622  st = app_namespace_get_local_table (app_ns);
1623  }
1624 
1625  if (show_one)
1626  {
1627  srt = &st->session_rules[transport_proto];
1628  session_rules_table_show_rule (vm, srt, &lcl_ip, lcl_port, &rmt_ip,
1629  rmt_port, is_ip4);
1630  return 0;
1631  }
1632 
1633  vlib_cli_output (vm, "%U rules table", format_transport_proto,
1634  transport_proto);
1635  srt = &st->session_rules[transport_proto];
1638 
1639  vec_free (ns_id);
1640  return 0;
1641 }
1642 
1643 /* *INDENT-OFF* */
1644 VLIB_CLI_COMMAND (show_session_rules_command, static) =
1645 {
1646  .path = "show session rules",
1647  .short_help = "show session rules [<proto> appns <id> <lcl-ip/plen> "
1648  "<lcl-port> <rmt-ip/plen> <rmt-port> scope <scope>]",
1649  .function = show_session_rules_command_fn,
1650 };
1651 /* *INDENT-ON* */
1652 
1653 void
1655 {
1656  /*
1657  * Allocate default table and map it to fib_index 0
1658  */
1660  vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP4], 0);
1661  fib_index_to_table_index[FIB_PROTOCOL_IP4][0] = session_table_index (st);
1662  st->active_fib_proto = FIB_PROTOCOL_IP4;
1663  session_table_init (st, FIB_PROTOCOL_IP4);
1664  st = session_table_alloc ();
1665  vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP6], 0);
1666  fib_index_to_table_index[FIB_PROTOCOL_IP6][0] = session_table_index (st);
1667  st->active_fib_proto = FIB_PROTOCOL_IP6;
1668  session_table_init (st, FIB_PROTOCOL_IP6);
1669 }
1670 
1671 /*
1672  * fd.io coding-style-patch-verification: ON
1673  *
1674  * Local Variables:
1675  * eval: (c-set-style "gnu")
1676  * End:
1677  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
#define SESSION_DROP_HANDLE
Definition: session_table.h:60
u32 connection_index
Index of the transport connection associated to the session.
static session_t * session_lookup_action_to_session(u32 action_index, u8 fib_proto, u8 transport_proto)
session_t * session_lookup_listener(u32 table_index, session_endpoint_t *sep)
Lookup listener, exact or proxy (inaddr_any:0) match.
int session_lookup_del_connection(transport_connection_t *tc)
Delete transport connection from session table.
static session_table_t * session_table_get_or_alloc_for_connection(transport_connection_t *tc)
session_table_t * session_table_alloc(void)
Definition: session_table.c:31
void session_lookup_show_table_entries(vlib_main_t *vm, session_table_t *table, u8 type, u8 is_local)
#define SESSION_RULES_TABLE_ACTION_DROP
u8 * format_transport_proto_short(u8 *s, va_list *args)
Definition: transport.c:80
clib_bihash_kv_48_8_t session_kv6_t
void session_rules_table_cli_dump(vlib_main_t *vm, session_rules_table_t *srt, u8 fib_proto)
#define SESSION_TABLE_INVALID_INDEX
Definition: session_table.h:56
static u8 transport_connection_fib_proto(transport_connection_t *tc)
u64 session_lookup_endpoint_listener(u32 table_index, session_endpoint_t *sep, u8 use_rules)
Lookup listener for session endpoint in table.
static clib_error_t * session_rule_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static session_table_t * session_table_get_for_fib_index(u32 fib_proto, u32 fib_index)
struct _session_rules_table_t session_rules_table_t
transport_connection_t * session_lookup_connection_wt6(u32 fib_index, ip6_address_t *lcl, ip6_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto, u32 thread_index, u8 *result)
Lookup connection with ip6 and transport layer information.
static u8 session_lookup_action_index_is_valid(u32 action_index)
u64 as_u64
Definition: bihash_doc.h:63
u32 app_namespace_index(app_namespace_t *app_ns)
session_t * session_lookup_rules_table_session6(session_table_t *st, u8 proto, ip6_address_t *lcl, u16 lcl_port, ip6_address_t *rmt, u16 rmt_port)
UNUSED.
u64 as_u64[2]
Definition: ip6_packet.h:51
unsigned long u64
Definition: types.h:89
static session_t * session_lookup_app_listen_session(u32 app_index, u8 fib_proto, u8 transport_proto)
session_t * session_lookup_safe4(u32 fib_index, ip4_address_t *lcl, ip4_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
Lookup session with ip4 and transport layer information.
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
void session_lookup_set_tables_appns(app_namespace_t *app_ns)
Mark (global) tables as pertaining to app ns.
static clib_error_t * show_session_rules_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u32 session_lookup_get_index_for_fib(u32 fib_proto, u32 fib_index)
static transport_proto_t session_get_transport_proto(session_t *s)
session_t * session_lookup_listener_wildcard(u32 table_index, session_endpoint_t *sep)
Lookup listener wildcard match.
static session_t * session_get(u32 si, u32 thread_index)
Definition: session.h:207
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
vl_api_ip4_address_t dst
Definition: ipsec_gre.api:39
u32 session_rules_table_lookup4(session_rules_table_t *srt, ip4_address_t *lcl_ip, ip4_address_t *rmt_ip, u16 lcl_port, u16 rmt_port)
static void make_v6_listener_kv(session_kv6_t *kv, ip6_address_t *lcl, u16 lcl_port, u8 proto)
session_t * session_lookup_safe6(u32 fib_index, ip6_address_t *lcl, ip6_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
Lookup session with ip6 and transport layer information.
static session_t * session_lookup_listener4_i(session_table_t *st, ip4_address_t *lcl, u16 lcl_port, u8 proto, u8 use_wildcard)
u64 session_lookup_half_open_handle(transport_connection_t *tc)
static void make_v6_ss_kv_from_tc(session_kv6_t *kv, transport_connection_t *tc)
unsigned char u8
Definition: types.h:56
application_t * application_get_if_valid(u32 app_index)
Definition: application.c:455
transport_connection_t * session_lookup_connection6(u32 fib_index, ip6_address_t *lcl, ip6_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
Lookup connection with ip6 and transport layer information.
u16 src_port
Definition: udp.api:41
#define SESSION_INVALID_INDEX
Definition: session_table.h:58
format_function_t format_ip4_address
Definition: format.h:75
unformat_function_t unformat_ip4_address
Definition: format.h:70
#define always_inline
Definition: clib.h:98
transport_connection_t * session_lookup_connection_wt4(u32 fib_index, ip4_address_t *lcl, ip4_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto, u32 thread_index, u8 *result)
Lookup connection with ip4 and transport layer information.
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)
#define clib_error_return(e, args...)
Definition: error.h:99
static int ip4_session_table_show(clib_bihash_kv_16_8_t *kvp, void *arg)
unsigned int u32
Definition: types.h:88
static void make_v6_proxy_kv(session_kv6_t *kv, ip6_address_t *lcl, u8 proto)
#define HALF_OPEN_LOOKUP_INVALID_VALUE
int session_lookup_del_half_open(transport_connection_t *tc)
transport_connection_t * session_lookup_connection4(u32 fib_index, ip4_address_t *lcl, ip4_address_t *rmt, u16 lcl_port, u16 rmt_port, u8 proto)
Lookup connection with ip4 and transport layer information.
void session_table_init(session_table_t *slt, u8 fib_proto)
Initialize session table hash tables.
Definition: session_table.c:70
u32 app_namespace_get_fib_index(app_namespace_t *app_ns, u8 fib_proto)
static session_type_t session_type_from_proto_and_ip(transport_proto_t proto, u8 is_ip4)
static session_t * session_get_from_handle(session_handle_t handle)
Definition: session.h:227
struct _session_rule_add_del_args session_rule_add_del_args_t
long ctx[MAX_CONNS]
Definition: main.c:144
void session_lookup_dump_rules_table(u32 fib_index, u8 fib_proto, u8 transport_proto)
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
const u8 * application_name_from_index(u32 app_index)
Returns app name for app-index.
Definition: application.c:381
static app_namespace_t * app_namespace_get_default(void)
int vnet_session_rule_add_del(session_rule_add_del_args_t *args)
#define PREDICT_FALSE(x)
Definition: clib.h:111
static session_t * session_get_from_handle_safe(u64 handle)
Get session from handle and &#39;lock&#39; pool resize if not in same thread.
Definition: session.h:279
int session_lookup_del_session(session_t *s)
app_namespace_t * app_namespace_get(u32 index)
vl_api_ip4_address_t src
Definition: ipsec_gre.api:38
session_t * session_lookup_listener6(u32 fib_index, ip6_address_t *lcl, u16 lcl_port, u8 proto)
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];};})
u32 session_rules_table_lookup6(session_rules_table_t *srt, ip6_address_t *lcl_ip, ip6_address_t *rmt_ip, u16 lcl_port, u16 rmt_port)
unformat_function_t unformat_ip6_address
Definition: format.h:91
u64 session_lookup_local_endpoint(u32 table_index, session_endpoint_t *sep)
Look up endpoint in local session table.
v6_connection_key_t
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
static session_table_t * session_table_get_for_connection(transport_connection_t *tc)
vlib_main_t * vm
Definition: buffer.c:312
static u32 * fib_index_to_table_index[2]
Generate typed init functions for multiple hash table styles...
static transport_connection_t * transport_get_connection(transport_proto_t tp, u32 conn_index, u8 thread_index)
Definition: transport.h:90
session_t * app_worker_first_listener(app_worker_t *app, u8 fib_proto, u8 transport_proto)
#define SESSION_RULES_TABLE_INVALID_INDEX
session_table_t * app_namespace_get_local_table(app_namespace_t *app_ns)
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
int session_lookup_del_session_endpoint(u32 table_index, session_endpoint_t *sep)
#define clib_warning(format, args...)
Definition: error.h:59
#define SESSION_INVALID_HANDLE
Definition: session_table.h:59
u8 ip4_is_local_host(ip4_address_t *ip4_address)
Definition: ip.c:39
struct _transport_connection transport_connection_t
u8 ip6_is_local_host(ip6_address_t *ip6_address)
Definition: ip.c:45
#define ARRAY_LEN(x)
Definition: clib.h:62
int session_lookup_add_session_endpoint(u32 table_index, session_endpoint_t *sep, u64 value)
struct _app_namespace app_namespace_t
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
session_table_t * session_table_get(u32 table_index)
Definition: session_table.c:46
static void make_v4_proxy_kv(session_kv4_t *kv, ip4_address_t *lcl, u8 proto)
struct _ip4_session_table_show_ctx_t ip4_session_table_show_ctx_t
#define ASSERT(truth)
uword unformat_transport_proto(unformat_input_t *input, va_list *args)
Definition: transport.c:161
u8 is_add
Definition: ipsec_gre.api:36
static u64 session_lookup_action_to_handle(u32 action_index)
void ip4_session_table_walk(clib_bihash_16_8_t *hash, ip4_session_table_walk_fn_t fn, void *arg)
#define SESSION_RULES_TABLE_ACTION_ALLOW
static void make_v4_listener_kv(session_kv4_t *kv, ip4_address_t *lcl, u16 lcl_port, u8 proto)
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u8 thread_index
Index of the thread that allocated the session.
void session_rules_table_show_rule(vlib_main_t *vm, session_rules_table_t *srt, ip46_address_t *lcl_ip, u16 lcl_port, ip46_address_t *rmt_ip, u16 rmt_port, u8 is_ip4)
u8 * format_ip4_session_lookup_kvp(u8 *s, va_list *args)
#define SESSION_RULE_TAG_MAX_LEN
static transport_connection_t * transport_get_half_open(transport_proto_t tp, u32 conn_index)
Definition: transport.h:103
app_worker_t * app_worker_get(u32 wrk_index)
void session_lookup_init(void)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
typedef key
Definition: ipsec.api:244
void session_lookup_dump_local_rules_table(u32 table_index, u8 fib_proto, u8 transport_proto)
app_worker_t * application_get_default_worker(application_t *app)
Definition: application.c:684
session_t * session_lookup_listener4(u32 fib_index, ip4_address_t *lcl, u16 lcl_port, u8 proto)
struct _session_lookup_table session_table_t
static session_table_t * session_table_get_or_alloc(u8 fib_proto, u8 fib_index)
int session_rules_table_add_del(session_rules_table_t *srt, session_rule_table_add_del_args_t *args)
Add/delete session rule.
int session_lookup_add_connection(transport_connection_t *tc, u64 value)
Add transport connection to a session table.
u32 session_table_index(session_table_t *slt)
Definition: session_table.c:40
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
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)
session_t * session_lookup_rules_table_session4(session_table_t *st, u8 proto, ip4_address_t *lcl, u16 lcl_port, ip4_address_t *rmt, u16 rmt_port)
UNUSED.
app_namespace_t * app_namespace_get_from_id(const u8 *ns_id)
u16 dst_port
Definition: udp.api:42
struct _session_endpoint session_endpoint_t
static transport_connection_t * transport_get_listener(transport_proto_t tp, u32 conn_index)
Definition: transport.h:97
static session_t * session_lookup_listener6_i(session_table_t *st, ip6_address_t *lcl, u16 lcl_port, u8 proto, u8 ip_wildcard)
int session_lookup_add_half_open(transport_connection_t *tc, u64 value)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:762
u8 * format_transport_proto(u8 *s, va_list *args)
Definition: transport.c:55
static void make_v4_ss_kv_from_tc(session_kv4_t *kv, transport_connection_t *tc)
static session_t * listen_session_get(u32 ls_index)
Definition: session.h:475
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
transport_connection_t * session_lookup_half_open_connection(u64 handle, u8 proto, u8 is_ip4)
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
clib_bihash_kv_16_8_t session_kv4_t