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