LCOV - code coverage report
Current view: top level - plugins/acl - lookup_context.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 116 159 73.0 %
Date: 2023-10-26 01:39:38 Functions: 16 21 76.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 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             : #include <plugins/acl/acl.h>
      17             : #include <plugins/acl/fa_node.h>
      18             : #include <vlib/unix/plugin.h>
      19             : #include <plugins/acl/public_inlines.h>
      20             : #include "hash_lookup.h"
      21             : #include "elog_acl_trace.h"
      22             : 
      23             : /* check if a given ACL exists */
      24             : static u8
      25        3010 : acl_plugin_acl_exists (u32 acl_index)
      26             : {
      27        3010 :   acl_main_t *am = &acl_main;
      28             : 
      29        3010 :   if (pool_is_free_index (am->acls, acl_index))
      30         425 :     return 0;
      31             : 
      32        2585 :   return 1;
      33             : }
      34             : 
      35             : 
      36        1150 : static u32 get_acl_user_id(acl_main_t *am, char *user_module_name, char *val1_label, char *val2_label)
      37             : {
      38             :     acl_lookup_context_user_t *auser;
      39             : 
      40        1725 :     pool_foreach (auser, am->acl_users)
      41             :      {
      42         575 :       if (0 == strcmp(auser->user_module_name, user_module_name)) {
      43           0 :         return (auser - am->acl_users);
      44             :       }
      45             :     }
      46             : 
      47        1150 :     pool_get(am->acl_users, auser);
      48        1150 :     auser->user_module_name = user_module_name;
      49        1150 :     auser->val1_label = val1_label;
      50        1150 :     auser->val2_label = val2_label;
      51        1150 :     return (auser - am->acl_users);
      52             : }
      53             : 
      54         316 : static int acl_user_id_valid(acl_main_t *am, u32 acl_user_id)
      55             : {
      56             : 
      57         316 :   if (pool_is_free_index (am->acl_users, acl_user_id))
      58           0 :     return 0;
      59             : 
      60         316 :   return 1;
      61             : }
      62             : 
      63         895 : static int acl_lc_index_valid(acl_main_t *am, u32 lc_index)
      64             : {
      65             : 
      66         895 :   if (pool_is_free_index (am->acl_lookup_contexts, lc_index))
      67           0 :     return 0;
      68             : 
      69         895 :   return 1;
      70             : }
      71             : 
      72             : /*
      73             :  * If you are using ACL plugin, get this unique ID first,
      74             :  * so you can identify yourself when creating the lookup contexts.
      75             :  */
      76             : 
      77        1150 : static u32 acl_plugin_register_user_module (char *user_module_name, char *val1_label, char *val2_label)
      78             : {
      79        1150 :   acl_main_t *am = &acl_main;
      80             :   /*
      81             :    * Because folks like to call this early on,
      82             :    * use the global heap, so as to avoid
      83             :    * initializing the main ACL heap before
      84             :    * they start using ACLs.
      85             :    */
      86        1150 :   u32 user_id = get_acl_user_id(am, user_module_name, val1_label, val2_label);
      87        1150 :   return user_id;
      88             : }
      89             : 
      90             : /*
      91             :  * Allocate a new lookup context index.
      92             :  * Supply the id assigned to your module during registration,
      93             :  * and two values of your choice identifying instances
      94             :  * of use within your module. They are useful for debugging.
      95             :  * If >= 0 - context id. If < 0 - error code.
      96             :  */
      97             : 
      98         316 : static int acl_plugin_get_lookup_context_index (u32 acl_user_id, u32 val1, u32 val2)
      99             : {
     100         316 :   acl_main_t *am = &acl_main;
     101             :   acl_lookup_context_t *acontext;
     102             : 
     103         316 :   if (!acl_user_id_valid(am, acl_user_id))
     104           0 :     return VNET_API_ERROR_INVALID_REGISTRATION;
     105             : 
     106             :   /*
     107             :    * The lookup context index allocation is
     108             :    * an operation done within the global heap,
     109             :    * so no heap switching necessary.
     110             :    */
     111             : 
     112         316 :   pool_get(am->acl_lookup_contexts, acontext);
     113         316 :   acontext->acl_indices = 0;
     114         316 :   acontext->context_user_id = acl_user_id;
     115         316 :   acontext->user_val1 = val1;
     116         316 :   acontext->user_val2 = val2;
     117             : 
     118         316 :   u32 new_context_id = acontext - am->acl_lookup_contexts;
     119         316 :   vec_add1(am->acl_users[acl_user_id].lookup_contexts, new_context_id);
     120             : 
     121         316 :   return new_context_id;
     122             : }
     123             : 
     124             : static void
     125        1022 : lock_acl(acl_main_t *am, u32 acl, u32 lc_index)
     126             : {
     127        1022 :   vec_validate(am->lc_index_vec_by_acl, acl);
     128        1022 :   elog_acl_cond_trace_X2(am, (am->trace_acl), "lock acl %d in lc_index %d", "i4i4", acl, lc_index);
     129        1022 :   vec_add1(am->lc_index_vec_by_acl[acl], lc_index);
     130        1022 : }
     131             : 
     132             : static void
     133         574 : lock_acl_vec(u32 lc_index, u32 *acls)
     134             : {
     135             :   int i;
     136         574 :   acl_main_t *am = &acl_main;
     137        1596 :   for(i=0; i<vec_len(acls); i++) {
     138        1022 :     lock_acl(am, acls[i], lc_index);
     139             :   }
     140         574 : }
     141             : 
     142             : static void
     143        1022 : unlock_acl(acl_main_t *am, u32 acl, u32 lc_index)
     144             : {
     145        1022 :   vec_validate(am->lc_index_vec_by_acl, acl);
     146        1022 :   elog_acl_cond_trace_X2(am, (am->trace_acl), "unlock acl %d in lc_index %d", "i4i4", acl, lc_index);
     147        1152 :   u32 index = vec_search(am->lc_index_vec_by_acl[acl], lc_index);
     148        1022 :   if (index != ~0)
     149        1022 :     vec_del1(am->lc_index_vec_by_acl[acl], index);
     150             :   else
     151           0 :     clib_warning("BUG: can not unlock acl %d lc_index %d", acl, lc_index);
     152        1022 : }
     153             : 
     154             : static void
     155         890 : unlock_acl_vec(u32 lc_index, u32 *acls)
     156             : {
     157             :   int i;
     158         890 :   acl_main_t *am = &acl_main;
     159        1912 :   for(i=0; i<vec_len(acls); i++)
     160        1022 :   unlock_acl(am, acls[i], lc_index);
     161         890 : }
     162             : 
     163             : 
     164             : static void
     165         574 : apply_acl_vec(u32 lc_index, u32 *acls)
     166             : {
     167             :   int i;
     168         574 :   acl_main_t *am = &acl_main;
     169             : 
     170        1596 :   for(i=0; i<vec_len(acls); i++)
     171        1022 :     hash_acl_apply(am, lc_index, acls[i], i);
     172         574 : }
     173             : 
     174             : 
     175             : static void
     176         890 : unapply_acl_vec(u32 lc_index, u32 *acls)
     177             : {
     178             :   int i;
     179         890 :   acl_main_t *am = &acl_main;
     180         890 :   if (vec_len(acls) == 0)
     181         316 :     return;
     182        1596 :   for(i=vec_len(acls); i > 0; i--)
     183        1022 :     hash_acl_unapply(am, lc_index, acls[i-1]);
     184             : }
     185             : 
     186             : /*
     187             :  * Release the lookup context index and destroy
     188             :  * any associated data structures.
     189             :  */
     190         316 : static void acl_plugin_put_lookup_context_index (u32 lc_index)
     191             : {
     192         316 :   acl_main_t *am = &acl_main;
     193             : 
     194         316 :   elog_acl_cond_trace_X1(am, (am->trace_acl), "LOOKUP-CONTEXT: put-context lc_index %d", "i4", lc_index);
     195         316 :   if (!acl_lc_index_valid(am, lc_index)) {
     196           0 :     clib_warning("BUG: lc_index %d is not valid", lc_index);
     197           0 :     return;
     198             :   }
     199             : 
     200         316 :   acl_lookup_context_t *acontext = pool_elt_at_index(am->acl_lookup_contexts, lc_index);
     201             : 
     202         783 :   u32 index = vec_search(am->acl_users[acontext->context_user_id].lookup_contexts, lc_index);
     203         316 :   ASSERT(index != ~0);
     204             : 
     205         316 :   vec_del1(am->acl_users[acontext->context_user_id].lookup_contexts, index);
     206         316 :   unapply_acl_vec(lc_index, acontext->acl_indices);
     207         316 :   unlock_acl_vec(lc_index, acontext->acl_indices);
     208         316 :   vec_free(acontext->acl_indices);
     209         316 :   pool_put(am->acl_lookup_contexts, acontext);
     210             : }
     211             : 
     212             : /*
     213             :  * Prepare the sequential vector of ACL#s to lookup within a given context.
     214             :  * Any existing list will be overwritten. acl_list is a vector.
     215             :  */
     216         579 : static int acl_plugin_set_acl_vec_for_context (u32 lc_index, u32 *acl_list)
     217             : {
     218         579 :   int rv = 0;
     219         579 :   uword *seen_acl_bitmap = 0;
     220         579 :   u32 *pacln = 0;
     221         579 :   acl_main_t *am = &acl_main;
     222             :   acl_lookup_context_t *acontext;
     223         579 :   if (am->trace_acl) {
     224             :     u32 i;
     225           0 :     elog_acl_cond_trace_X1(am, (1), "LOOKUP-CONTEXT: set-acl-list lc_index %d", "i4", lc_index);
     226           0 :     for(i=0; i<vec_len(acl_list); i++) {
     227           0 :       elog_acl_cond_trace_X2(am, (1), "   acl-list[%d]: %d", "i4i4", i, acl_list[i]);
     228             :     }
     229             :   }  
     230         579 :   if (!acl_lc_index_valid(am, lc_index)) {
     231           0 :     clib_warning("BUG: lc_index %d is not valid", lc_index);
     232           0 :     return -1;
     233             :   }
     234        1606 :   vec_foreach (pacln, acl_list)
     235             :   {
     236        1032 :     if (pool_is_free_index (am->acls, *pacln))
     237             :       {
     238             :         /* ACL is not defined. Can not apply */
     239           0 :         clib_warning ("ERROR: ACL %d not defined", *pacln);
     240           0 :         rv = VNET_API_ERROR_NO_SUCH_ENTRY;
     241           0 :         goto done;
     242             :       }
     243        1032 :     if (clib_bitmap_get (seen_acl_bitmap, *pacln))
     244             :       {
     245             :         /* ACL being applied twice within the list. error. */
     246           5 :         clib_warning ("ERROR: ACL %d being applied twice", *pacln);
     247           5 :         rv = VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
     248           5 :         goto done;
     249             :       }
     250        1027 :     seen_acl_bitmap = clib_bitmap_set (seen_acl_bitmap, *pacln, 1);
     251             :   }
     252             : 
     253         574 :   acontext = pool_elt_at_index(am->acl_lookup_contexts, lc_index);
     254         574 :   u32 *old_acl_vector = acontext->acl_indices;
     255         574 :   acontext->acl_indices = vec_dup(acl_list);
     256             : 
     257         574 :   unapply_acl_vec(lc_index, old_acl_vector);
     258         574 :   unlock_acl_vec(lc_index, old_acl_vector);
     259         574 :   lock_acl_vec(lc_index, acontext->acl_indices);
     260         574 :   apply_acl_vec(lc_index, acontext->acl_indices);
     261             : 
     262         574 :   vec_free(old_acl_vector);
     263             : 
     264         579 : done:
     265         579 :   clib_bitmap_free (seen_acl_bitmap);
     266         579 :   return rv;
     267             : }
     268             : 
     269             : 
     270        3010 : void acl_plugin_lookup_context_notify_acl_change(u32 acl_num)
     271             : {
     272        3010 :   acl_main_t *am = &acl_main;
     273        3010 :   if (acl_plugin_acl_exists(acl_num)) {
     274        2585 :     if (hash_acl_exists(am, acl_num)) {
     275             :         /* this is a modification, clean up the older entries */
     276        2160 :         hash_acl_delete(am, acl_num);
     277             :     }
     278        2585 :     hash_acl_add(am, acl_num);
     279             :   } else {
     280             :     /* this is a deletion notification */
     281         425 :     hash_acl_delete(am, acl_num);
     282             :   }
     283        3010 : }
     284             : 
     285             : 
     286             : /* Fill the 5-tuple from the packet */
     287             : 
     288           0 : static void acl_plugin_fill_5tuple (u32 lc_index, vlib_buffer_t * b0, int is_ip6, int is_input,
     289             :                                 int is_l2_path, fa_5tuple_opaque_t * p5tuple_pkt)
     290             : {
     291           0 :   acl_plugin_fill_5tuple_inline(&acl_main, lc_index, b0, is_ip6, is_input, is_l2_path, p5tuple_pkt);
     292           0 : }
     293             : 
     294           0 : static int acl_plugin_match_5tuple (u32 lc_index,
     295             :                                            fa_5tuple_opaque_t * pkt_5tuple,
     296             :                                            int is_ip6, u8 * r_action,
     297             :                                            u32 * r_acl_pos_p,
     298             :                                            u32 * r_acl_match_p,
     299             :                                            u32 * r_rule_match_p,
     300             :                                            u32 * trace_bitmap)
     301             : {
     302           0 :   return acl_plugin_match_5tuple_inline (&acl_main, lc_index, pkt_5tuple, is_ip6, r_action, r_acl_pos_p, r_acl_match_p, r_rule_match_p, trace_bitmap);
     303             : }
     304             : 
     305             : 
     306             : void
     307           0 : acl_plugin_show_lookup_user (u32 user_index)
     308             : {
     309           0 :     acl_main_t *am = &acl_main;
     310           0 :     vlib_main_t *vm = am->vlib_main;
     311             :     acl_lookup_context_user_t *auser;
     312             : 
     313           0 :     pool_foreach (auser, am->acl_users)
     314             :      {
     315           0 :       u32 curr_user_index = (auser - am->acl_users);
     316           0 :       if (user_index == ~0 || (curr_user_index == user_index)) {
     317           0 :         vlib_cli_output (vm, "index %d:%s:%s:%s", curr_user_index, auser->user_module_name, auser->val1_label, auser->val2_label);
     318             :       }
     319             :     }
     320           0 : }
     321             : 
     322             : 
     323             : void
     324           0 : acl_plugin_show_lookup_context (u32 lc_index)
     325             : {
     326           0 :   acl_main_t *am = &acl_main;
     327           0 :   vlib_main_t *vm = am->vlib_main;
     328             :   acl_lookup_context_t *acontext;
     329             :   // clib_warning("LOOKUP-CONTEXT: lc_index %d acl_list [ %U ]", lc_index, format_vec32, acl_list, "%d");
     330           0 :   if (!am->acl_lookup_contexts)
     331             :   {
     332           0 :     vlib_cli_output(vm, "ACL lookup contexts are not initialized");
     333           0 :     return;
     334             :   }
     335             : 
     336           0 :   pool_foreach (acontext, am->acl_lookup_contexts)
     337             :    {
     338           0 :     u32 curr_lc_index = (acontext - am->acl_lookup_contexts);
     339           0 :     if ((lc_index == ~0) || (curr_lc_index == lc_index)) {
     340           0 :       if (acl_user_id_valid(am, acontext->context_user_id)) {
     341           0 :         acl_lookup_context_user_t *auser = pool_elt_at_index(am->acl_users, acontext->context_user_id);
     342           0 :         vlib_cli_output (vm, "index %d:%s %s: %d %s: %d, acl_indices: %U",
     343             :                        curr_lc_index, auser->user_module_name, auser->val1_label,
     344             :                        acontext->user_val1, auser->val2_label, acontext->user_val2,
     345             :                        format_vec32, acontext->acl_indices, "%d");
     346             :       } else {
     347           0 :         vlib_cli_output (vm, "index %d: user_id: %d user_val1: %d user_val2: %d, acl_indices: %U",
     348             :                        curr_lc_index, acontext->context_user_id,
     349             :                        acontext->user_val1, acontext->user_val2,
     350             :                        format_vec32, acontext->acl_indices, "%d");
     351             :       }
     352             :     }
     353             :   }
     354             : }
     355             : 
     356             : void *
     357           0 : acl_plugin_get_p_acl_main(void)
     358             : {
     359           0 :   return &acl_main;
     360             : }
     361             : 
     362             : __clib_export clib_error_t *
     363        1150 : acl_plugin_methods_vtable_init(acl_plugin_methods_t *m)
     364             : {
     365        1150 :   m->p_acl_main = &acl_main;
     366             : #define _(name) m->name = acl_plugin_ ## name;
     367        1150 :   foreach_acl_plugin_exported_method_name
     368             : #undef _
     369        1150 :   return 0;
     370             : }

Generated by: LCOV version 1.14