FD.io VPP  v19.08-27-gf4dcae4
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
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  if (ts->flags & TRANSPORT_CONNECTION_F_NO_LOOKUP)
342  return 0;
343  return session_lookup_del_connection (ts);
344 }
345 
346 static u8
348 {
349  if (action_index == SESSION_RULES_TABLE_ACTION_ALLOW
350  || action_index == SESSION_RULES_TABLE_INVALID_INDEX)
351  return 0;
352  return 1;
353 }
354 
355 static u64
357 {
358  switch (action_index)
359  {
361  return SESSION_DROP_HANDLE;
364  return SESSION_INVALID_HANDLE;
365  default:
366  /* application index */
367  return action_index;
368  }
369 }
370 
371 static session_t *
373  u8 transport_proto)
374 {
375  application_t *app;
376  app = application_get_if_valid (app_index);
377  if (!app)
378  return 0;
379 
381  fib_proto, transport_proto);
382 }
383 
384 static session_t *
385 session_lookup_action_to_session (u32 action_index, u8 fib_proto,
386  u8 transport_proto)
387 {
388  u32 app_index;
389  app_index = session_lookup_action_to_handle (action_index);
390  /* Nothing sophisticated for now, action index is app index */
391  return session_lookup_app_listen_session (app_index, fib_proto,
392  transport_proto);
393 }
394 
395 /** UNUSED */
396 session_t *
398  ip4_address_t * lcl, u16 lcl_port,
399  ip4_address_t * rmt, u16 rmt_port)
400 {
401  session_rules_table_t *srt = &st->session_rules[proto];
402  u32 action_index, app_index;
403  action_index = session_rules_table_lookup4 (srt, lcl, rmt, lcl_port,
404  rmt_port);
405  app_index = session_lookup_action_to_handle (action_index);
406  /* Nothing sophisticated for now, action index is app index */
408  proto);
409 }
410 
411 /** UNUSED */
412 session_t *
414  ip6_address_t * lcl, u16 lcl_port,
415  ip6_address_t * rmt, u16 rmt_port)
416 {
417  session_rules_table_t *srt = &st->session_rules[proto];
418  u32 action_index, app_index;
419  action_index = session_rules_table_lookup6 (srt, lcl, rmt, lcl_port,
420  rmt_port);
421  app_index = session_lookup_action_to_handle (action_index);
423  proto);
424 }
425 
426 /**
427  * Lookup listener for session endpoint in table
428  *
429  * @param table_index table where the endpoint should be looked up
430  * @param sep session endpoint to be looked up
431  * @param use_rules flag that indicates if the session rules of the table
432  * should be used
433  * @return invalid handle if nothing is found, the handle of a valid listener
434  * or an action derived handle if a rule is hit
435  */
436 u64
438  u8 use_rules)
439 {
441  session_table_t *st;
442  u32 ai;
443  int rv;
444 
445  st = session_table_get (table_index);
446  if (!st)
447  return SESSION_INVALID_HANDLE;
448  if (sep->is_ip4)
449  {
450  session_kv4_t kv4;
451  ip4_address_t lcl4;
452 
453  make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
454  sep->transport_proto);
455  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
456  if (rv == 0)
457  return kv4.value;
458  if (use_rules)
459  {
460  clib_memset (&lcl4, 0, sizeof (lcl4));
461  srt = &st->session_rules[sep->transport_proto];
462  ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
463  sep->port);
466  }
467  }
468  else
469  {
470  session_kv6_t kv6;
471  ip6_address_t lcl6;
472 
473  make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
474  sep->transport_proto);
475  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
476  if (rv == 0)
477  return kv6.value;
478 
479  if (use_rules)
480  {
481  clib_memset (&lcl6, 0, sizeof (lcl6));
482  srt = &st->session_rules[sep->transport_proto];
483  ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
484  sep->port);
487  }
488  }
489  return SESSION_INVALID_HANDLE;
490 }
491 
492 /**
493  * Look up endpoint in local session table
494  *
495  * The result, for now, is an application index and it may in the future
496  * be extended to a more complicated "action object". The only action we
497  * emulate now is "drop" and for that we return a special app index.
498  *
499  * Lookup logic is to check in order:
500  * - the rules in the table (connect acls)
501  * - session sub-table for a listener
502  * - session sub-table for a local listener (zeroed addr)
503  *
504  * @param table_index table where the lookup should be done
505  * @param sep session endpoint to be looked up
506  * @return session handle that can be interpreted as an adjacency
507  */
508 u64
510 {
512  session_table_t *st;
513  u32 ai;
514  int rv;
515 
516  st = session_table_get (table_index);
517  if (!st)
518  return SESSION_INVALID_INDEX;
519  ASSERT (st->is_local);
520 
521  if (sep->is_ip4)
522  {
523  session_kv4_t kv4;
524  ip4_address_t lcl4;
525 
526  /*
527  * Check if endpoint has special rules associated
528  */
529  clib_memset (&lcl4, 0, sizeof (lcl4));
530  srt = &st->session_rules[sep->transport_proto];
531  ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
532  sep->port);
535 
536  /*
537  * Check if session endpoint is a listener
538  */
539  make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
540  sep->transport_proto);
541  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
542  if (rv == 0)
543  return kv4.value;
544 
545  /*
546  * Zero out the ip. Logic is that connect to local ips, say
547  * 127.0.0.1:port, can match 0.0.0.0:port
548  */
549  if (ip4_is_local_host (&sep->ip.ip4))
550  {
551  kv4.key[0] = 0;
552  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
553  if (rv == 0)
554  return kv4.value;
555  }
556  else
557  {
558  kv4.key[0] = 0;
559  }
560 
561  /*
562  * Zero out the port and check if we have proxy
563  */
564  kv4.key[1] = 0;
565  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
566  if (rv == 0)
567  return kv4.value;
568  }
569  else
570  {
571  session_kv6_t kv6;
572  ip6_address_t lcl6;
573 
574  clib_memset (&lcl6, 0, sizeof (lcl6));
575  srt = &st->session_rules[sep->transport_proto];
576  ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
577  sep->port);
580 
581  make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
582  sep->transport_proto);
583  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
584  if (rv == 0)
585  return kv6.value;
586 
587  /*
588  * Zero out the ip. Same logic as above.
589  */
590 
591  if (ip6_is_local_host (&sep->ip.ip6))
592  {
593  kv6.key[0] = kv6.key[1] = 0;
594  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
595  if (rv == 0)
596  return kv6.value;
597  }
598  else
599  {
600  kv6.key[0] = kv6.key[1] = 0;
601  }
602 
603  /*
604  * Zero out the port. Same logic as above.
605  */
606  kv6.key[4] = kv6.key[5] = 0;
607  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
608  if (rv == 0)
609  return kv6.value;
610  }
611  return SESSION_INVALID_HANDLE;
612 }
613 
614 static inline session_t *
616  u16 lcl_port, u8 proto, u8 use_wildcard)
617 {
618  session_kv4_t kv4;
619  int rv;
620 
621  /*
622  * First, try a fully formed listener
623  */
624  make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
625  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
626  if (rv == 0)
627  return listen_session_get ((u32) kv4.value);
628 
629  /*
630  * Zero out the lcl ip and check if any 0/0 port binds have been done
631  */
632  if (use_wildcard)
633  {
634  kv4.key[0] = 0;
635  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
636  if (rv == 0)
637  return listen_session_get ((u32) kv4.value);
638  }
639  else
640  {
641  kv4.key[0] = 0;
642  }
643 
644  /*
645  * Zero out port and check if we have a proxy set up for our ip
646  */
647  make_v4_proxy_kv (&kv4, lcl, proto);
648  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
649  if (rv == 0)
650  return listen_session_get ((u32) kv4.value);
651 
652  return 0;
653 }
654 
655 session_t *
656 session_lookup_listener4 (u32 fib_index, ip4_address_t * lcl, u16 lcl_port,
657  u8 proto)
658 {
659  session_table_t *st;
661  if (!st)
662  return 0;
663  return session_lookup_listener4_i (st, lcl, lcl_port, proto, 0);
664 }
665 
666 static session_t *
668  u16 lcl_port, u8 proto, u8 ip_wildcard)
669 {
670  session_kv6_t kv6;
671  int rv;
672 
673  make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
674  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
675  if (rv == 0)
676  return listen_session_get ((u32) kv6.value);
677 
678  /* Zero out the lcl ip */
679  if (ip_wildcard)
680  {
681  kv6.key[0] = kv6.key[1] = 0;
682  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
683  if (rv == 0)
684  return listen_session_get ((u32) kv6.value);
685  }
686  else
687  {
688  kv6.key[0] = kv6.key[1] = 0;
689  }
690 
691  make_v6_proxy_kv (&kv6, lcl, proto);
692  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
693  if (rv == 0)
694  return listen_session_get ((u32) kv6.value);
695  return 0;
696 }
697 
698 session_t *
699 session_lookup_listener6 (u32 fib_index, ip6_address_t * lcl, u16 lcl_port,
700  u8 proto)
701 {
702  session_table_t *st;
704  if (!st)
705  return 0;
706  return session_lookup_listener6_i (st, lcl, lcl_port, proto, 1);
707 }
708 
709 /**
710  * Lookup listener, exact or proxy (inaddr_any:0) match
711  */
712 session_t *
714 {
715  session_table_t *st;
716  st = session_table_get (table_index);
717  if (!st)
718  return 0;
719  if (sep->is_ip4)
720  return session_lookup_listener4_i (st, &sep->ip.ip4, sep->port,
721  sep->transport_proto, 0);
722  else
723  return session_lookup_listener6_i (st, &sep->ip.ip6, sep->port,
724  sep->transport_proto, 0);
725  return 0;
726 }
727 
728 /**
729  * Lookup listener wildcard match
730  */
731 session_t *
733 {
734  session_table_t *st;
735  st = session_table_get (table_index);
736  if (!st)
737  return 0;
738  if (sep->is_ip4)
739  return session_lookup_listener4_i (st, &sep->ip.ip4, sep->port,
740  sep->transport_proto,
741  1 /* use_wildcard */ );
742  else
743  return session_lookup_listener6_i (st, &sep->ip.ip6, sep->port,
744  sep->transport_proto,
745  1 /* use_wildcard */ );
746  return 0;
747 }
748 
749 int
751 {
752  session_table_t *st;
753  session_kv4_t kv4;
754  session_kv6_t kv6;
755 
757  if (!st)
758  return 0;
759  if (tc->is_ip4)
760  {
761  make_v4_ss_kv_from_tc (&kv4, tc);
762  kv4.value = value;
763  return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
764  1 /* is_add */ );
765  }
766  else
767  {
768  make_v6_ss_kv_from_tc (&kv6, tc);
769  kv6.value = value;
770  return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
771  1 /* is_add */ );
772  }
773 }
774 
775 int
777 {
778  session_table_t *st;
779  session_kv4_t kv4;
780  session_kv6_t kv6;
781 
783  if (!st)
784  return -1;
785  if (tc->is_ip4)
786  {
787  make_v4_ss_kv_from_tc (&kv4, tc);
788  return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
789  0 /* is_add */ );
790  }
791  else
792  {
793  make_v6_ss_kv_from_tc (&kv6, tc);
794  return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
795  0 /* is_add */ );
796  }
797 }
798 
799 u64
801 {
802  session_table_t *st;
803  session_kv4_t kv4;
804  session_kv6_t kv6;
805  int rv;
806 
808  tc->fib_index);
809  if (!st)
811  if (tc->is_ip4)
812  {
813  make_v4_ss_kv (&kv4, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port,
814  tc->rmt_port, tc->proto);
815  rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
816  if (rv == 0)
817  return kv4.value;
818  }
819  else
820  {
821  make_v6_ss_kv (&kv6, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port,
822  tc->rmt_port, tc->proto);
823  rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
824  if (rv == 0)
825  return kv6.value;
826  }
828 }
829 
832 {
833  if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
834  {
835  u32 sst = session_type_from_proto_and_ip (proto, is_ip4);
836  return transport_get_half_open (sst, handle & 0xFFFFFFFF);
837  }
838  return 0;
839 }
840 
841 /**
842  * Lookup connection with ip4 and transport layer information
843  *
844  * This is used on the fast path so it needs to be fast. Thereby,
845  * duplication of code and 'hacks' allowed.
846  *
847  * The lookup is incremental and returns whenever something is matched. The
848  * steps are:
849  * - Try to find an established session
850  * - Try to find a half-open connection
851  * - Try session rules table
852  * - Try to find a fully-formed or local source wildcarded (listener bound to
853  * all interfaces) listener session
854  * - return 0
855  *
856  * @param fib_index index of fib wherein the connection was received
857  * @param lcl local ip4 address
858  * @param rmt remote ip4 address
859  * @param lcl_port local port
860  * @param rmt_port remote port
861  * @param proto transport protocol (e.g., tcp, udp)
862  * @param thread_index thread index for request
863  * @param is_filtered return flag that indicates if connection was filtered.
864  *
865  * @return pointer to transport connection, if one is found, 0 otherwise
866  */
869  ip4_address_t * rmt, u16 lcl_port,
870  u16 rmt_port, u8 proto, u32 thread_index,
871  u8 * result)
872 {
873  session_table_t *st;
874  session_kv4_t kv4;
875  session_t *s;
876  u32 action_index;
877  int rv;
878 
880  if (PREDICT_FALSE (!st))
881  return 0;
882 
883  /*
884  * Lookup session amongst established ones
885  */
886  make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
887  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
888  if (rv == 0)
889  {
890  if (PREDICT_FALSE ((u32) (kv4.value >> 32) != thread_index))
891  {
893  return 0;
894  }
895  s = session_get (kv4.value & 0xFFFFFFFFULL, thread_index);
896  return transport_get_connection (proto, s->connection_index,
897  thread_index);
898  }
899 
900  /*
901  * Try half-open connections
902  */
903  rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
904  if (rv == 0)
905  return transport_get_half_open (proto, kv4.value & 0xFFFFFFFF);
906 
907  /*
908  * Check the session rules table
909  */
910  action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
911  rmt, lcl_port, rmt_port);
912  if (session_lookup_action_index_is_valid (action_index))
913  {
914  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
915  {
917  return 0;
918  }
919  if ((s = session_lookup_action_to_session (action_index,
920  FIB_PROTOCOL_IP4, proto)))
921  return transport_get_listener (proto, s->connection_index);
922  return 0;
923  }
924 
925  /*
926  * If nothing is found, check if any listener is available
927  */
928  s = session_lookup_listener4_i (st, lcl, lcl_port, proto, 1);
929  if (s)
930  return transport_get_listener (proto, s->connection_index);
931 
932  return 0;
933 }
934 
935 /**
936  * Lookup connection with ip4 and transport layer information
937  *
938  * Not optimized. Lookup logic is identical to that of
939  * @ref session_lookup_connection_wt4
940  *
941  * @param fib_index index of the fib wherein the connection was received
942  * @param lcl local ip4 address
943  * @param rmt remote ip4 address
944  * @param lcl_port local port
945  * @param rmt_port remote port
946  * @param proto transport protocol (e.g., tcp, udp)
947  *
948  * @return pointer to transport connection, if one is found, 0 otherwise
949  */
952  ip4_address_t * rmt, u16 lcl_port, u16 rmt_port,
953  u8 proto)
954 {
955  session_table_t *st;
956  session_kv4_t kv4;
957  session_t *s;
958  u32 action_index;
959  int rv;
960 
962  if (PREDICT_FALSE (!st))
963  return 0;
964 
965  /*
966  * Lookup session amongst established ones
967  */
968  make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
969  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
970  if (rv == 0)
971  {
972  s = session_get_from_handle (kv4.value);
973  return transport_get_connection (proto, s->connection_index,
974  s->thread_index);
975  }
976 
977  /*
978  * Try half-open connections
979  */
980  rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
981  if (rv == 0)
982  return transport_get_half_open (proto, kv4.value & 0xFFFFFFFF);
983 
984  /*
985  * Check the session rules table
986  */
987  action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
988  rmt, lcl_port, rmt_port);
989  if (session_lookup_action_index_is_valid (action_index))
990  {
991  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
992  return 0;
993  if ((s = session_lookup_action_to_session (action_index,
994  FIB_PROTOCOL_IP4, proto)))
995  return transport_get_listener (proto, s->connection_index);
996  return 0;
997  }
998 
999  /*
1000  * If nothing is found, check if any listener is available
1001  */
1002  s = session_lookup_listener4_i (st, lcl, lcl_port, proto, 1);
1003  if (s)
1004  return transport_get_listener (proto, s->connection_index);
1005 
1006  return 0;
1007 }
1008 
1009 /**
1010  * Lookup session with ip4 and transport layer information
1011  *
1012  * Important note: this may look into another thread's pool table and
1013  * register as 'peeker'. Caller should call @ref session_pool_remove_peeker as
1014  * if needed as soon as possible.
1015  *
1016  * Lookup logic is similar to that of @ref session_lookup_connection_wt4 but
1017  * this returns a session as opposed to a transport connection and it does not
1018  * try to lookup half-open sessions.
1019  *
1020  * Typically used by dgram connections
1021  */
1022 session_t *
1024  u16 lcl_port, u16 rmt_port, u8 proto)
1025 {
1026  session_table_t *st;
1027  session_kv4_t kv4;
1028  session_t *s;
1029  u32 action_index;
1030  int rv;
1031 
1033  if (PREDICT_FALSE (!st))
1034  return 0;
1035 
1036  /*
1037  * Lookup session amongst established ones
1038  */
1039  make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
1040  rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
1041  if (rv == 0)
1042  return session_get_from_handle_safe (kv4.value);
1043 
1044  /*
1045  * Check the session rules table
1046  */
1047  action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
1048  rmt, lcl_port, rmt_port);
1049  if (session_lookup_action_index_is_valid (action_index))
1050  {
1051  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1052  return 0;
1053  return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
1054  proto);
1055  }
1056 
1057  /*
1058  * If nothing is found, check if any listener is available
1059  */
1060  if ((s = session_lookup_listener4_i (st, lcl, lcl_port, proto, 1)))
1061  return s;
1062 
1063  return 0;
1064 }
1065 
1066 /**
1067  * Lookup connection with ip6 and transport layer information
1068  *
1069  * This is used on the fast path so it needs to be fast. Thereby,
1070  * duplication of code and 'hacks' allowed.
1071  *
1072  * The lookup is incremental and returns whenever something is matched. The
1073  * steps are:
1074  * - Try to find an established session
1075  * - Try to find a half-open connection
1076  * - Try session rules table
1077  * - Try to find a fully-formed or local source wildcarded (listener bound to
1078  * all interfaces) listener session
1079  * - return 0
1080  *
1081  * @param fib_index index of the fib wherein the connection was received
1082  * @param lcl local ip6 address
1083  * @param rmt remote ip6 address
1084  * @param lcl_port local port
1085  * @param rmt_port remote port
1086  * @param proto transport protocol (e.g., tcp, udp)
1087  * @param thread_index thread index for request
1088  *
1089  * @return pointer to transport connection, if one is found, 0 otherwise
1090  */
1093  ip6_address_t * rmt, u16 lcl_port,
1094  u16 rmt_port, u8 proto, u32 thread_index,
1095  u8 * result)
1096 {
1097  session_table_t *st;
1098  session_t *s;
1099  session_kv6_t kv6;
1100  u32 action_index;
1101  int rv;
1102 
1104  if (PREDICT_FALSE (!st))
1105  return 0;
1106 
1107  make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1108  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1109  if (rv == 0)
1110  {
1111  ASSERT ((u32) (kv6.value >> 32) == thread_index);
1112  if (PREDICT_FALSE ((u32) (kv6.value >> 32) != thread_index))
1113  {
1115  return 0;
1116  }
1117  s = session_get (kv6.value & 0xFFFFFFFFULL, thread_index);
1118  return transport_get_connection (proto, s->connection_index,
1119  thread_index);
1120  }
1121 
1122  /* Try half-open connections */
1123  rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
1124  if (rv == 0)
1125  return transport_get_half_open (proto, kv6.value & 0xFFFFFFFF);
1126 
1127  /* Check the session rules table */
1128  action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
1129  rmt, lcl_port, rmt_port);
1130  if (session_lookup_action_index_is_valid (action_index))
1131  {
1132  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1133  {
1135  return 0;
1136  }
1137  if ((s = session_lookup_action_to_session (action_index,
1138  FIB_PROTOCOL_IP6, proto)))
1139  return transport_get_listener (proto, s->connection_index);
1140  return 0;
1141  }
1142 
1143  /* If nothing is found, check if any listener is available */
1144  s = session_lookup_listener6_i (st, lcl, lcl_port, proto, 1);
1145  if (s)
1146  return transport_get_listener (proto, s->connection_index);
1147 
1148  return 0;
1149 }
1150 
1151 /**
1152  * Lookup connection with ip6 and transport layer information
1153  *
1154  * Not optimized. This is used on the fast path so it needs to be fast.
1155  * Thereby, duplication of code and 'hacks' allowed. Lookup logic is identical
1156  * to that of @ref session_lookup_connection_wt4
1157  *
1158  * @param fib_index index of the fib wherein the connection was received
1159  * @param lcl local ip6 address
1160  * @param rmt remote ip6 address
1161  * @param lcl_port local port
1162  * @param rmt_port remote port
1163  * @param proto transport protocol (e.g., tcp, udp)
1164  *
1165  * @return pointer to transport connection, if one is found, 0 otherwise
1166  */
1169  ip6_address_t * rmt, u16 lcl_port, u16 rmt_port,
1170  u8 proto)
1171 {
1172  session_table_t *st;
1173  session_t *s;
1174  session_kv6_t kv6;
1175  u32 action_index;
1176  int rv;
1177 
1179  if (PREDICT_FALSE (!st))
1180  return 0;
1181 
1182  make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1183  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1184  if (rv == 0)
1185  {
1186  s = session_get_from_handle (kv6.value);
1187  return transport_get_connection (proto, s->connection_index,
1188  s->thread_index);
1189  }
1190 
1191  /* Try half-open connections */
1192  rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
1193  if (rv == 0)
1194  return transport_get_half_open (proto, kv6.value & 0xFFFFFFFF);
1195 
1196  /* Check the session rules table */
1197  action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
1198  rmt, lcl_port, rmt_port);
1199  if (session_lookup_action_index_is_valid (action_index))
1200  {
1201  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1202  return 0;
1203  if ((s = session_lookup_action_to_session (action_index,
1204  FIB_PROTOCOL_IP6, proto)))
1205  return transport_get_listener (proto, s->connection_index);
1206  return 0;
1207  }
1208 
1209  /* If nothing is found, check if any listener is available */
1210  s = session_lookup_listener6_i (st, lcl, lcl_port, proto, 1);
1211  if (s)
1212  return transport_get_listener (proto, s->connection_index);
1213 
1214  return 0;
1215 }
1216 
1217 /**
1218  * Lookup session with ip6 and transport layer information
1219  *
1220  * Important note: this may look into another thread's pool table and
1221  * register as 'peeker'. Caller should call @ref session_pool_remove_peeker as
1222  * if needed as soon as possible.
1223  *
1224  * Lookup logic is similar to that of @ref session_lookup_connection_wt6 but
1225  * this returns a session as opposed to a transport connection and it does not
1226  * try to lookup half-open sessions.
1227  *
1228  * Typically used by dgram connections
1229  */
1230 session_t *
1232  u16 lcl_port, u16 rmt_port, u8 proto)
1233 {
1234  session_table_t *st;
1235  session_kv6_t kv6;
1236  session_t *s;
1237  u32 action_index;
1238  int rv;
1239 
1241  if (PREDICT_FALSE (!st))
1242  return 0;
1243 
1244  make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1245  rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1246  if (rv == 0)
1247  return session_get_from_handle_safe (kv6.value);
1248 
1249  /* Check the session rules table */
1250  action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
1251  rmt, lcl_port, rmt_port);
1252  if (session_lookup_action_index_is_valid (action_index))
1253  {
1254  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1255  return 0;
1256  return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP6,
1257  proto);
1258  }
1259 
1260  /* If nothing is found, check if any listener is available */
1261  if ((s = session_lookup_listener6_i (st, lcl, lcl_port, proto, 1)))
1262  return s;
1263  return 0;
1264 }
1265 
1266 int
1268 {
1269  app_namespace_t *app_ns = app_namespace_get (args->appns_index);
1270  session_rules_table_t *srt;
1271  session_table_t *st;
1272  u32 fib_index;
1273  u8 fib_proto;
1274  int rv = 0;
1275 
1276  if (!app_ns)
1277  return VNET_API_ERROR_APP_INVALID_NS;
1278 
1279  if (args->scope > 3)
1280  return VNET_API_ERROR_INVALID_VALUE;
1281 
1282  if (args->transport_proto != TRANSPORT_PROTO_TCP
1283  && args->transport_proto != TRANSPORT_PROTO_UDP)
1284  return VNET_API_ERROR_INVALID_VALUE;
1285 
1286  if ((args->scope & SESSION_RULE_SCOPE_GLOBAL) || args->scope == 0)
1287  {
1288  fib_proto = args->table_args.rmt.fp_proto;
1289  fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1290  st = session_table_get_for_fib_index (fib_proto, fib_index);
1291  srt = &st->session_rules[args->transport_proto];
1292  if ((rv = session_rules_table_add_del (srt, &args->table_args)))
1293  return rv;
1294  }
1295  if (args->scope & SESSION_RULE_SCOPE_LOCAL)
1296  {
1297  clib_memset (&args->table_args.lcl, 0, sizeof (args->table_args.lcl));
1298  args->table_args.lcl.fp_proto = args->table_args.rmt.fp_proto;
1299  args->table_args.lcl_port = 0;
1300  st = app_namespace_get_local_table (app_ns);
1301  srt = &st->session_rules[args->transport_proto];
1302  rv = session_rules_table_add_del (srt, &args->table_args);
1303  }
1304  return rv;
1305 }
1306 
1307 /**
1308  * Mark (global) tables as pertaining to app ns
1309  */
1310 void
1312 {
1313  session_table_t *st;
1314  u32 fib_index;
1315  u8 fp;
1316 
1317  for (fp = 0; fp < ARRAY_LEN (fib_index_to_table_index); fp++)
1318  {
1319  fib_index = app_namespace_get_fib_index (app_ns, fp);
1320  st = session_table_get_for_fib_index (fp, fib_index);
1321  if (st)
1322  st->appns_index = app_namespace_index (app_ns);
1323  }
1324 }
1325 
1326 u8 *
1327 format_ip4_session_lookup_kvp (u8 * s, va_list * args)
1328 {
1329  clib_bihash_kv_16_8_t *kvp = va_arg (*args, clib_bihash_kv_16_8_t *);
1330  u32 is_local = va_arg (*args, u32);
1331  v4_connection_key_t *key = (v4_connection_key_t *) kvp->key;
1332  session_t *session;
1333  app_worker_t *app_wrk;
1334  const u8 *app_name;
1335  u8 *str = 0;
1336 
1337  if (!is_local)
1338  {
1339  session = session_get_from_handle (kvp->value);
1340  app_wrk = app_worker_get (session->app_wrk_index);
1341  app_name = application_name_from_index (app_wrk->app_index);
1342  str = format (0, "[%U] %U:%d->%U:%d", format_transport_proto_short,
1343  key->proto, format_ip4_address, &key->src,
1344  clib_net_to_host_u16 (key->src_port), format_ip4_address,
1345  &key->dst, clib_net_to_host_u16 (key->dst_port));
1346  s = format (s, "%-40v%-30v", str, app_name);
1347  }
1348  else
1349  {
1350  session = session_get_from_handle (kvp->value);
1351  app_wrk = app_worker_get (session->app_wrk_index);
1352  app_name = application_name_from_index (app_wrk->app_index);
1353  str = format (0, "[%U] %U:%d", format_transport_proto_short, key->proto,
1354  format_ip4_address, &key->src,
1355  clib_net_to_host_u16 (key->src_port));
1356  s = format (s, "%-30v%-30v", str, app_name);
1357  }
1358  return s;
1359 }
1360 
1361 typedef struct _ip4_session_table_show_ctx_t
1362 {
1363  vlib_main_t *vm;
1364  u8 is_local;
1366 
1367 static int
1369 {
1371  vlib_cli_output (ctx->vm, "%U", format_ip4_session_lookup_kvp, kvp,
1372  ctx->is_local);
1373  return 1;
1374 }
1375 
1376 void
1378  u8 type, u8 is_local)
1379 {
1381  .vm = vm,
1382  .is_local = is_local,
1383  };
1384  if (!is_local)
1385  vlib_cli_output (vm, "%-40s%-30s", "Session", "Application");
1386  else
1387  vlib_cli_output (vm, "%-30s%-30s", "Listener", "Application");
1388  switch (type)
1389  {
1390  /* main table v4 */
1391  case 0:
1392  ip4_session_table_walk (&table->v4_session_hash, ip4_session_table_show,
1393  &ctx);
1394  break;
1395  default:
1396  clib_warning ("not supported");
1397  }
1398 }
1399 
1400 static clib_error_t *
1402  vlib_cli_command_t * cmd)
1403 {
1404  u32 proto = ~0, lcl_port, rmt_port, action = 0, lcl_plen = 0, rmt_plen = 0;
1405  u32 appns_index, scope = 0;
1406  ip46_address_t lcl_ip, rmt_ip;
1407  u8 is_ip4 = 1, conn_set = 0;
1408  u8 fib_proto, is_add = 1, *ns_id = 0;
1409  u8 *tag = 0;
1410  app_namespace_t *app_ns;
1411  int rv;
1412 
1413  clib_memset (&lcl_ip, 0, sizeof (lcl_ip));
1414  clib_memset (&rmt_ip, 0, sizeof (rmt_ip));
1415  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1416  {
1417  if (unformat (input, "del"))
1418  is_add = 0;
1419  else if (unformat (input, "add"))
1420  ;
1421  else if (unformat (input, "appns %_%v%_", &ns_id))
1422  ;
1423  else if (unformat (input, "scope global"))
1424  scope = SESSION_RULE_SCOPE_GLOBAL;
1425  else if (unformat (input, "scope local"))
1426  scope = SESSION_RULE_SCOPE_LOCAL;
1427  else if (unformat (input, "scope all"))
1429  else if (unformat (input, "proto %U", unformat_transport_proto, &proto))
1430  ;
1431  else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address,
1432  &lcl_ip.ip4, &lcl_plen, &lcl_port,
1433  unformat_ip4_address, &rmt_ip.ip4, &rmt_plen,
1434  &rmt_port))
1435  {
1436  is_ip4 = 1;
1437  conn_set = 1;
1438  }
1439  else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address,
1440  &lcl_ip.ip6, &lcl_plen, &lcl_port,
1441  unformat_ip6_address, &rmt_ip.ip6, &rmt_plen,
1442  &rmt_port))
1443  {
1444  is_ip4 = 0;
1445  conn_set = 1;
1446  }
1447  else if (unformat (input, "action %d", &action))
1448  ;
1449  else if (unformat (input, "tag %_%v%_", &tag))
1450  ;
1451  else
1452  return clib_error_return (0, "unknown input `%U'",
1453  format_unformat_error, input);
1454  }
1455 
1456  if (proto == ~0)
1457  {
1458  vlib_cli_output (vm, "proto must be set");
1459  return 0;
1460  }
1461  if (is_add && !conn_set && action == ~0)
1462  {
1463  vlib_cli_output (vm, "connection and action must be set for add");
1464  return 0;
1465  }
1466  if (!is_add && !tag && !conn_set)
1467  {
1468  vlib_cli_output (vm, "connection or tag must be set for delete");
1469  return 0;
1470  }
1471  if (vec_len (tag) > SESSION_RULE_TAG_MAX_LEN)
1472  {
1473  vlib_cli_output (vm, "tag too long (max u64)");
1474  return 0;
1475  }
1476 
1477  if (ns_id)
1478  {
1479  app_ns = app_namespace_get_from_id (ns_id);
1480  if (!app_ns)
1481  {
1482  vlib_cli_output (vm, "namespace %v does not exist", ns_id);
1483  return 0;
1484  }
1485  }
1486  else
1487  {
1488  app_ns = app_namespace_get_default ();
1489  }
1490  appns_index = app_namespace_index (app_ns);
1491 
1492  fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
1494  .transport_proto = proto,
1495  .table_args.lcl.fp_addr = lcl_ip,
1496  .table_args.lcl.fp_len = lcl_plen,
1497  .table_args.lcl.fp_proto = fib_proto,
1498  .table_args.rmt.fp_addr = rmt_ip,
1499  .table_args.rmt.fp_len = rmt_plen,
1500  .table_args.rmt.fp_proto = fib_proto,
1501  .table_args.lcl_port = lcl_port,
1502  .table_args.rmt_port = rmt_port,
1503  .table_args.action_index = action,
1504  .table_args.is_add = is_add,
1505  .table_args.tag = tag,
1506  .appns_index = appns_index,
1507  .scope = scope,
1508  };
1509  if ((rv = vnet_session_rule_add_del (&args)))
1510  return clib_error_return (0, "rule add del returned %u", rv);
1511 
1512  vec_free (tag);
1513  return 0;
1514 }
1515 
1516 /* *INDENT-OFF* */
1517 VLIB_CLI_COMMAND (session_rule_command, static) =
1518 {
1519  .path = "session rule",
1520  .short_help = "session rule [add|del] appns <ns_id> proto <proto> "
1521  "<lcl-ip/plen> <lcl-port> <rmt-ip/plen> <rmt-port> action <action>",
1522  .function = session_rule_command_fn,
1523 };
1524 /* *INDENT-ON* */
1525 
1526 void
1528  u8 transport_proto)
1529 {
1531  session_rules_table_t *srt;
1532  session_table_t *st;
1533  st = session_table_get_for_fib_index (fib_index, fib_proto);
1534  srt = &st->session_rules[transport_proto];
1535  session_rules_table_cli_dump (vm, srt, fib_proto);
1536 }
1537 
1538 void
1540  u8 transport_proto)
1541 {
1543  session_rules_table_t *srt;
1544  session_table_t *st;
1545  st = session_table_get (table_index);
1546  srt = &st->session_rules[transport_proto];
1547  session_rules_table_cli_dump (vm, srt, fib_proto);
1548 }
1549 
1550 static clib_error_t *
1552  vlib_cli_command_t * cmd)
1553 {
1554  u32 transport_proto = ~0, lcl_port, rmt_port, lcl_plen, rmt_plen;
1555  u32 fib_index, scope = 0;
1556  ip46_address_t lcl_ip, rmt_ip;
1557  u8 is_ip4 = 1, show_one = 0;
1558  app_namespace_t *app_ns;
1559  session_rules_table_t *srt;
1560  session_table_t *st;
1561  u8 *ns_id = 0, fib_proto;
1562 
1563  clib_memset (&lcl_ip, 0, sizeof (lcl_ip));
1564  clib_memset (&rmt_ip, 0, sizeof (rmt_ip));
1565  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1566  {
1567  if (unformat (input, "%U", unformat_transport_proto, &transport_proto))
1568  ;
1569  else if (unformat (input, "appns %_%v%_", &ns_id))
1570  ;
1571  else if (unformat (input, "scope global"))
1572  scope = 1;
1573  else if (unformat (input, "scope local"))
1574  scope = 2;
1575  else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address,
1576  &lcl_ip.ip4, &lcl_plen, &lcl_port,
1577  unformat_ip4_address, &rmt_ip.ip4, &rmt_plen,
1578  &rmt_port))
1579  {
1580  is_ip4 = 1;
1581  show_one = 1;
1582  }
1583  else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address,
1584  &lcl_ip.ip6, &lcl_plen, &lcl_port,
1585  unformat_ip6_address, &rmt_ip.ip6, &rmt_plen,
1586  &rmt_port))
1587  {
1588  is_ip4 = 0;
1589  show_one = 1;
1590  }
1591  else
1592  return clib_error_return (0, "unknown input `%U'",
1593  format_unformat_error, input);
1594  }
1595 
1596  if (transport_proto == ~0)
1597  {
1598  vlib_cli_output (vm, "transport proto must be set");
1599  return 0;
1600  }
1601 
1602  if (ns_id)
1603  {
1604  app_ns = app_namespace_get_from_id (ns_id);
1605  if (!app_ns)
1606  {
1607  vlib_cli_output (vm, "appns %v doesn't exist", ns_id);
1608  return 0;
1609  }
1610  }
1611  else
1612  {
1613  app_ns = app_namespace_get_default ();
1614  }
1615 
1616  if (scope == 1 || scope == 0)
1617  {
1618  fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
1619  fib_index = is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
1620  st = session_table_get_for_fib_index (fib_proto, fib_index);
1621  }
1622  else
1623  {
1624  st = app_namespace_get_local_table (app_ns);
1625  }
1626 
1627  if (show_one)
1628  {
1629  srt = &st->session_rules[transport_proto];
1630  session_rules_table_show_rule (vm, srt, &lcl_ip, lcl_port, &rmt_ip,
1631  rmt_port, is_ip4);
1632  return 0;
1633  }
1634 
1635  vlib_cli_output (vm, "%U rules table", format_transport_proto,
1636  transport_proto);
1637  srt = &st->session_rules[transport_proto];
1640 
1641  vec_free (ns_id);
1642  return 0;
1643 }
1644 
1645 /* *INDENT-OFF* */
1646 VLIB_CLI_COMMAND (show_session_rules_command, static) =
1647 {
1648  .path = "show session rules",
1649  .short_help = "show session rules [<proto> appns <id> <lcl-ip/plen> "
1650  "<lcl-port> <rmt-ip/plen> <rmt-port> scope <scope>]",
1651  .function = show_session_rules_command_fn,
1652 };
1653 /* *INDENT-ON* */
1654 
1655 void
1657 {
1658  /*
1659  * Allocate default table and map it to fib_index 0
1660  */
1662  vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP4], 0);
1663  fib_index_to_table_index[FIB_PROTOCOL_IP4][0] = session_table_index (st);
1664  st->active_fib_proto = FIB_PROTOCOL_IP4;
1665  session_table_init (st, FIB_PROTOCOL_IP4);
1666  st = session_table_alloc ();
1667  vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP6], 0);
1668  fib_index_to_table_index[FIB_PROTOCOL_IP6][0] = session_table_index (st);
1669  st->active_fib_proto = FIB_PROTOCOL_IP6;
1670  session_table_init (st, FIB_PROTOCOL_IP6);
1671 }
1672 
1673 /*
1674  * fd.io coding-style-patch-verification: ON
1675  *
1676  * Local Variables:
1677  * eval: (c-set-style "gnu")
1678  * End:
1679  */
#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:58
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:89
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.
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.
vl_api_address_t src
Definition: gre.api:51
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
static session_t * session_get(u32 si, u32 thread_index)
Definition: session.h:258
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
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:426
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
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
#define SESSION_INVALID_HANDLE
Definition: session_types.h:23
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.
vl_api_fib_path_type_t type
Definition: fib_types.api:123
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:278
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:352
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:330
int session_lookup_del_session(session_t *s)
app_namespace_t * app_namespace_get(u32 index)
#define SESSION_INVALID_INDEX
Definition: session_types.h:22
vl_api_address_t dst
Definition: gre.api:52
session_t * session_lookup_listener6(u32 fib_index, ip6_address_t *lcl, u16 lcl_port, u8 proto)
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:145
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:111
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
u8 ip4_is_local_host(ip4_address_t *ip4_address)
Definition: ip.c:39
Don&#39;t register connection in lookup Does not apply to local apps and transports using the network lay...
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
u8 value
Definition: qos.api:53
#define ASSERT(truth)
uword unformat_transport_proto(unformat_input_t *input, va_list *args)
Definition: transport.c:179
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
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];};})
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:124
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:245
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:654
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:118
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:768
vl_api_gbp_scope_t scope
Definition: gbp.api:73
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:524
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
transport_connection_t * session_lookup_half_open_connection(u64 handle, u8 proto, u8 is_ip4)
vl_api_fib_path_nh_proto_t proto
Definition: fib_types.api:125
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
clib_bihash_kv_16_8_t session_kv4_t