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