LCOV - code coverage report
Current view: top level - plugins/ct6 - ct6.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 23 196 11.7 %
Date: 2023-10-26 01:39:38 Functions: 16 25 64.0 %

          Line data    Source code
       1             : /*
       2             :  * ct6.c - skeleton vpp engine plug-in
       3             :  *
       4             :  * Copyright (c) <current-year> <your-organization>
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vnet/vnet.h>
      19             : #include <vnet/plugin/plugin.h>
      20             : #include <ct6/ct6.h>
      21             : 
      22             : #include <vlibapi/api.h>
      23             : #include <vlibmemory/api.h>
      24             : #include <vpp/app/version.h>
      25             : 
      26             : /* define message IDs */
      27             : #include <ct6/ct6.api_enum.h>
      28             : #include <ct6/ct6.api_types.h>
      29             : 
      30             : #define REPLY_MSG_ID_BASE cmp->msg_id_base
      31             : #include <vlibapi/api_helper_macros.h>
      32             : 
      33             : ct6_main_t ct6_main;
      34             : 
      35             : /* Action function shared between message handler and debug CLI */
      36             : 
      37             : static void
      38           0 : ct6_feature_init (ct6_main_t * cmp)
      39             : {
      40           0 :   u32 nworkers = vlib_num_workers ();
      41             : 
      42           0 :   if (cmp->feature_initialized)
      43           0 :     return;
      44             : 
      45           0 :   clib_bihash_init_48_8 (&cmp->session_hash, "ct6 session table",
      46             :                          cmp->session_hash_buckets, cmp->session_hash_memory);
      47           0 :   cmp->feature_initialized = 1;
      48           0 :   vec_validate (cmp->sessions, nworkers);
      49           0 :   vec_validate_init_empty (cmp->first_index, nworkers, ~0);
      50           0 :   vec_validate_init_empty (cmp->last_index, nworkers, ~0);
      51             : }
      52             : 
      53             : int
      54           0 : ct6_in2out_enable_disable (ct6_main_t * cmp, u32 sw_if_index,
      55             :                            int enable_disable)
      56             : {
      57             :   vnet_sw_interface_t *sw;
      58           0 :   int rv = 0;
      59             : 
      60           0 :   ct6_feature_init (cmp);
      61             : 
      62             :   /* Utterly wrong? */
      63           0 :   if (pool_is_free_index (cmp->vnet_main->interface_main.sw_interfaces,
      64             :                           sw_if_index))
      65           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
      66             : 
      67             :   /* Not a physical port? */
      68           0 :   sw = vnet_get_sw_interface (cmp->vnet_main, sw_if_index);
      69           0 :   if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
      70           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
      71             : 
      72           0 :   vnet_feature_enable_disable ("interface-output", "ct6-in2out",
      73             :                                sw_if_index, enable_disable, 0, 0);
      74             : 
      75           0 :   return rv;
      76             : }
      77             : 
      78             : int
      79           0 : ct6_out2in_enable_disable (ct6_main_t * cmp, u32 sw_if_index,
      80             :                            int enable_disable)
      81             : {
      82             :   vnet_sw_interface_t *sw;
      83           0 :   int rv = 0;
      84             : 
      85           0 :   ct6_feature_init (cmp);
      86             : 
      87             :   /* Utterly wrong? */
      88           0 :   if (pool_is_free_index (cmp->vnet_main->interface_main.sw_interfaces,
      89             :                           sw_if_index))
      90           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
      91             : 
      92             :   /* Not a physical port? */
      93           0 :   sw = vnet_get_sw_interface (cmp->vnet_main, sw_if_index);
      94           0 :   if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
      95           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
      96             : 
      97           0 :   vnet_feature_enable_disable ("ip6-unicast", "ct6-out2in",
      98             :                                sw_if_index, enable_disable, 0, 0);
      99             : 
     100           0 :   return rv;
     101             : }
     102             : 
     103             : static clib_error_t *
     104           0 : set_ct6_enable_disable_command_fn (vlib_main_t * vm,
     105             :                                    unformat_input_t * input,
     106             :                                    vlib_cli_command_t * cmd)
     107             : {
     108           0 :   ct6_main_t *cmp = &ct6_main;
     109           0 :   u32 sw_if_index = ~0;
     110           0 :   int enable_disable = 1;
     111           0 :   u32 inside = ~0;
     112             :   int rv;
     113             : 
     114           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     115             :     {
     116           0 :       if (unformat (input, "disable"))
     117           0 :         enable_disable = 0;
     118           0 :       else if (unformat (input, "%U", unformat_vnet_sw_interface,
     119             :                          cmp->vnet_main, &sw_if_index))
     120             :         ;
     121           0 :       else if (unformat (input, "inside") || unformat (input, "in"))
     122           0 :         inside = 1;
     123           0 :       else if (unformat (input, "outside") || unformat (input, "out"))
     124           0 :         inside = 0;
     125             :       else
     126             :         break;
     127             :     }
     128             : 
     129           0 :   if (inside == ~0)
     130           0 :     return clib_error_return (0, "Please specify inside or outside");
     131             : 
     132           0 :   if (sw_if_index == ~0)
     133           0 :     return clib_error_return (0, "Please specify an interface...");
     134             : 
     135           0 :   if (inside == 1)
     136           0 :     rv = ct6_in2out_enable_disable (cmp, sw_if_index, enable_disable);
     137             :   else
     138           0 :     rv = ct6_out2in_enable_disable (cmp, sw_if_index, enable_disable);
     139             : 
     140           0 :   switch (rv)
     141             :     {
     142           0 :     case 0:
     143           0 :       break;
     144             : 
     145           0 :     case VNET_API_ERROR_INVALID_SW_IF_INDEX:
     146           0 :       return clib_error_return
     147             :         (0, "Invalid interface, only works on physical ports");
     148             :       break;
     149             : 
     150           0 :     default:
     151           0 :       return clib_error_return (0, "ct6_enable_disable returned %d", rv);
     152             :     }
     153           0 :   return 0;
     154             : }
     155             : 
     156             : /* *INDENT-OFF* */
     157      254185 : VLIB_CLI_COMMAND (set_ct6_command, static) =
     158             : {
     159             :   .path = "set ct6",
     160             :   .short_help =
     161             :   "set ct6 [inside|outside] <interface-name> [disable]",
     162             :   .function = set_ct6_enable_disable_command_fn,
     163             : };
     164             : /* *INDENT-ON* */
     165             : 
     166             : /* API message handler */
     167           0 : static void vl_api_ct6_enable_disable_t_handler
     168             :   (vl_api_ct6_enable_disable_t * mp)
     169             : {
     170             :   vl_api_ct6_enable_disable_reply_t *rmp;
     171           0 :   ct6_main_t *cmp = &ct6_main;
     172             :   int rv;
     173             : 
     174           0 :   VALIDATE_SW_IF_INDEX (mp);
     175             : 
     176           0 :   if (mp->is_inside)
     177           0 :     rv = ct6_in2out_enable_disable (cmp, ntohl (mp->sw_if_index),
     178           0 :                                     (int) (mp->enable_disable));
     179             :   else
     180           0 :     rv = ct6_out2in_enable_disable (cmp, ntohl (mp->sw_if_index),
     181           0 :                                     (int) (mp->enable_disable));
     182             : 
     183           0 :   BAD_SW_IF_INDEX_LABEL;
     184           0 :   REPLY_MACRO (VL_API_CT6_ENABLE_DISABLE_REPLY);
     185             : }
     186             : 
     187             : #include <ct6/ct6.api.c>
     188             : static clib_error_t *
     189         575 : ct6_init (vlib_main_t * vm)
     190             : {
     191         575 :   ct6_main_t *cmp = &ct6_main;
     192         575 :   clib_error_t *error = 0;
     193             : 
     194         575 :   cmp->vlib_main = vm;
     195         575 :   cmp->vnet_main = vnet_get_main ();
     196             : 
     197             :   /* Ask for a correctly-sized block of API message decode slots */
     198         575 :   cmp->msg_id_base = setup_message_id_table ();
     199             : 
     200             :   /*
     201             :    * Set default parameters...
     202             :    * 256K sessions
     203             :    * 64K buckets
     204             :    * 2 minute inactivity timer
     205             :    * 10000 concurrent sessions
     206             :    */
     207         575 :   cmp->session_hash_memory = 16ULL << 20;
     208         575 :   cmp->session_hash_buckets = 64 << 10;
     209         575 :   cmp->session_timeout_interval = 120.0;
     210         575 :   cmp->max_sessions_per_worker = 10000;
     211             : 
     212             :   /* ... so the packet generator can feed the in2out node ... */
     213         575 :   ethernet_setup_node (vm, ct6_in2out_node.index);
     214         575 :   return error;
     215             : }
     216             : 
     217        1151 : VLIB_INIT_FUNCTION (ct6_init);
     218             : 
     219             : /* *INDENT-OFF* */
     220       63387 : VNET_FEATURE_INIT (ct6out2in, static) =
     221             : {
     222             :   .arc_name = "ip6-unicast",
     223             :   .node_name = "ct6-out2in",
     224             :   .runs_before = VNET_FEATURES ("ip6-lookup"),
     225             : };
     226             : /* *INDENT-ON */
     227             : 
     228             : /* *INDENT-OFF* */
     229       63387 : VNET_FEATURE_INIT (ct6in2out, static) = {
     230             :   .arc_name = "interface-output",
     231             :   .node_name = "ct6-in2out",
     232             :   .runs_before = VNET_FEATURES ("interface-output-arc-end"),
     233             : };
     234             : /* *INDENT-ON */
     235             : 
     236             : /* *INDENT-OFF* */
     237             : VLIB_PLUGIN_REGISTER () =
     238             : {
     239             :   .version = VPP_BUILD_VER,
     240             :   .description = "IPv6 Connection Tracker",
     241             : };
     242             : /* *INDENT-ON* */
     243             : 
     244             : u8 *
     245           0 : format_ct6_session (u8 * s, va_list * args)
     246             : {
     247           0 :   ct6_main_t *cmp = va_arg (*args, ct6_main_t *);
     248           0 :   int i = va_arg (*args, int);
     249           0 :   ct6_session_t *s0 = va_arg (*args, ct6_session_t *);
     250           0 :   int verbose = va_arg (*args, int);
     251             :   clib_bihash_kv_48_8_t kvp0;
     252             : 
     253           0 :   if (s0 == 0)
     254             :     {
     255           0 :       s = format (s, "\n%6s%6s%40s%6s%40s%6s",
     256             :                   "Sess", "Prot", "Src", "Sport", "Dst", "Dport");
     257           0 :       return s;
     258             :     }
     259             : 
     260           0 :   s = format (s, "\n%6d%6d%40U%6u%40U%6u",
     261           0 :               s0 - cmp->sessions[i], s0->key.proto,
     262             :               format_ip6_address, &s0->key.src,
     263           0 :               clib_net_to_host_u16 (s0->key.sport),
     264             :               format_ip6_address, &s0->key.dst,
     265           0 :               clib_net_to_host_u16 (s0->key.dport));
     266             : 
     267           0 :   clib_memcpy_fast (&kvp0, s0, sizeof (ct6_session_key_t));
     268             : 
     269           0 :   if (clib_bihash_search_48_8 (&cmp->session_hash, &kvp0, &kvp0) < 0)
     270             :     {
     271           0 :       s = format (s, " LOOKUP FAIL!");
     272             :     }
     273             :   else
     274             :     {
     275           0 :       if (kvp0.value == s0 - cmp->sessions[s0->thread_index])
     276             :         {
     277           0 :           s = format (s, " OK");
     278           0 :           if (verbose > 1)
     279             :             {
     280           0 :               s = format (s, " next %d prev %d", s0->next_index,
     281             :                           s0->prev_index);
     282           0 :               s = format (s, " hits %d expires %.2f", s0->hits, s0->expires);
     283             :             }
     284             :         }
     285             :       else
     286           0 :         s = format (s, " BOGUS LOOKUP RESULT!");
     287             :     }
     288             : 
     289           0 :   return s;
     290             : }
     291             : 
     292             : static clib_error_t *
     293           0 : show_ct6_command_fn_command_fn (vlib_main_t * vm,
     294             :                                 unformat_input_t * input,
     295             :                                 vlib_cli_command_t * cmd)
     296             : {
     297           0 :   ct6_main_t *cmp = &ct6_main;
     298             :   ct6_session_t *s0;
     299           0 :   int verbose = 0;
     300           0 :   u8 *s = 0;
     301             :   int i;
     302             : 
     303           0 :   if (!cmp->feature_initialized)
     304           0 :     return clib_error_return (0, "ip6 connection tracking not enabled...");
     305             : 
     306           0 :   if (unformat (input, "verbose %d", &verbose))
     307             :     ;
     308           0 :   else if (unformat (input, "verbose"))
     309           0 :     verbose = 1;
     310             : 
     311           0 :   for (i = 0; i < vec_len (cmp->sessions); i++)
     312             :     {
     313           0 :       s = format (s, "Thread %d: %d sessions\n", i,
     314           0 :                   pool_elts (cmp->sessions[i]));
     315             : 
     316           0 :       if (verbose == 0)
     317           0 :         continue;
     318             : 
     319           0 :       s =
     320           0 :         format (s, "%U", format_ct6_session, cmp,
     321             :                 0 /* pool */ , 0 /* header */ , verbose);
     322             : 
     323             :       /* *INDENT-OFF* */
     324           0 :       pool_foreach (s0, cmp->sessions[i])
     325             :        {
     326           0 :         s = format (s, "%U", format_ct6_session, cmp, i, s0, verbose);
     327             :       }
     328             :       /* *INDENT-ON* */
     329             :     }
     330           0 :   vlib_cli_output (cmp->vlib_main, "%v", s);
     331           0 :   vec_free (s);
     332           0 :   return 0;
     333             : }
     334             : 
     335             : /* *INDENT-OFF* */
     336      254185 : VLIB_CLI_COMMAND (show_ct6_command_fn_command, static) =
     337             : {
     338             :   .path = "show ip6 connection-tracker",
     339             :   .short_help = "show ip6 connection-tracker",
     340             :   .function = show_ct6_command_fn_command_fn,
     341             : };
     342             : /* *INDENT-ON* */
     343             : 
     344             : static void
     345           0 : increment_v6_address (ip6_address_t * a)
     346             : {
     347             :   u64 v0, v1;
     348             : 
     349           0 :   v0 = clib_net_to_host_u64 (a->as_u64[0]);
     350           0 :   v1 = clib_net_to_host_u64 (a->as_u64[1]);
     351             : 
     352           0 :   v1 += 1;
     353           0 :   if (v1 == 0)
     354           0 :     v0 += 1;
     355           0 :   a->as_u64[0] = clib_net_to_host_u64 (v0);
     356           0 :   a->as_u64[1] = clib_net_to_host_u64 (v1);
     357           0 : }
     358             : 
     359             : 
     360             : static clib_error_t *
     361           0 : test_ct6_command_fn_command_fn (vlib_main_t * vm,
     362             :                                 unformat_input_t * input,
     363             :                                 vlib_cli_command_t * cmd)
     364             : {
     365           0 :   ct6_main_t *cmp = &ct6_main;
     366             :   clib_bihash_kv_48_8_t kvp0;
     367             :   ct6_session_key_t *key0;
     368             :   ct6_session_t *s0;
     369             :   u8 src[16], dst[16];
     370           0 :   u32 recycled = 0, created = 0;
     371           0 :   int i, num_sessions = 5;
     372             :   u32 midpt_index;
     373           0 :   u8 *s = 0;
     374             : 
     375           0 :   cmp->max_sessions_per_worker = 4;
     376             : 
     377           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     378             :     {
     379           0 :       if (unformat (input, "num-sessions %d", &num_sessions))
     380             :         ;
     381             :       else
     382           0 :         if (unformat
     383             :             (input, "max-sessions %d", &cmp->max_sessions_per_worker))
     384             :         ;
     385             :       else
     386           0 :         break;
     387             :     }
     388             : 
     389           0 :   ct6_feature_init (cmp);
     390             : 
     391             :   /* Set up starting src/dst addresses */
     392           0 :   memset (src, 0, sizeof (src));
     393           0 :   memset (dst, 0, sizeof (dst));
     394             : 
     395           0 :   src[0] = 0xdb;
     396           0 :   dst[0] = 0xbe;
     397             : 
     398           0 :   src[15] = 1;
     399           0 :   dst[15] = 1;
     400             : 
     401             :   /*
     402             :    * See if we know about this flow.
     403             :    * Key set up for the out2in path, the performant case
     404             :    */
     405           0 :   key0 = (ct6_session_key_t *) & kvp0;
     406           0 :   memset (&kvp0, 0, sizeof (kvp0));
     407             : 
     408           0 :   for (i = 0; i < num_sessions; i++)
     409             :     {
     410           0 :       clib_memcpy_fast (&key0->src, src, sizeof (src));
     411           0 :       clib_memcpy_fast (&key0->dst, dst, sizeof (dst));
     412           0 :       key0->as_u64[4] = 0;
     413           0 :       key0->as_u64[5] = 0;
     414           0 :       key0->sport = clib_host_to_net_u16 (1234);
     415           0 :       key0->dport = clib_host_to_net_u16 (4321);
     416           0 :       key0->proto = 17;              /* udp, fwiw */
     417             : 
     418           0 :       s0 = ct6_create_or_recycle_session
     419             :         (cmp, &kvp0, 3.0 /* now */ , 0 /* thread index */ ,
     420             :          &recycled, &created);
     421             : 
     422           0 :       s = format (s, "%U (%d, %d)", format_ct6_session, cmp,
     423             :                   0 /* thread index */ , s0, 1 /* verbose */ ,
     424             :                   recycled, created);
     425           0 :       vlib_cli_output (vm, "%v", s);
     426           0 :       vec_free (s);
     427           0 :       increment_v6_address ((ip6_address_t *) src);
     428           0 :       recycled = 0;
     429           0 :       created = 0;
     430             :     }
     431             : 
     432             :   /* *INDENT-OFF* */
     433           0 :   pool_foreach (s0, cmp->sessions[0])
     434             :    {
     435           0 :     s = format (s, "%U", format_ct6_session, cmp, 0, s0, 1 /* verbose */);
     436             :   }
     437             :   /* *INDENT-ON* */
     438             : 
     439           0 :   vlib_cli_output (vm, "\nEnd state: first index %d last index %d\n%v",
     440           0 :                    cmp->first_index[0], cmp->last_index[0], s);
     441             : 
     442           0 :   vec_free (s);
     443             : 
     444           0 :   midpt_index = cmp->max_sessions_per_worker / 3;
     445             : 
     446           0 :   s0 = pool_elt_at_index (cmp->sessions[0], midpt_index);
     447           0 :   vlib_cli_output (vm, "\nSimulate LRU hit on session %d",
     448           0 :                    s0 - cmp->sessions[0]);
     449             : 
     450           0 :   ct6_update_session_hit (cmp, s0, 234.0);
     451             : 
     452             :   /* *INDENT-OFF* */
     453           0 :   pool_foreach (s0, cmp->sessions[0])
     454             :    {
     455           0 :     s = format (s, "%U", format_ct6_session, cmp, 0, s0, 1 /* verbose */);
     456             :   }
     457             :   /* *INDENT-ON* */
     458             : 
     459           0 :   vlib_cli_output (vm, "\nEnd state: first index %d last index %d\n%v",
     460           0 :                    cmp->first_index[0], cmp->last_index[0], s);
     461             : 
     462           0 :   vec_free (s);
     463             : 
     464           0 :   return 0;
     465             : }
     466             : 
     467             : /* *INDENT-OFF* */
     468      254185 : VLIB_CLI_COMMAND (test_ct6_command_fn_command, static) =
     469             : {
     470             :   .path = "test ip6 connection-tracker",
     471             :   .short_help = "test ip6 connection-tracker",
     472             :   .function = test_ct6_command_fn_command_fn,
     473             : };
     474             : /* *INDENT-ON* */
     475             : 
     476             : static clib_error_t *
     477         575 : ct6_config (vlib_main_t * vm, unformat_input_t * input)
     478             : {
     479         575 :   ct6_main_t *cmp = &ct6_main;
     480             : 
     481         575 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     482             :     {
     483           0 :       if (unformat (input, "session-hash-buckets %u",
     484             :                     &cmp->session_hash_buckets))
     485             :         ;
     486           0 :       else if (unformat (input, "session-hash-memory %U",
     487             :                          unformat_memory_size, &cmp->session_hash_memory))
     488             :         ;
     489           0 :       else if (unformat (input, "session-timeout %f",
     490             :                          &cmp->session_timeout_interval))
     491             :         ;
     492             :       else
     493             :         {
     494           0 :           return clib_error_return (0, "unknown input '%U'",
     495             :                                     format_unformat_error, input);
     496             :         }
     497             :     }
     498         575 :   return 0;
     499             : }
     500             : 
     501        5786 : VLIB_CONFIG_FUNCTION (ct6_config, "ct6");
     502             : 
     503             : /*
     504             :  * fd.io coding-style-patch-verification: ON
     505             :  *
     506             :  * Local Variables:
     507             :  * eval: (c-set-style "gnu")
     508             :  * End:
     509             :  */

Generated by: LCOV version 1.14