LCOV - code coverage report
Current view: top level - vnet/session - session_lookup.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 371 694 53.5 %
Date: 2023-07-05 22:20:52 Functions: 42 59 71.2 %

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

Generated by: LCOV version 1.14