LCOV - code coverage report
Current view: top level - vnet/classify - in_out_acl.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 107 168 63.7 %
Date: 2023-10-26 01:39:38 Functions: 20 23 87.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 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             : #include <vnet/ip/ip.h>
      16             : #include <vnet/classify/vnet_classify.h>
      17             : #include <vnet/classify/in_out_acl.h>
      18             : #include <vnet/l2/l2_output.h>
      19             : #include <vnet/l2/l2_input.h>
      20             : 
      21             : in_out_acl_main_t in_out_acl_main;
      22             : 
      23             : static int
      24         510 : vnet_in_out_acl_feature_enable (in_out_acl_main_t *am, u32 sw_if_index,
      25             :                                 in_out_acl_table_id_t tid, int feature_enable,
      26             :                                 int is_output)
      27             : {
      28             :   const char *arc_name, *feature_name;
      29             :   vnet_feature_config_main_t *fcm;
      30             :   u8 arc;
      31             :   int rv;
      32             : 
      33         510 :   switch (tid)
      34             :     {
      35           0 :     case IN_OUT_ACL_N_TABLES:
      36           0 :       return VNET_API_ERROR_NO_SUCH_TABLE;
      37         158 :     case IN_OUT_ACL_TABLE_L2:
      38         158 :       if (is_output)
      39           6 :         l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_ACL,
      40             :                                      feature_enable);
      41             :       else
      42         152 :         l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_ACL,
      43             :                                     feature_enable);
      44         158 :       return 0;
      45         178 :     case IN_OUT_ACL_TABLE_IP4:
      46         178 :       arc_name = is_output ? "ip4-output" : "ip4-unicast";
      47         178 :       feature_name = is_output ? "ip4-outacl" : "ip4-inacl";
      48         178 :       break;
      49         168 :     case IN_OUT_ACL_TABLE_IP6:
      50         168 :       arc_name = is_output ? "ip6-output" : "ip6-unicast";
      51         168 :       feature_name = is_output ? "ip6-outacl" : "ip6-inacl";
      52         168 :       break;
      53           4 :     case IN_OUT_ACL_TABLE_IP4_PUNT:
      54           4 :       if (sw_if_index != 0)
      55           0 :         return VNET_API_ERROR_INVALID_INTERFACE;
      56           4 :       arc_name = "ip4-punt";
      57           4 :       feature_name = "ip4-punt-acl";
      58           4 :       break;
      59           2 :     case IN_OUT_ACL_TABLE_IP6_PUNT:
      60           2 :       if (sw_if_index != 0)
      61           0 :         return VNET_API_ERROR_INVALID_INTERFACE;
      62           2 :       arc_name = "ip6-punt";
      63           2 :       feature_name = "ip6-punt-acl";
      64           2 :       break;
      65             :     }
      66             : 
      67         352 :   rv = vnet_feature_enable_disable (arc_name, feature_name, sw_if_index,
      68             :                                     feature_enable, 0, 0);
      69         352 :   if (rv)
      70           0 :     return rv;
      71             : 
      72         352 :   arc = vnet_get_feature_arc_index (arc_name);
      73         352 :   fcm = vnet_get_feature_arc_config_main (arc);
      74         352 :   am->vnet_config_main[is_output][tid] = &fcm->config_main;
      75             : 
      76         352 :   return 0;
      77             : }
      78             : 
      79             : int
      80         370 : vnet_set_in_out_acl_intfc (vlib_main_t *vm, u32 sw_if_index,
      81             :                            u32 ip4_table_index, u32 ip6_table_index,
      82             :                            u32 l2_table_index, u32 ip4_punt_table_index,
      83             :                            u32 ip6_punt_table_index, u32 is_add, u32 is_output)
      84             : {
      85         370 :   in_out_acl_main_t *am = &in_out_acl_main;
      86         370 :   vnet_classify_main_t *vcm = am->vnet_classify_main;
      87         370 :   u32 acl[IN_OUT_ACL_N_TABLES] = {
      88             :     ip4_table_index,      ip6_table_index,      l2_table_index,
      89             :     ip4_punt_table_index, ip6_punt_table_index,
      90             :   };
      91             :   u32 ti;
      92             :   int rv;
      93             : 
      94             :   /* Assume that we've validated sw_if_index in the API layer */
      95             : 
      96        2220 :   for (ti = 0; ti < IN_OUT_ACL_N_TABLES; ti++)
      97             :     {
      98        1850 :       if (acl[ti] == ~0)
      99        1340 :         continue;
     100             : 
     101         510 :       if (pool_is_free_index (vcm->tables, acl[ti]))
     102           0 :         return VNET_API_ERROR_NO_SUCH_TABLE;
     103             : 
     104         617 :       vec_validate_init_empty
     105             :         (am->classify_table_index_by_sw_if_index[is_output][ti], sw_if_index,
     106             :          ~0);
     107             : 
     108             :       /* Reject any DEL operation with wrong sw_if_index */
     109         510 :       if (!is_add &&
     110         255 :           (acl[ti] !=
     111         255 :            am->classify_table_index_by_sw_if_index[is_output][ti]
     112         255 :            [sw_if_index]))
     113             :         {
     114           0 :           clib_warning
     115             :             ("Non-existent intf_idx=%d with table_index=%d for delete",
     116             :              sw_if_index, acl[ti]);
     117           0 :           return VNET_API_ERROR_NO_SUCH_TABLE;
     118             :         }
     119             : 
     120             :       /* Return ok on ADD operaton if feature is already enabled */
     121         510 :       if (is_add &&
     122         255 :           am->classify_table_index_by_sw_if_index[is_output][ti][sw_if_index]
     123             :           != ~0)
     124           0 :         return 0;
     125             : 
     126         510 :       rv = vnet_in_out_acl_feature_enable (am, sw_if_index, ti, is_add,
     127             :                                            is_output);
     128         510 :       if (rv)
     129           0 :         return rv;
     130             : 
     131         510 :       if (is_add)
     132         255 :         am->classify_table_index_by_sw_if_index[is_output][ti][sw_if_index] =
     133         255 :           acl[ti];
     134             :       else
     135         255 :         am->classify_table_index_by_sw_if_index[is_output][ti][sw_if_index] =
     136             :           ~0;
     137             :     }
     138             : 
     139         370 :   return 0;
     140             : }
     141             : 
     142             : int
     143         210 : vnet_set_input_acl_intfc (vlib_main_t * vm, u32 sw_if_index,
     144             :                           u32 ip4_table_index,
     145             :                           u32 ip6_table_index, u32 l2_table_index, u32 is_add)
     146             : {
     147         210 :   return vnet_set_in_out_acl_intfc (
     148             :     vm, sw_if_index, ip4_table_index, ip6_table_index, l2_table_index,
     149             :     ~0 /* ip4_punt_table_index */, ~0 /* ip6_punt_table_index */, is_add,
     150             :     IN_OUT_ACL_INPUT_TABLE_GROUP);
     151             : }
     152             : 
     153             : int
     154         154 : vnet_set_output_acl_intfc (vlib_main_t * vm, u32 sw_if_index,
     155             :                            u32 ip4_table_index,
     156             :                            u32 ip6_table_index, u32 l2_table_index,
     157             :                            u32 is_add)
     158             : {
     159         154 :   return vnet_set_in_out_acl_intfc (
     160             :     vm, sw_if_index, ip4_table_index, ip6_table_index, l2_table_index,
     161             :     ~0 /* ip4_punt_table_index */, ~0 /* ip6_punt_table_index */, is_add,
     162             :     IN_OUT_ACL_OUTPUT_TABLE_GROUP);
     163             : }
     164             : 
     165             : static clib_error_t *
     166           0 : set_in_out_acl_command_fn (vlib_main_t * vm,
     167             :                            unformat_input_t * input, vlib_cli_command_t * cmd,
     168             :                            u32 is_output)
     169             : {
     170           0 :   vnet_main_t *vnm = vnet_get_main ();
     171           0 :   u32 sw_if_index = ~0;
     172           0 :   u32 ip4_table_index = ~0;
     173           0 :   u32 ip6_table_index = ~0;
     174           0 :   u32 ip4_punt_table_index = ~0;
     175           0 :   u32 ip6_punt_table_index = ~0;
     176           0 :   u32 l2_table_index = ~0;
     177           0 :   u32 is_add = 1;
     178           0 :   u32 idx_cnt = 0;
     179             :   int rv;
     180             : 
     181           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     182             :     {
     183           0 :       if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
     184             :                     vnm, &sw_if_index))
     185             :         ;
     186           0 :       else if (unformat (input, "ip4-table %d", &ip4_table_index))
     187           0 :         idx_cnt++;
     188           0 :       else if (unformat (input, "ip6-table %d", &ip6_table_index))
     189           0 :         idx_cnt++;
     190           0 :       else if (unformat (input, "ip4-punt-table %d", &ip4_punt_table_index))
     191           0 :         idx_cnt++;
     192           0 :       else if (unformat (input, "ip6-punt-table %d", &ip6_punt_table_index))
     193           0 :         idx_cnt++;
     194           0 :       else if (unformat (input, "l2-table %d", &l2_table_index))
     195           0 :         idx_cnt++;
     196           0 :       else if (unformat (input, "del"))
     197           0 :         is_add = 0;
     198             :       else
     199           0 :         break;
     200             :     }
     201             : 
     202           0 :   if (sw_if_index == ~0)
     203           0 :     return clib_error_return (0, "Interface must be specified.");
     204             : 
     205           0 :   if (!idx_cnt)
     206           0 :     return clib_error_return (0, "Table index should be specified.");
     207             : 
     208           0 :   if (idx_cnt > 1)
     209           0 :     return clib_error_return (0, "Only one table index per API is allowed.");
     210             : 
     211           0 :   rv = vnet_set_in_out_acl_intfc (
     212             :     vm, sw_if_index, ip4_table_index, ip6_table_index, l2_table_index,
     213             :     ip4_punt_table_index, ip6_punt_table_index, is_add, is_output);
     214             : 
     215           0 :   switch (rv)
     216             :     {
     217           0 :     case 0:
     218           0 :       break;
     219             : 
     220           0 :     case VNET_API_ERROR_NO_MATCHING_INTERFACE:
     221           0 :       return clib_error_return (0, "No such interface");
     222             : 
     223           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
     224           0 :       return clib_error_return (0, "No such classifier table");
     225             : 
     226           0 :     default:
     227           0 :       return clib_error_return (0, "Error: %d", rv);
     228             :     }
     229           0 :   return 0;
     230             : }
     231             : 
     232             : static clib_error_t *
     233           0 : set_input_acl_command_fn (vlib_main_t * vm,
     234             :                           unformat_input_t * input, vlib_cli_command_t * cmd)
     235             : {
     236           0 :   return set_in_out_acl_command_fn (vm, input, cmd,
     237             :                                     IN_OUT_ACL_INPUT_TABLE_GROUP);
     238             : }
     239             : 
     240             : static clib_error_t *
     241           0 : set_output_acl_command_fn (vlib_main_t * vm,
     242             :                            unformat_input_t * input, vlib_cli_command_t * cmd)
     243             : {
     244           0 :   return set_in_out_acl_command_fn (vm, input, cmd,
     245             :                                     IN_OUT_ACL_OUTPUT_TABLE_GROUP);
     246             : }
     247             : 
     248             : /*
     249             :  * Configure interface to enable/disble input/output ACL features:
     250             :  * intfc - interface name to be configured as input ACL
     251             :  * Ip4-table <index> [del] - enable/disable IP4 input ACL
     252             :  * Ip6-table <index> [del] - enable/disable IP6 input ACL
     253             :  * l2-table <index> [del] - enable/disable Layer2 input ACL
     254             :  *
     255             :  * Note: Only one table index per API call is allowed.
     256             :  *
     257             :  */
     258             : /* *INDENT-OFF* */
     259      285289 : VLIB_CLI_COMMAND (set_input_acl_command, static) = {
     260             :   .path = "set interface input acl",
     261             :   .short_help =
     262             :     "set interface input acl intfc <int> [ip4-table <index>]\n"
     263             :     "  [ip6-table <index>] [l2-table <index>] [ip4-punt-table <index>]\n"
     264             :     "  [ip6-punt-table <index> [del]",
     265             :   .function = set_input_acl_command_fn,
     266             : };
     267      285289 : VLIB_CLI_COMMAND (set_output_acl_command, static) = {
     268             :     .path = "set interface output acl",
     269             :     .short_help =
     270             :     "set interface output acl intfc <int> [ip4-table <index>]\n"
     271             :     "  [ip6-table <index>] [l2-table <index>] [del]",
     272             :     .function = set_output_acl_command_fn,
     273             : };
     274             : /* *INDENT-ON* */
     275             : 
     276             : clib_error_t *
     277         575 : in_out_acl_init (vlib_main_t * vm)
     278             : {
     279         575 :   in_out_acl_main_t *am = &in_out_acl_main;
     280             : 
     281         575 :   am->vlib_main = vm;
     282         575 :   am->vnet_main = vnet_get_main ();
     283         575 :   am->vnet_classify_main = &vnet_classify_main;
     284             : 
     285         575 :   return 0;
     286             : }
     287             : /* *INDENT-OFF* */
     288       13823 : VLIB_INIT_FUNCTION (in_out_acl_init) =
     289             : {
     290             :   .runs_after = VLIB_INITS("ip_in_out_acl_init"),
     291             : };
     292             : /* *INDENT-ON* */
     293             : 
     294             : uword
     295          64 : unformat_acl_type (unformat_input_t * input, va_list * args)
     296             : {
     297          64 :   u32 *acl_type = va_arg (*args, u32 *);
     298          64 :   u32 tid = IN_OUT_ACL_N_TABLES;
     299             : 
     300         128 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     301             :     {
     302          64 :       if (unformat (input, "ip4"))
     303          38 :         tid = IN_OUT_ACL_TABLE_IP4;
     304          26 :       else if (unformat (input, "ip6"))
     305          26 :         tid = IN_OUT_ACL_TABLE_IP6;
     306           0 :       else if (unformat (input, "l2"))
     307           0 :         tid = IN_OUT_ACL_TABLE_L2;
     308             :       else
     309           0 :         break;
     310             :     }
     311             : 
     312          64 :   *acl_type = tid;
     313          64 :   return 1;
     314             : }
     315             : 
     316             : u8 *
     317          63 : format_vnet_in_out_acl_info (u8 * s, va_list * va)
     318             : {
     319          63 :   in_out_acl_main_t *am = va_arg (*va, in_out_acl_main_t *);
     320          63 :   int sw_if_idx = va_arg (*va, int);
     321          63 :   u32 tid = va_arg (*va, u32);
     322             : 
     323          63 :   if (tid == ~0)
     324             :     {
     325          33 :       s = format (s, "%10s%20s\t\t%s", "Intfc idx", "Classify table",
     326             :                   "Interface name");
     327          33 :       return s;
     328             :     }
     329             : 
     330          30 :   s = format (s, "%10d%20d\t\t%U", sw_if_idx, tid,
     331             :               format_vnet_sw_if_index_name, am->vnet_main, sw_if_idx);
     332             : 
     333          30 :   return s;
     334             : }
     335             : 
     336             : static clib_error_t *
     337          64 : show_in_out_acl_command_fn (vlib_main_t * vm,
     338             :                             unformat_input_t * input,
     339             :                             vlib_cli_command_t * cmd, u32 is_output)
     340             : {
     341          64 :   in_out_acl_main_t *am = &in_out_acl_main;
     342          64 :   u32 type = IN_OUT_ACL_N_TABLES;
     343             :   int i;
     344             :   u32 *vec_tbl;
     345             : 
     346         128 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     347             :     {
     348          64 :       if (unformat (input, "type %U", unformat_acl_type, &type))
     349             :         ;
     350             :       else
     351           0 :         break;
     352             :     }
     353             : 
     354          64 :   if (type == IN_OUT_ACL_N_TABLES)
     355           0 :     return clib_error_return (0, is_output ? "Invalid output ACL table type."
     356             :                               : "Invalid input ACL table type.");
     357             : 
     358          64 :   vec_tbl = am->classify_table_index_by_sw_if_index[is_output][type];
     359             : 
     360          64 :   if (vec_len (vec_tbl))
     361          33 :     vlib_cli_output (vm, "%U", format_vnet_in_out_acl_info, am, ~0 /* hdr */ ,
     362             :                      ~0);
     363             :   else
     364          31 :     vlib_cli_output (vm, is_output ? "No output ACL tables configured"
     365             :                      : "No input ACL tables configured");
     366             : 
     367         130 :   for (i = 0; i < vec_len (vec_tbl); i++)
     368             :     {
     369          66 :       if (vec_elt (vec_tbl, i) == ~0)
     370          36 :         continue;
     371             : 
     372          30 :       vlib_cli_output (vm, "%U", format_vnet_in_out_acl_info,
     373          30 :                        am, i, vec_elt (vec_tbl, i));
     374             :     }
     375             : 
     376          64 :   return 0;
     377             : }
     378             : 
     379             : static clib_error_t *
     380          32 : show_inacl_command_fn (vlib_main_t * vm,
     381             :                        unformat_input_t * input, vlib_cli_command_t * cmd)
     382             : {
     383          32 :   return show_in_out_acl_command_fn (vm, input, cmd,
     384             :                                      IN_OUT_ACL_INPUT_TABLE_GROUP);
     385             : }
     386             : 
     387             : static clib_error_t *
     388          32 : show_outacl_command_fn (vlib_main_t * vm,
     389             :                         unformat_input_t * input, vlib_cli_command_t * cmd)
     390             : {
     391          32 :   return show_in_out_acl_command_fn (vm, input, cmd,
     392             :                                      IN_OUT_ACL_OUTPUT_TABLE_GROUP);
     393             : }
     394             : 
     395             : /* *INDENT-OFF* */
     396      285289 : VLIB_CLI_COMMAND (show_inacl_command, static) = {
     397             :     .path = "show inacl",
     398             :     .short_help = "show inacl type [ip4|ip6|l2]",
     399             :     .function = show_inacl_command_fn,
     400             : };
     401      285289 : VLIB_CLI_COMMAND (show_outacl_command, static) = {
     402             :     .path = "show outacl",
     403             :     .short_help = "show outacl type [ip4|ip6|l2]",
     404             :     .function = show_outacl_command_fn,
     405             : };
     406             : /* *INDENT-ON* */
     407             : 
     408             : /*
     409             :  * fd.io coding-style-patch-verification: ON
     410             :  *
     411             :  * Local Variables:
     412             :  * eval: (c-set-style "gnu")
     413             :  * End:
     414             :  */

Generated by: LCOV version 1.14