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