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