LCOV - code coverage report
Current view: top level - plugins/acl - acl.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 1158 1796 64.5 %
Date: 2023-07-05 22:20:52 Functions: 109 133 82.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 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 <stddef.h>
      17             : 
      18             : #include <vnet/vnet.h>
      19             : #include <vnet/plugin/plugin.h>
      20             : #include <acl/acl.h>
      21             : 
      22             : #include <vnet/l2/l2_classify.h>
      23             : #include <vnet/l2/l2_in_out_feat_arc.h>
      24             : #include <vnet/classify/in_out_acl.h>
      25             : #include <vpp/app/version.h>
      26             : 
      27             : #include <vnet/ethernet/ethernet_types_api.h>
      28             : #include <vnet/ip/format.h>
      29             : #include <vnet/ethernet/ethernet.h>
      30             : #include <vnet/ip/ip_types_api.h>
      31             : 
      32             : #include <vlibapi/api.h>
      33             : #include <vlibmemory/api.h>
      34             : 
      35             : /* define message IDs */
      36             : #include <acl/acl.api_enum.h>
      37             : #include <acl/acl.api_types.h>
      38             : 
      39             : 
      40             : #include "fa_node.h"
      41             : #include "public_inlines.h"
      42             : 
      43             : acl_main_t acl_main;
      44             : 
      45             : #define REPLY_MSG_ID_BASE am->msg_id_base
      46             : #include <vlibapi/api_helper_macros.h>
      47             : 
      48             : /*
      49             :  * The code for the bihash, used by the session management.
      50             :  */
      51             : #include <vppinfra/bihash_40_8.h>
      52             : #include <vppinfra/bihash_template.h>
      53             : #include <vppinfra/bihash_template.c>
      54             : 
      55             : /* *INDENT-OFF* */
      56             : VLIB_PLUGIN_REGISTER () = {
      57             :     .version = VPP_BUILD_VER,
      58             :     .description = "Access Control Lists (ACL)",
      59             : };
      60             : /* *INDENT-ON* */
      61             : 
      62             : /* methods exported from ACL-as-a-service */
      63             : static acl_plugin_methods_t acl_plugin;
      64             : 
      65             : /* Format vec16. */
      66             : u8 *
      67           0 : format_vec16 (u8 * s, va_list * va)
      68             : {
      69           0 :   u16 *v = va_arg (*va, u16 *);
      70           0 :   char *fmt = va_arg (*va, char *);
      71             :   uword i;
      72           0 :   for (i = 0; i < vec_len (v); i++)
      73             :     {
      74           0 :       if (i > 0)
      75           0 :         s = format (s, ", ");
      76           0 :       s = format (s, fmt, v[i]);
      77             :     }
      78           0 :   return s;
      79             : }
      80             : 
      81             : static void
      82           1 : vl_api_acl_plugin_get_version_t_handler (vl_api_acl_plugin_get_version_t * mp)
      83             : {
      84           1 :   acl_main_t *am = &acl_main;
      85             :   vl_api_acl_plugin_get_version_reply_t *rmp;
      86           1 :   int msg_size = sizeof (*rmp);
      87             :   vl_api_registration_t *reg;
      88             : 
      89           1 :   reg = vl_api_client_index_to_registration (mp->client_index);
      90           1 :   if (!reg)
      91           0 :     return;
      92             : 
      93           1 :   rmp = vl_msg_api_alloc (msg_size);
      94           1 :   clib_memset (rmp, 0, msg_size);
      95           1 :   rmp->_vl_msg_id =
      96           1 :     ntohs (VL_API_ACL_PLUGIN_GET_VERSION_REPLY + am->msg_id_base);
      97           1 :   rmp->context = mp->context;
      98           1 :   rmp->major = htonl (ACL_PLUGIN_VERSION_MAJOR);
      99           1 :   rmp->minor = htonl (ACL_PLUGIN_VERSION_MINOR);
     100             : 
     101           1 :   vl_api_send_msg (reg, (u8 *) rmp);
     102             : }
     103             : 
     104             : static void
     105           0 : vl_api_acl_plugin_control_ping_t_handler (vl_api_acl_plugin_control_ping_t *
     106             :                                           mp)
     107             : {
     108             :   vl_api_acl_plugin_control_ping_reply_t *rmp;
     109           0 :   acl_main_t *am = &acl_main;
     110           0 :   int rv = 0;
     111             : 
     112             :   /* *INDENT-OFF* */
     113           0 :   REPLY_MACRO2 (VL_API_ACL_PLUGIN_CONTROL_PING_REPLY,
     114             :   ({
     115             :     rmp->vpe_pid = ntohl (getpid ());
     116             :   }));
     117             :   /* *INDENT-ON* */
     118             : }
     119             : 
     120             : static void
     121           0 : print_clib_warning_and_reset (vlib_main_t * vm, u8 * out0)
     122             : {
     123           0 :   clib_warning ("%v", out0);
     124           0 :   vec_reset_length (out0);
     125           0 : }
     126             : 
     127             : static void
     128        1172 : print_cli_and_reset (vlib_main_t * vm, u8 * out0)
     129             : {
     130        1172 :   vlib_cli_output (vm, "%v", out0);
     131        1172 :   vec_reset_length (out0);
     132        1172 : }
     133             : 
     134             : typedef void (*acl_vector_print_func_t) (vlib_main_t * vm, u8 * out0);
     135             : 
     136             : static inline u8 *
     137        1009 : format_acl_action (u8 * s, u8 action)
     138             : {
     139        1009 :   switch (action)
     140             :     {
     141         232 :     case 0:
     142         232 :       s = format (s, "deny");
     143         232 :       break;
     144         697 :     case 1:
     145         697 :       s = format (s, "permit");
     146         697 :       break;
     147          80 :     case 2:
     148          80 :       s = format (s, "permit+reflect");
     149          80 :       break;
     150           0 :     default:
     151           0 :       s = format (s, "action %d", action);
     152             :     }
     153        1009 :   return (s);
     154             : }
     155             : 
     156             : static void
     157         163 : acl_print_acl_x (acl_vector_print_func_t vpr, vlib_main_t * vm,
     158             :                  acl_main_t * am, int acl_index)
     159             : {
     160             :   acl_rule_t *r;
     161         163 :   acl_rule_t *acl_rules = am->acls[acl_index].rules;
     162         163 :   u8 *out0 = format (0, "acl-index %u count %u tag {%s}\n", acl_index,
     163         163 :                      vec_len (acl_rules), am->acls[acl_index].tag);
     164             :   int j;
     165         163 :   vpr (vm, out0);
     166        1172 :   for (j = 0; j < vec_len (acl_rules); j++)
     167             :     {
     168        1009 :       r = &acl_rules[j];
     169        1009 :       out0 = format (out0, "  %9d: %s ", j, r->is_ipv6 ? "ipv6" : "ipv4");
     170        1009 :       out0 = format_acl_action (out0, r->is_permit);
     171        1009 :       out0 = format (out0, " src %U/%d", format_ip46_address, &r->src,
     172        1009 :                      r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
     173        1009 :                      r->src_prefixlen);
     174             :       out0 =
     175        1009 :         format (out0, " dst %U/%d", format_ip46_address, &r->dst,
     176        1009 :                 r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4, r->dst_prefixlen);
     177        1009 :       out0 = format (out0, " proto %d", r->proto);
     178        1009 :       out0 = format (out0, " sport %d", r->src_port_or_type_first);
     179        1009 :       if (r->src_port_or_type_first != r->src_port_or_type_last)
     180             :         {
     181         229 :           out0 = format (out0, "-%d", r->src_port_or_type_last);
     182             :         }
     183        1009 :       out0 = format (out0, " dport %d", r->dst_port_or_code_first);
     184        1009 :       if (r->dst_port_or_code_first != r->dst_port_or_code_last)
     185             :         {
     186          85 :           out0 = format (out0, "-%d", r->dst_port_or_code_last);
     187             :         }
     188        1009 :       if (r->tcp_flags_mask || r->tcp_flags_value)
     189             :         {
     190             :           out0 =
     191           0 :             format (out0, " tcpflags %d mask %d", r->tcp_flags_value,
     192           0 :                     r->tcp_flags_mask);
     193             :         }
     194        1009 :       out0 = format (out0, "\n");
     195        1009 :       vpr (vm, out0);
     196             :     }
     197         163 : }
     198             : 
     199             : static void
     200           0 :   vl_api_acl_plugin_get_conn_table_max_entries_t_handler
     201             :   (vl_api_acl_plugin_get_conn_table_max_entries_t * mp)
     202             : {
     203           0 :   acl_main_t *am = &acl_main;
     204             :   vl_api_acl_plugin_get_conn_table_max_entries_reply_t *rmp;
     205           0 :   int msg_size = sizeof (*rmp);
     206             :   vl_api_registration_t *rp;
     207             : 
     208           0 :   rp = vl_api_client_index_to_registration (mp->client_index);
     209           0 :   if (rp == 0)
     210           0 :     return;
     211             : 
     212           0 :   rmp = vl_msg_api_alloc (msg_size);
     213           0 :   memset (rmp, 0, msg_size);
     214           0 :   rmp->_vl_msg_id =
     215           0 :     ntohs (VL_API_ACL_PLUGIN_GET_CONN_TABLE_MAX_ENTRIES_REPLY +
     216           0 :            am->msg_id_base);
     217           0 :   rmp->context = mp->context;
     218           0 :   rmp->conn_table_max_entries =
     219           0 :     clib_net_to_host_u64 (am->fa_conn_table_max_entries);
     220             : 
     221           0 :   vl_api_send_msg (rp, (u8 *) rmp);
     222             : }
     223             : 
     224             : static void
     225         163 : acl_print_acl (vlib_main_t * vm, acl_main_t * am, int acl_index)
     226             : {
     227         163 :   acl_print_acl_x (print_cli_and_reset, vm, am, acl_index);
     228         163 : }
     229             : 
     230             : static void
     231           0 : warning_acl_print_acl (vlib_main_t * vm, acl_main_t * am, int acl_index)
     232             : {
     233           0 :   acl_print_acl_x (print_clib_warning_and_reset, vm, am, acl_index);
     234           0 : }
     235             : 
     236             : static void
     237           0 : increment_policy_epoch (acl_main_t * am, u32 sw_if_index, int is_input)
     238             : {
     239             : 
     240           0 :   u32 **ppolicy_epoch_by_swi =
     241           0 :     is_input ? &am->input_policy_epoch_by_sw_if_index :
     242             :     &am->output_policy_epoch_by_sw_if_index;
     243           0 :   vec_validate (*ppolicy_epoch_by_swi, sw_if_index);
     244             : 
     245           0 :   u32 *p_epoch = vec_elt_at_index ((*ppolicy_epoch_by_swi), sw_if_index);
     246           0 :   *p_epoch =
     247           0 :     ((1 + *p_epoch) & FA_POLICY_EPOCH_MASK) +
     248           0 :     (is_input * FA_POLICY_EPOCH_IS_INPUT);
     249           0 : }
     250             : 
     251             : static void
     252           0 : try_increment_acl_policy_epoch (acl_main_t * am, u32 acl_num, int is_input)
     253             : {
     254           0 :   u32 ***p_swi_vec_by_acl = is_input ? &am->input_sw_if_index_vec_by_acl
     255           0 :     : &am->output_sw_if_index_vec_by_acl;
     256           0 :   if (acl_num < vec_len (*p_swi_vec_by_acl))
     257             :     {
     258             :       u32 *p_swi;
     259           0 :       vec_foreach (p_swi, (*p_swi_vec_by_acl)[acl_num])
     260             :       {
     261           0 :         increment_policy_epoch (am, *p_swi, is_input);
     262             :       }
     263             : 
     264             :     }
     265           0 : }
     266             : 
     267             : static void
     268           0 : policy_notify_acl_change (acl_main_t * am, u32 acl_num)
     269             : {
     270           0 :   try_increment_acl_policy_epoch (am, acl_num, 0);
     271           0 :   try_increment_acl_policy_epoch (am, acl_num, 1);
     272           0 : }
     273             : 
     274             : 
     275             : static void
     276        2585 : validate_and_reset_acl_counters (acl_main_t * am, u32 acl_index)
     277             : {
     278             :   int i;
     279             :   /* counters are set as vectors [acl#] pointing to vectors of [acl rule] */
     280        2585 :   acl_plugin_counter_lock (am);
     281             : 
     282        2585 :   int old_len = vec_len (am->combined_acl_counters);
     283             : 
     284        2585 :   vec_validate (am->combined_acl_counters, acl_index);
     285             : 
     286        2605 :   for (i = old_len; i < vec_len (am->combined_acl_counters); i++)
     287             :     {
     288          20 :       am->combined_acl_counters[i].name = 0;
     289             :       /* filled in once only */
     290          40 :       am->combined_acl_counters[i].stat_segment_name = (void *)
     291          20 :         format (0, "/acl/%d/matches%c", i, 0);
     292          20 :       i32 rule_count = vec_len (am->acls[i].rules);
     293             :       /* Validate one extra so we always have at least one counter for an ACL */
     294          20 :       vlib_validate_combined_counter (&am->combined_acl_counters[i],
     295             :                                       rule_count);
     296          20 :       vlib_clear_combined_counters (&am->combined_acl_counters[i]);
     297             :     }
     298             : 
     299             :   /* (re)validate for the actual ACL that is getting added/updated */
     300        2585 :   i32 rule_count = vec_len (am->acls[acl_index].rules);
     301             :   /* Validate one extra so we always have at least one counter for an ACL */
     302        2585 :   vlib_validate_combined_counter (&am->combined_acl_counters[acl_index],
     303             :                                   rule_count);
     304        2585 :   vlib_clear_combined_counters (&am->combined_acl_counters[acl_index]);
     305        2585 :   acl_plugin_counter_unlock (am);
     306        2585 : }
     307             : 
     308             : static int
     309       33050 : acl_api_invalid_prefix (const vl_api_prefix_t * prefix)
     310             : {
     311             :   ip_prefix_t ip_prefix;
     312       33050 :   int valid_af =
     313       33050 :     prefix->address.af == ADDRESS_IP4 || prefix->address.af == ADDRESS_IP6;
     314       33050 :   return (!valid_af) || ip_prefix_decode2 (prefix, &ip_prefix);
     315             : }
     316             : 
     317             : static int
     318        2586 : acl_add_list (u32 count, vl_api_acl_rule_t rules[],
     319             :               u32 * acl_list_index, u8 * tag)
     320             : {
     321        2586 :   acl_main_t *am = &acl_main;
     322             :   acl_list_t *a;
     323             :   acl_rule_t *r;
     324        2586 :   acl_rule_t *acl_new_rules = 0;
     325             :   size_t tag_len;
     326             :   int i;
     327             : 
     328        2586 :   tag_len = clib_strnlen ((const char *) tag, sizeof (a->tag));
     329        2586 :   if (tag_len == sizeof (a->tag))
     330           0 :     return VNET_API_ERROR_INVALID_VALUE;
     331             : 
     332        2586 :   if (am->trace_acl > 255)
     333           0 :     clib_warning ("API dbg: acl_add_list index %d tag %s", *acl_list_index,
     334             :                   tag);
     335             : 
     336             :   /* check if what they request is consistent */
     337       19111 :   for (i = 0; i < count; i++)
     338             :     {
     339       16525 :       if (acl_api_invalid_prefix (&rules[i].src_prefix))
     340           0 :         return VNET_API_ERROR_INVALID_SRC_ADDRESS;
     341       16525 :       if (acl_api_invalid_prefix (&rules[i].dst_prefix))
     342           0 :         return VNET_API_ERROR_INVALID_DST_ADDRESS;
     343       16525 :       if (rules[i].src_prefix.address.af != rules[i].dst_prefix.address.af)
     344           0 :         return VNET_API_ERROR_INVALID_SRC_ADDRESS;
     345       16525 :       if (ntohs (rules[i].srcport_or_icmptype_first) >
     346       16525 :           ntohs (rules[i].srcport_or_icmptype_last))
     347           0 :         return VNET_API_ERROR_INVALID_VALUE_2;
     348       16525 :       if (ntohs (rules[i].dstport_or_icmpcode_first) >
     349       16525 :           ntohs (rules[i].dstport_or_icmpcode_last))
     350           0 :         return VNET_API_ERROR_INVALID_VALUE_2;
     351             :     }
     352             : 
     353        2586 :   if (*acl_list_index != ~0)
     354             :     {
     355             :       /* They supplied some number, let's see if this ACL exists */
     356        2161 :       if (pool_is_free_index (am->acls, *acl_list_index))
     357             :         {
     358             :           /* tried to replace a non-existent ACL, no point doing anything */
     359           1 :           clib_warning
     360             :             ("acl-plugin-error: Trying to replace nonexistent ACL %d (tag %s)",
     361             :              *acl_list_index, tag);
     362           1 :           return VNET_API_ERROR_NO_SUCH_ENTRY;
     363             :         }
     364             :     }
     365        2585 :   if (0 == count)
     366             :     {
     367           0 :       clib_warning
     368             :         ("acl-plugin-warning: supplied no rules for ACL %d (tag %s)",
     369             :          *acl_list_index, tag);
     370             :     }
     371             : 
     372             :   /* Create and populate the rules */
     373        2585 :   if (count > 0)
     374        2585 :     vec_validate (acl_new_rules, count - 1);
     375             : 
     376       19109 :   for (i = 0; i < count; i++)
     377             :     {
     378       16524 :       r = vec_elt_at_index (acl_new_rules, i);
     379       16524 :       clib_memset (r, 0, sizeof (*r));
     380       16524 :       r->is_permit = rules[i].is_permit;
     381       16524 :       r->is_ipv6 = rules[i].src_prefix.address.af;
     382       16524 :       ip_address_decode (&rules[i].src_prefix.address, &r->src);
     383       16524 :       ip_address_decode (&rules[i].dst_prefix.address, &r->dst);
     384       16524 :       r->src_prefixlen = rules[i].src_prefix.len;
     385       16524 :       r->dst_prefixlen = rules[i].dst_prefix.len;
     386       16524 :       r->proto = rules[i].proto;
     387       16524 :       r->src_port_or_type_first = ntohs (rules[i].srcport_or_icmptype_first);
     388       16524 :       r->src_port_or_type_last = ntohs (rules[i].srcport_or_icmptype_last);
     389       16524 :       r->dst_port_or_code_first = ntohs (rules[i].dstport_or_icmpcode_first);
     390       16524 :       r->dst_port_or_code_last = ntohs (rules[i].dstport_or_icmpcode_last);
     391       16524 :       r->tcp_flags_value = rules[i].tcp_flags_value;
     392       16524 :       r->tcp_flags_mask = rules[i].tcp_flags_mask;
     393             :     }
     394             : 
     395        2585 :   if (~0 == *acl_list_index)
     396             :     {
     397             :       /* Get ACL index */
     398         425 :       pool_get_aligned (am->acls, a, CLIB_CACHE_LINE_BYTES);
     399         425 :       clib_memset (a, 0, sizeof (*a));
     400             :       /* Will return the newly allocated ACL index */
     401         425 :       *acl_list_index = a - am->acls;
     402             :     }
     403             :   else
     404             :     {
     405        2160 :       a = am->acls + *acl_list_index;
     406             :       /* Get rid of the old rules */
     407        2160 :       if (a->rules)
     408        2160 :         vec_free (a->rules);
     409             :     }
     410        2585 :   a->rules = acl_new_rules;
     411        2585 :   memcpy (a->tag, tag, tag_len + 1);
     412        2585 :   if (am->trace_acl > 255)
     413           0 :     warning_acl_print_acl (am->vlib_main, am, *acl_list_index);
     414        2585 :   if (am->reclassify_sessions)
     415             :     {
     416             :       /* a change in an ACLs if they are applied may mean a new policy epoch */
     417           0 :       policy_notify_acl_change (am, *acl_list_index);
     418             :     }
     419        2585 :   validate_and_reset_acl_counters (am, *acl_list_index);
     420        2585 :   acl_plugin_lookup_context_notify_acl_change (*acl_list_index);
     421        2585 :   return 0;
     422             : }
     423             : 
     424             : static int
     425        1278 : acl_is_used_by (u32 acl_index, u32 ** foo_index_vec_by_acl)
     426             : {
     427        1278 :   if (acl_index < vec_len (foo_index_vec_by_acl))
     428             :     {
     429        1251 :       if (vec_len (vec_elt (foo_index_vec_by_acl, acl_index)) > 0)
     430             :         {
     431             :           /* ACL is applied somewhere. */
     432           2 :           return 1;
     433             :         }
     434             :     }
     435        1276 :   return 0;
     436             : }
     437             : 
     438             : static int
     439         427 : acl_del_list (u32 acl_list_index)
     440             : {
     441         427 :   acl_main_t *am = &acl_main;
     442             :   acl_list_t *a;
     443         427 :   if (pool_is_free_index (am->acls, acl_list_index))
     444             :     {
     445           0 :       return VNET_API_ERROR_NO_SUCH_ENTRY;
     446             :     }
     447         427 :   if (acl_is_used_by (acl_list_index, am->input_sw_if_index_vec_by_acl))
     448           1 :     return VNET_API_ERROR_ACL_IN_USE_INBOUND;
     449         426 :   if (acl_is_used_by (acl_list_index, am->output_sw_if_index_vec_by_acl))
     450           1 :     return VNET_API_ERROR_ACL_IN_USE_OUTBOUND;
     451             :   /* lookup contexts cover other cases, not just inbound/outbound, so check that */
     452         425 :   if (acl_is_used_by (acl_list_index, am->lc_index_vec_by_acl))
     453           0 :     return VNET_API_ERROR_ACL_IN_USE_BY_LOOKUP_CONTEXT;
     454             : 
     455             :   /* now we can delete the ACL itself */
     456         425 :   a = pool_elt_at_index (am->acls, acl_list_index);
     457         425 :   if (a->rules)
     458         425 :     vec_free (a->rules);
     459         425 :   pool_put (am->acls, a);
     460             :   /* acl_list_index is now free, notify the lookup contexts */
     461         425 :   acl_plugin_lookup_context_notify_acl_change (acl_list_index);
     462         425 :   return 0;
     463             : }
     464             : 
     465             : static int
     466        1209 : count_skip (u8 * p, u32 size)
     467             : {
     468        1209 :   u64 *p64 = (u64 *) p;
     469             :   /* Be tolerant to null pointer */
     470        1209 :   if (0 == p)
     471         408 :     return 0;
     472             : 
     473        1044 :   while ((0ULL == *p64) && ((u8 *) p64 - p) < size)
     474             :     {
     475         243 :       p64++;
     476             :     }
     477         801 :   return (p64 - (u64 *) p) / 2;
     478             : }
     479             : 
     480             : static int
     481        1209 : acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask,
     482             :                                   u32 mask_len, u32 next_table_index,
     483             :                                   u32 miss_next_index, u32 * table_index,
     484             :                                   int is_add)
     485             : {
     486        1209 :   u32 nbuckets = 32;
     487        1209 :   u32 memory_size = 2 << 22;
     488        1209 :   u32 skip = count_skip (mask, mask_len);
     489        1209 :   u32 match = (mask_len / 16) - skip;
     490        1209 :   u8 *skip_mask_ptr = mask + 16 * skip;
     491        1209 :   u32 current_data_flag = 0;
     492        1209 :   int current_data_offset = 0;
     493             : 
     494        1209 :   if (0 == match)
     495           0 :     match = 1;
     496             : 
     497        1209 :   int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
     498             :                                          memory_size, skip, match,
     499             :                                          next_table_index, miss_next_index,
     500             :                                          table_index, current_data_flag,
     501             :                                          current_data_offset, is_add,
     502             :                                          1 /* delete_chain */ );
     503        1209 :   return ret;
     504             : }
     505             : 
     506             : static int
     507        1420 : intf_has_etype_whitelist (acl_main_t * am, u32 sw_if_index, int is_input)
     508             : {
     509        1420 :   u16 **v = is_input
     510             :     ? am->input_etype_whitelist_by_sw_if_index
     511        1420 :     : am->output_etype_whitelist_by_sw_if_index;
     512        1420 :   u16 *whitelist = (vec_len (v) > sw_if_index) ? vec_elt (v, sw_if_index) : 0;
     513        1420 :   return vec_len (whitelist) > 0;
     514             : }
     515             : 
     516             : static void
     517         573 : acl_clear_sessions (acl_main_t * am, u32 sw_if_index)
     518             : {
     519         573 :   vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
     520             :                              ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX,
     521             :                              sw_if_index);
     522         573 : }
     523             : 
     524             : 
     525             : static int
     526        4775 : acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index,
     527             :                                  int enable_disable)
     528             : {
     529        4775 :   int rv = 0;
     530             : 
     531             :   /* Utterly wrong? */
     532        4775 :   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
     533             :                           sw_if_index))
     534           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     535             : 
     536        4775 :   if (clib_bitmap_get (am->in_acl_on_sw_if_index, sw_if_index) ==
     537             :       enable_disable)
     538        4371 :     return 0;
     539             : 
     540         404 :   acl_fa_enable_disable (sw_if_index, 1, enable_disable);
     541             : 
     542         404 :   rv = vnet_l2_feature_enable_disable ("l2-input-ip4", "acl-plugin-in-ip4-l2",
     543             :                                        sw_if_index, enable_disable, 0, 0);
     544         404 :   if (rv)
     545           0 :     clib_error ("Could not enable on input");
     546         404 :   rv = vnet_l2_feature_enable_disable ("l2-input-ip6", "acl-plugin-in-ip6-l2",
     547             :                                        sw_if_index, enable_disable, 0, 0);
     548         404 :   if (rv)
     549           0 :     clib_error ("Could not enable on input");
     550             : 
     551         404 :   if (intf_has_etype_whitelist (am, sw_if_index, 1))
     552          12 :     vnet_l2_feature_enable_disable ("l2-input-nonip",
     553             :                                     "acl-plugin-in-nonip-l2", sw_if_index,
     554             :                                     enable_disable, 0, 0);
     555         404 :   am->in_acl_on_sw_if_index =
     556         404 :     clib_bitmap_set (am->in_acl_on_sw_if_index, sw_if_index, enable_disable);
     557             : 
     558         404 :   return rv;
     559             : }
     560             : 
     561             : static int
     562        4751 : acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index,
     563             :                                   int enable_disable)
     564             : {
     565        4751 :   int rv = 0;
     566             : 
     567             :   /* Utterly wrong? */
     568        4751 :   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
     569             :                           sw_if_index))
     570           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     571             : 
     572        4751 :   if (clib_bitmap_get (am->out_acl_on_sw_if_index, sw_if_index) ==
     573             :       enable_disable)
     574        4509 :     return 0;
     575             : 
     576         242 :   acl_fa_enable_disable (sw_if_index, 0, enable_disable);
     577             : 
     578             :   rv =
     579         242 :     vnet_l2_feature_enable_disable ("l2-output-ip4", "acl-plugin-out-ip4-l2",
     580             :                                     sw_if_index, enable_disable, 0, 0);
     581         242 :   if (rv)
     582           0 :     clib_error ("Could not enable on output");
     583             :   rv =
     584         242 :     vnet_l2_feature_enable_disable ("l2-output-ip6", "acl-plugin-out-ip6-l2",
     585             :                                     sw_if_index, enable_disable, 0, 0);
     586         242 :   if (rv)
     587           0 :     clib_error ("Could not enable on output");
     588         242 :   if (intf_has_etype_whitelist (am, sw_if_index, 0))
     589           0 :     vnet_l2_feature_enable_disable ("l2-output-nonip",
     590             :                                     "acl-plugin-out-nonip-l2", sw_if_index,
     591             :                                     enable_disable, 0, 0);
     592         242 :   am->out_acl_on_sw_if_index =
     593         242 :     clib_bitmap_set (am->out_acl_on_sw_if_index, sw_if_index, enable_disable);
     594             : 
     595         242 :   return rv;
     596             : }
     597             : 
     598             : static int
     599           6 : acl_stats_intf_counters_enable_disable (acl_main_t * am, int enable_disable)
     600             : {
     601           6 :   int rv = 0;
     602             : 
     603           6 :   am->interface_acl_counters_enabled = enable_disable;
     604             : 
     605           6 :   return rv;
     606             : }
     607             : 
     608             : static int
     609        9502 : acl_interface_inout_enable_disable (acl_main_t * am, u32 sw_if_index,
     610             :                                     int is_input, int enable_disable)
     611             : {
     612        9502 :   if (is_input)
     613        4751 :     return acl_interface_in_enable_disable (am, sw_if_index, enable_disable);
     614             :   else
     615        4751 :     return acl_interface_out_enable_disable (am, sw_if_index, enable_disable);
     616             : }
     617             : 
     618             : static int
     619        2381 : acl_is_not_defined (acl_main_t * am, u32 acl_list_index)
     620             : {
     621        2381 :   return (pool_is_free_index (am->acls, acl_list_index));
     622             : }
     623             : 
     624             : static int
     625        9502 : acl_interface_set_inout_acl_list (acl_main_t * am, u32 sw_if_index,
     626             :                                   u8 is_input, u32 * vec_acl_list_index,
     627             :                                   int *may_clear_sessions)
     628             : {
     629             :   u32 *pacln;
     630        9502 :   uword *seen_acl_bitmap = 0;
     631        9502 :   uword *old_seen_acl_bitmap = 0;
     632        9502 :   uword *change_acl_bitmap = 0;
     633             :   int acln;
     634        9502 :   int rv = 0;
     635             : 
     636             : 
     637        9502 :   if (am->trace_acl > 255)
     638           0 :     clib_warning
     639             :       ("API dbg: acl_interface_set_inout_acl_list: sw_if_index %d is_input %d acl_vec: [%U]",
     640             :        sw_if_index, is_input, format_vec32, vec_acl_list_index, "%d");
     641             : 
     642       10518 :   vec_foreach (pacln, vec_acl_list_index)
     643             :   {
     644        1016 :     if (acl_is_not_defined (am, *pacln))
     645             :       {
     646             :         /* ACL is not defined. Can not apply */
     647           0 :         clib_warning ("ERROR: ACL %d not defined", *pacln);
     648           0 :         rv = VNET_API_ERROR_NO_SUCH_ENTRY;
     649           0 :         goto done;
     650             :       }
     651        1016 :     if (clib_bitmap_get (seen_acl_bitmap, *pacln))
     652             :       {
     653             :         /* ACL being applied twice within the list. error. */
     654           0 :         clib_warning ("ERROR: ACL %d being applied twice", *pacln);
     655           0 :         rv = VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
     656           0 :         goto done;
     657             :       }
     658        1016 :     seen_acl_bitmap = clib_bitmap_set (seen_acl_bitmap, *pacln, 1);
     659             :   }
     660             : 
     661             : 
     662        9502 :   u32 **pinout_lc_index_by_sw_if_index =
     663        9502 :     is_input ? &am->input_lc_index_by_sw_if_index : &am->
     664             :     output_lc_index_by_sw_if_index;
     665             : 
     666        9502 :   u32 ***pinout_acl_vec_by_sw_if_index =
     667        9502 :     is_input ? &am->input_acl_vec_by_sw_if_index : &am->
     668             :     output_acl_vec_by_sw_if_index;
     669             : 
     670        9502 :   u32 ***pinout_sw_if_index_vec_by_acl =
     671        9502 :     is_input ? &am->input_sw_if_index_vec_by_acl : &am->
     672             :     output_sw_if_index_vec_by_acl;
     673             : 
     674        9502 :   vec_validate ((*pinout_acl_vec_by_sw_if_index), sw_if_index);
     675             : 
     676        9502 :   clib_bitmap_validate (old_seen_acl_bitmap, 1);
     677             : 
     678       10518 :   vec_foreach (pacln, (*pinout_acl_vec_by_sw_if_index)[sw_if_index])
     679             :   {
     680        1016 :     old_seen_acl_bitmap = clib_bitmap_set (old_seen_acl_bitmap, *pacln, 1);
     681             :   }
     682        9502 :   change_acl_bitmap =
     683        9502 :     clib_bitmap_dup_xor (old_seen_acl_bitmap, seen_acl_bitmap);
     684             : 
     685        9502 :   if (am->trace_acl > 255)
     686           0 :     clib_warning ("bitmaps: old seen %U new seen %U changed %U",
     687             :                   format_bitmap_hex, old_seen_acl_bitmap, format_bitmap_hex,
     688             :                   seen_acl_bitmap, format_bitmap_hex, change_acl_bitmap);
     689             : 
     690             : /* *INDENT-OFF* */
     691       11020 :   clib_bitmap_foreach (acln, change_acl_bitmap)  {
     692        1518 :     if (clib_bitmap_get(old_seen_acl_bitmap, acln)) {
     693             :       /* ACL is being removed. */
     694         759 :       if (acln < vec_len((*pinout_sw_if_index_vec_by_acl))) {
     695         856 :         int index = vec_search((*pinout_sw_if_index_vec_by_acl)[acln], sw_if_index);
     696         759 :         vec_del1((*pinout_sw_if_index_vec_by_acl)[acln], index);
     697             :       }
     698             :     } else {
     699             :       /* ACL is being added. */
     700         759 :       vec_validate((*pinout_sw_if_index_vec_by_acl), acln);
     701         759 :       vec_add1((*pinout_sw_if_index_vec_by_acl)[acln], sw_if_index);
     702             :     }
     703             :   }
     704             : /* *INDENT-ON* */
     705             : 
     706        9502 :   vec_free ((*pinout_acl_vec_by_sw_if_index)[sw_if_index]);
     707       19004 :   (*pinout_acl_vec_by_sw_if_index)[sw_if_index] =
     708        9502 :     vec_dup (vec_acl_list_index);
     709             : 
     710        9502 :   if (am->reclassify_sessions)
     711             :     {
     712             :       /* re-applying ACLs means a new policy epoch */
     713           0 :       increment_policy_epoch (am, sw_if_index, is_input);
     714             :     }
     715             :   else
     716             :     {
     717             :       /* if no commonalities between the ACL# - then we should definitely clear the sessions */
     718        9502 :       if (may_clear_sessions && *may_clear_sessions
     719        9132 :           && !clib_bitmap_is_zero (change_acl_bitmap))
     720             :         {
     721         573 :           acl_clear_sessions (am, sw_if_index);
     722         573 :           *may_clear_sessions = 0;
     723             :         }
     724             :     }
     725             : 
     726             :   /*
     727             :    * prepare or delete the lookup context if necessary, and if context exists, set ACL list
     728             :    */
     729       11900 :   vec_validate_init_empty ((*pinout_lc_index_by_sw_if_index), sw_if_index,
     730             :                            ~0);
     731        9502 :   if (vec_len (vec_acl_list_index) > 0)
     732         568 :     {
     733         568 :       u32 lc_index = (*pinout_lc_index_by_sw_if_index)[sw_if_index];
     734         568 :       if (~0 == lc_index)
     735             :         {
     736         311 :           lc_index =
     737         311 :             acl_plugin.get_lookup_context_index (am->interface_acl_user_id,
     738             :                                                  sw_if_index, is_input);
     739         311 :           (*pinout_lc_index_by_sw_if_index)[sw_if_index] = lc_index;
     740             :         }
     741         568 :       acl_plugin.set_acl_vec_for_context (lc_index, vec_acl_list_index);
     742             :     }
     743             :   else
     744             :     {
     745        8934 :       if (~0 != (*pinout_lc_index_by_sw_if_index)[sw_if_index])
     746             :         {
     747         311 :           acl_plugin.
     748         311 :             put_lookup_context_index ((*pinout_lc_index_by_sw_if_index)
     749         311 :                                       [sw_if_index]);
     750         311 :           (*pinout_lc_index_by_sw_if_index)[sw_if_index] = ~0;
     751             :         }
     752             :     }
     753             :   /* ensure ACL processing is enabled/disabled as needed */
     754       10070 :   acl_interface_inout_enable_disable (am, sw_if_index, is_input,
     755         568 :                                       vec_len (vec_acl_list_index) > 0);
     756             : 
     757        9502 : done:
     758        9502 :   clib_bitmap_free (change_acl_bitmap);
     759        9502 :   clib_bitmap_free (seen_acl_bitmap);
     760        9502 :   clib_bitmap_free (old_seen_acl_bitmap);
     761        9502 :   return rv;
     762             : }
     763             : 
     764             : static void
     765        8358 : acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input,
     766             :                                 int *may_clear_sessions)
     767             : {
     768        8358 :   acl_main_t *am = &acl_main;
     769        8358 :   acl_interface_set_inout_acl_list (am, sw_if_index, is_input, 0,
     770             :                                     may_clear_sessions);
     771        8358 : }
     772             : 
     773             : static int
     774           0 : acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
     775             :                                  u32 acl_list_index)
     776             : {
     777             : 
     778           0 :   acl_main_t *am = &acl_main;
     779           0 :   u32 *acl_vec = 0;
     780           0 :   int may_clear_sessions = 1;
     781             : 
     782           0 :   int error_already_applied = is_input ? VNET_API_ERROR_ACL_IN_USE_INBOUND
     783           0 :     : VNET_API_ERROR_ACL_IN_USE_OUTBOUND;
     784             : 
     785           0 :   u32 ***pinout_acl_vec_by_sw_if_index =
     786           0 :     is_input ? &am->input_acl_vec_by_sw_if_index : &am->
     787             :     output_acl_vec_by_sw_if_index;
     788           0 :   int rv = 0;
     789           0 :   if (is_add)
     790             :     {
     791           0 :       vec_validate ((*pinout_acl_vec_by_sw_if_index), sw_if_index);
     792           0 :       u32 index = vec_search ((*pinout_acl_vec_by_sw_if_index)[sw_if_index],
     793             :                               acl_list_index);
     794             : 
     795           0 :       if (~0 != index)
     796             :         {
     797           0 :           rv = error_already_applied;
     798           0 :           goto done;
     799             :         }
     800             : 
     801           0 :       acl_vec = vec_dup ((*pinout_acl_vec_by_sw_if_index)[sw_if_index]);
     802           0 :       vec_add1 (acl_vec, acl_list_index);
     803             :     }
     804             :   else
     805             :     {
     806           0 :       if (sw_if_index >= vec_len (*pinout_acl_vec_by_sw_if_index))
     807             :         {
     808           0 :           rv = VNET_API_ERROR_NO_SUCH_ENTRY;
     809           0 :           goto done;
     810             :         }
     811             : 
     812           0 :       u32 index = vec_search ((*pinout_acl_vec_by_sw_if_index)[sw_if_index],
     813             :                               acl_list_index);
     814             : 
     815           0 :       if (~0 == index)
     816             :         {
     817           0 :           rv = VNET_API_ERROR_NO_SUCH_ENTRY;
     818           0 :           goto done;
     819             :         }
     820             : 
     821           0 :       acl_vec = vec_dup ((*pinout_acl_vec_by_sw_if_index)[sw_if_index]);
     822           0 :       vec_del1 (acl_vec, index);
     823             :     }
     824             : 
     825           0 :   rv = acl_interface_set_inout_acl_list (am, sw_if_index, is_input, acl_vec,
     826             :                                          &may_clear_sessions);
     827           0 : done:
     828           0 :   vec_free (acl_vec);
     829           0 :   return rv;
     830             : }
     831             : 
     832             : static int
     833          12 : acl_set_etype_whitelists (acl_main_t * am, u32 sw_if_index, u16 * vec_in,
     834             :                           u16 * vec_out)
     835             : {
     836          12 :   vec_validate (am->input_etype_whitelist_by_sw_if_index, sw_if_index);
     837          12 :   vec_validate (am->output_etype_whitelist_by_sw_if_index, sw_if_index);
     838             : 
     839          12 :   vec_free (am->input_etype_whitelist_by_sw_if_index[sw_if_index]);
     840          12 :   vec_free (am->output_etype_whitelist_by_sw_if_index[sw_if_index]);
     841             : 
     842          12 :   am->input_etype_whitelist_by_sw_if_index[sw_if_index] = vec_in;
     843          12 :   am->output_etype_whitelist_by_sw_if_index[sw_if_index] = vec_out;
     844             : 
     845             :   /*
     846             :    * if there are already inbound/outbound ACLs applied, toggle the
     847             :    * enable/disable - this will recreate the necessary tables.
     848             :    */
     849             : 
     850          12 :   if (vec_len (am->input_acl_vec_by_sw_if_index) > sw_if_index)
     851             :     {
     852          12 :       if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0)
     853             :         {
     854          12 :           acl_interface_in_enable_disable (am, sw_if_index, 0);
     855          12 :           acl_interface_in_enable_disable (am, sw_if_index, 1);
     856             :         }
     857             :     }
     858          12 :   if (vec_len (am->output_acl_vec_by_sw_if_index) > sw_if_index)
     859             :     {
     860          12 :       if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0)
     861             :         {
     862           0 :           acl_interface_out_enable_disable (am, sw_if_index, 0);
     863           0 :           acl_interface_out_enable_disable (am, sw_if_index, 1);
     864             :         }
     865             :     }
     866          12 :   return 0;
     867             : }
     868             : 
     869             : 
     870             : typedef struct
     871             : {
     872             :   u8 is_ipv6;
     873             :   u8 has_egress;
     874             :   u8 mac_mask[6];
     875             :   u8 prefix_len;
     876             :   u32 count;
     877             :   u32 table_index;
     878             :   u32 arp_table_index;
     879             :   u32 dot1q_table_index;
     880             :   u32 dot1ad_table_index;
     881             :   u32 arp_dot1q_table_index;
     882             :   u32 arp_dot1ad_table_index;
     883             :   /* egress tables */
     884             :   u32 out_table_index;
     885             :   u32 out_arp_table_index;
     886             :   u32 out_dot1q_table_index;
     887             :   u32 out_dot1ad_table_index;
     888             :   u32 out_arp_dot1q_table_index;
     889             :   u32 out_arp_dot1ad_table_index;
     890             : } macip_match_type_t;
     891             : 
     892             : static u32
     893       23884 : macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
     894             :                        u8 is_ipv6)
     895             : {
     896             :   u32 i;
     897       23884 :   if (mv)
     898             :     {
     899       23914 :       for (i = 0; i < vec_len (mv); i++)
     900             :         {
     901       23872 :           if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
     902       23738 :               && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
     903             :             {
     904       23706 :               return i;
     905             :             }
     906             :         }
     907             :     }
     908         178 :   return ~0;
     909             : }
     910             : 
     911             : 
     912             : /* Get metric used to sort match types.
     913             :    The more specific and the more often seen - the bigger the metric */
     914             : static int
     915          84 : match_type_metric (macip_match_type_t * m)
     916             : {
     917          84 :   unsigned int mac_bits_set = 0;
     918             :   unsigned int mac_byte;
     919             :   int i;
     920         588 :   for (i = 0; i < 6; i++)
     921             :     {
     922         504 :       mac_byte = m->mac_mask[i];
     923        1752 :       for (; mac_byte; mac_byte >>= 1)
     924        1248 :         mac_bits_set += mac_byte & 1;
     925             :     }
     926             :   /*
     927             :    * Attempt to place the more specific and the more used rules on top.
     928             :    * There are obvious caveat corner cases to this, but they do not
     929             :    * seem to be sensible in real world (e.g. specific IPv4 with wildcard MAC
     930             :    * going with a wildcard IPv4 with a specific MAC).
     931             :    */
     932          84 :   return m->prefix_len + mac_bits_set + m->is_ipv6 + 10 * m->count;
     933             : }
     934             : 
     935             : static int
     936          42 : match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
     937             : {
     938             :   /* Ascending sort based on the metric values */
     939          42 :   return match_type_metric (m1) - match_type_metric (m2);
     940             : }
     941             : 
     942             : /* Get the offset of L3 source within ethernet packet */
     943             : static int
     944       36360 : get_l3_src_offset (int is6)
     945             : {
     946       36360 :   if (is6)
     947       18183 :     return (sizeof (ethernet_header_t) +
     948             :             offsetof (ip6_header_t, src_address));
     949             :   else
     950       18177 :     return (sizeof (ethernet_header_t) +
     951             :             offsetof (ip4_header_t, src_address));
     952             : }
     953             : 
     954             : static int
     955           0 : get_l3_dst_offset (int is6)
     956             : {
     957           0 :   if (is6)
     958           0 :     return (sizeof (ethernet_header_t) +
     959             :             offsetof (ip6_header_t, dst_address));
     960             :   else
     961           0 :     return (sizeof (ethernet_header_t) +
     962             :             offsetof (ip4_header_t, dst_address));
     963             : }
     964             : 
     965             : /*
     966             :  * return if the is_permit value also requires to create the egress tables
     967             :  * For backwards compatibility, we keep the is_permit = 1 to only
     968             :  * create the ingress tables, and the new value of 3 will also
     969             :  * create the egress tables based on destination.
     970             :  */
     971             : static int
     972       23884 : macip_permit_also_egress (u8 is_permit)
     973             : {
     974       23884 :   return (is_permit == 3);
     975             : }
     976             : 
     977             : static int
     978         136 : macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
     979             : {
     980         136 :   macip_match_type_t *mvec = NULL;
     981             :   macip_match_type_t *mt;
     982         136 :   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
     983             :   int i;
     984             :   u32 match_type_index;
     985             :   u32 last_table;
     986             :   u32 out_last_table;
     987             :   u8 mask[5 * 16];
     988         136 :   vnet_classify_main_t *cm = &vnet_classify_main;
     989             : 
     990             :   /* Count the number of different types of rules */
     991       12078 :   for (i = 0; i < a->count; i++)
     992             :     {
     993       11942 :       if (~0 ==
     994             :           (match_type_index =
     995       11942 :            macip_find_match_type (mvec, a->rules[i].src_mac_mask,
     996       11942 :                                   a->rules[i].src_prefixlen,
     997       11942 :                                   a->rules[i].is_ipv6)))
     998             :         {
     999         178 :           match_type_index = vec_len (mvec);
    1000         178 :           vec_validate (mvec, match_type_index);
    1001         178 :           memcpy (mvec[match_type_index].mac_mask,
    1002         178 :                   a->rules[i].src_mac_mask, 6);
    1003         178 :           mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
    1004         178 :           mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
    1005         178 :           mvec[match_type_index].has_egress = 0;
    1006         178 :           mvec[match_type_index].table_index = ~0;
    1007         178 :           mvec[match_type_index].arp_table_index = ~0;
    1008         178 :           mvec[match_type_index].dot1q_table_index = ~0;
    1009         178 :           mvec[match_type_index].dot1ad_table_index = ~0;
    1010         178 :           mvec[match_type_index].arp_dot1q_table_index = ~0;
    1011         178 :           mvec[match_type_index].arp_dot1ad_table_index = ~0;
    1012         178 :           mvec[match_type_index].out_table_index = ~0;
    1013         178 :           mvec[match_type_index].out_arp_table_index = ~0;
    1014         178 :           mvec[match_type_index].out_dot1q_table_index = ~0;
    1015         178 :           mvec[match_type_index].out_dot1ad_table_index = ~0;
    1016         178 :           mvec[match_type_index].out_arp_dot1q_table_index = ~0;
    1017         178 :           mvec[match_type_index].out_arp_dot1ad_table_index = ~0;
    1018             :         }
    1019       11942 :       mvec[match_type_index].count++;
    1020       11942 :       mvec[match_type_index].has_egress |=
    1021       11942 :         macip_permit_also_egress (a->rules[i].is_permit);
    1022             :     }
    1023             :   /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
    1024         136 :   vec_sort_with_function (mvec, match_type_compare);
    1025             :   /* Create the classifier tables */
    1026         136 :   last_table = ~0;
    1027         136 :   out_last_table = ~0;
    1028             :   /* First add ARP tables */
    1029         314 :   vec_foreach (mt, mvec)
    1030             :   {
    1031             :     int mask_len;
    1032         178 :     int is6 = mt->is_ipv6;
    1033             :     int tags;
    1034             :     u32 *last_tag_table;
    1035             :     u32 *out_last_tag_table;
    1036             :     u32 l3_offset;
    1037             : 
    1038         178 :     if (!is6)
    1039             :       {
    1040             :         /*
    1041             :            0                   1                   2                   3
    1042             :            0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    1043             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1044             :            |                      Destination Address                      |
    1045             :            +                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1046             :            |                               |                               |
    1047             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
    1048             :            |                         Source Address                        |
    1049             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1050             :            |           EtherType           |         Hardware Type         |
    1051             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1052             :            |         Protocol Type         |  Hw addr len  | Proto addr len|
    1053             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1054             :            |             Opcode            |                               |
    1055             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
    1056             :            |                    Sender Hardware Address                    |
    1057             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1058             :            |                    Sender Protocol Address                    |
    1059             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1060             :            |                    Target Hardware Address                    |
    1061             :            +                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1062             :            |                               |     TargetProtocolAddress     |
    1063             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1064             :            |                               |
    1065             :            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    1066             :          */
    1067         356 :         for (tags = 2; tags >= 0; tags--)
    1068             :           {
    1069         267 :             clib_memset (mask, 0, sizeof (mask));
    1070             :             /* source MAC address */
    1071         267 :             memcpy (&mask[6], mt->mac_mask, 6);
    1072             : 
    1073         267 :             switch (tags)
    1074             :               {
    1075          89 :               case 0:
    1076             :               default:
    1077          89 :                 clib_memset (&mask[12], 0xff, 2);   /* ethernet protocol */
    1078          89 :                 l3_offset = 14;
    1079          89 :                 last_tag_table = &mt->arp_table_index;
    1080          89 :                 break;
    1081          89 :               case 1:
    1082          89 :                 clib_memset (&mask[12], 0xff, 2);   /* VLAN tag1 */
    1083          89 :                 clib_memset (&mask[16], 0xff, 2);   /* ethernet protocol */
    1084          89 :                 l3_offset = 18;
    1085          89 :                 last_tag_table = &mt->arp_dot1q_table_index;
    1086          89 :                 break;
    1087          89 :               case 2:
    1088          89 :                 clib_memset (&mask[12], 0xff, 2);   /* VLAN tag1 */
    1089          89 :                 clib_memset (&mask[16], 0xff, 2);   /* VLAN tag2 */
    1090          89 :                 clib_memset (&mask[20], 0xff, 2);   /* ethernet protocol */
    1091          89 :                 l3_offset = 22;
    1092          89 :                 last_tag_table = &mt->arp_dot1ad_table_index;
    1093          89 :                 break;
    1094             :               }
    1095             : 
    1096             :             /* sender hardware address within ARP */
    1097         267 :             memcpy (&mask[l3_offset + 8], mt->mac_mask, 6);
    1098             :             /* sender protocol address within ARP */
    1099         924 :             for (i = 0; i < (mt->prefix_len / 8); i++)
    1100         657 :               mask[l3_offset + 14 + i] = 0xff;
    1101         267 :             if (mt->prefix_len % 8)
    1102           0 :               mask[l3_offset + 14 + (mt->prefix_len / 8)] =
    1103           0 :                 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
    1104             : 
    1105         267 :             mask_len = ((l3_offset + 14 + ((mt->prefix_len + 7) / 8) +
    1106             :                          (sizeof (u32x4) -
    1107         267 :                           1)) / sizeof (u32x4)) * sizeof (u32x4);
    1108         267 :             acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
    1109             :                                               (~0 == last_table) ? 0 : ~0,
    1110             :                                               last_tag_table, 1);
    1111         267 :             last_table = *last_tag_table;
    1112         267 :             if (mt->has_egress)
    1113             :               {
    1114             :                 /* egress ARP table */
    1115           0 :                 clib_memset (mask, 0, sizeof (mask));
    1116             : 
    1117           0 :                 switch (tags)
    1118             :                   {
    1119           0 :                   case 0:
    1120             :                   default:
    1121           0 :                     clib_memset (&mask[12], 0xff, 2);       /* ethernet protocol */
    1122           0 :                     l3_offset = 14;
    1123           0 :                     out_last_tag_table = &mt->out_arp_table_index;
    1124           0 :                     break;
    1125           0 :                   case 1:
    1126           0 :                     clib_memset (&mask[12], 0xff, 2);       /* VLAN tag1 */
    1127           0 :                     clib_memset (&mask[16], 0xff, 2);       /* ethernet protocol */
    1128           0 :                     l3_offset = 18;
    1129           0 :                     out_last_tag_table = &mt->out_arp_dot1q_table_index;
    1130           0 :                     break;
    1131           0 :                   case 2:
    1132           0 :                     clib_memset (&mask[12], 0xff, 2);       /* VLAN tag1 */
    1133           0 :                     clib_memset (&mask[16], 0xff, 2);       /* VLAN tag2 */
    1134           0 :                     clib_memset (&mask[20], 0xff, 2);       /* ethernet protocol */
    1135           0 :                     l3_offset = 22;
    1136           0 :                     out_last_tag_table = &mt->out_arp_dot1ad_table_index;
    1137           0 :                     break;
    1138             :                   }
    1139             : 
    1140             :                 /* AYXX: FIXME here - can we tighten the ARP-related table more ? */
    1141             :                 /* mask captures just the destination and the ethertype */
    1142           0 :                 mask_len = ((l3_offset +
    1143             :                              (sizeof (u32x4) -
    1144           0 :                               1)) / sizeof (u32x4)) * sizeof (u32x4);
    1145           0 :                 acl_classify_add_del_table_small (cm, mask, mask_len,
    1146             :                                                   out_last_table,
    1147             :                                                   (~0 ==
    1148             :                                                    out_last_table) ? 0 : ~0,
    1149             :                                                   out_last_tag_table, 1);
    1150           0 :                 out_last_table = *out_last_tag_table;
    1151             :               }
    1152             :           }
    1153             :       }
    1154             :   }
    1155             :   /* Now add IP[46] tables */
    1156         314 :   vec_foreach (mt, mvec)
    1157             :   {
    1158             :     int mask_len;
    1159         178 :     int is6 = mt->is_ipv6;
    1160             :     int l3_src_offs;
    1161             :     int l3_dst_offs;
    1162             :     int tags;
    1163             :     u32 *last_tag_table;
    1164             :     u32 *out_last_tag_table;
    1165             : 
    1166             :     /*
    1167             :      * create chained tables for VLAN (no-tags, dot1q and dot1ad) packets
    1168             :      */
    1169         712 :     for (tags = 2; tags >= 0; tags--)
    1170             :       {
    1171         534 :         clib_memset (mask, 0, sizeof (mask));
    1172         534 :         memcpy (&mask[6], mt->mac_mask, 6);
    1173         534 :         l3_src_offs = tags * 4 + get_l3_src_offset (is6);
    1174         534 :         switch (tags)
    1175             :           {
    1176         178 :           case 0:
    1177             :           default:
    1178         178 :             clib_memset (&mask[12], 0xff, 2);       /* ethernet protocol */
    1179         178 :             last_tag_table = &mt->table_index;
    1180         178 :             break;
    1181         178 :           case 1:
    1182         178 :             clib_memset (&mask[12], 0xff, 2);       /* VLAN tag1 */
    1183         178 :             clib_memset (&mask[16], 0xff, 2);       /* ethernet protocol */
    1184         178 :             last_tag_table = &mt->dot1q_table_index;
    1185         178 :             break;
    1186         178 :           case 2:
    1187         178 :             clib_memset (&mask[12], 0xff, 2);       /* VLAN tag1 */
    1188         178 :             clib_memset (&mask[16], 0xff, 2);       /* VLAN tag2 */
    1189         178 :             clib_memset (&mask[20], 0xff, 2);       /* ethernet protocol */
    1190         178 :             last_tag_table = &mt->dot1ad_table_index;
    1191         178 :             break;
    1192             :           }
    1193        3759 :         for (i = 0; i < (mt->prefix_len / 8); i++)
    1194             :           {
    1195        3225 :             mask[l3_src_offs + i] = 0xff;
    1196             :           }
    1197         534 :         if (mt->prefix_len % 8)
    1198             :           {
    1199           0 :             mask[l3_src_offs + (mt->prefix_len / 8)] =
    1200           0 :               0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
    1201             :           }
    1202             :         /*
    1203             :          * Round-up the number of bytes needed to store the prefix,
    1204             :          * and round up the number of vectors too
    1205             :          */
    1206         534 :         mask_len = ((l3_src_offs + ((mt->prefix_len + 7) / 8) +
    1207         534 :                      (sizeof (u32x4) - 1)) / sizeof (u32x4)) * sizeof (u32x4);
    1208         534 :         acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
    1209             :                                           (~0 == last_table) ? 0 : ~0,
    1210             :                                           last_tag_table, 1);
    1211         534 :         last_table = *last_tag_table;
    1212             :       }
    1213         178 :     if (mt->has_egress)
    1214             :       {
    1215           0 :         for (tags = 2; tags >= 0; tags--)
    1216             :           {
    1217           0 :             clib_memset (mask, 0, sizeof (mask));
    1218             :             /* MAC destination */
    1219           0 :             memcpy (&mask[0], mt->mac_mask, 6);
    1220           0 :             l3_dst_offs = tags * 4 + get_l3_dst_offset (is6);
    1221           0 :             switch (tags)
    1222             :               {
    1223           0 :               case 0:
    1224             :               default:
    1225           0 :                 clib_memset (&mask[12], 0xff, 2);   /* ethernet protocol */
    1226           0 :                 out_last_tag_table = &mt->out_table_index;
    1227           0 :                 break;
    1228           0 :               case 1:
    1229           0 :                 clib_memset (&mask[12], 0xff, 2);   /* VLAN tag1 */
    1230           0 :                 clib_memset (&mask[16], 0xff, 2);   /* ethernet protocol */
    1231           0 :                 out_last_tag_table = &mt->out_dot1q_table_index;
    1232           0 :                 break;
    1233           0 :               case 2:
    1234           0 :                 clib_memset (&mask[12], 0xff, 2);   /* VLAN tag1 */
    1235           0 :                 clib_memset (&mask[16], 0xff, 2);   /* VLAN tag2 */
    1236           0 :                 clib_memset (&mask[20], 0xff, 2);   /* ethernet protocol */
    1237           0 :                 out_last_tag_table = &mt->out_dot1ad_table_index;
    1238           0 :                 break;
    1239             :               }
    1240           0 :             for (i = 0; i < (mt->prefix_len / 8); i++)
    1241             :               {
    1242           0 :                 mask[l3_dst_offs + i] = 0xff;
    1243             :               }
    1244           0 :             if (mt->prefix_len % 8)
    1245             :               {
    1246           0 :                 mask[l3_dst_offs + (mt->prefix_len / 8)] =
    1247           0 :                   0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
    1248             :               }
    1249             :             /*
    1250             :              * Round-up the number of bytes needed to store the prefix,
    1251             :              * and round up the number of vectors too
    1252             :              */
    1253           0 :             mask_len = ((l3_dst_offs + ((mt->prefix_len + 7) / 8) +
    1254             :                          (sizeof (u32x4) -
    1255           0 :                           1)) / sizeof (u32x4)) * sizeof (u32x4);
    1256           0 :             acl_classify_add_del_table_small (cm, mask, mask_len,
    1257             :                                               out_last_table,
    1258             :                                               (~0 == out_last_table) ? 0 : ~0,
    1259             :                                               out_last_tag_table, 1);
    1260           0 :             out_last_table = *out_last_tag_table;
    1261             :           }
    1262             :       }
    1263             :   }
    1264         136 :   a->ip4_table_index = last_table;
    1265         136 :   a->ip6_table_index = last_table;
    1266         136 :   a->l2_table_index = last_table;
    1267             : 
    1268         136 :   a->out_ip4_table_index = out_last_table;
    1269         136 :   a->out_ip6_table_index = out_last_table;
    1270         136 :   a->out_l2_table_index = out_last_table;
    1271             : 
    1272             :   /* Populate the classifier tables with rules from the MACIP ACL */
    1273       12078 :   for (i = 0; i < a->count; i++)
    1274             :     {
    1275       11942 :       u32 action = 0;
    1276       11942 :       u32 metadata = 0;
    1277       11942 :       int is6 = a->rules[i].is_ipv6;
    1278             :       int l3_src_offs;
    1279             :       int l3_dst_offs;
    1280             :       u32 tag_table;
    1281             :       int tags, eth;
    1282             : 
    1283             :       match_type_index =
    1284       11942 :         macip_find_match_type (mvec, a->rules[i].src_mac_mask,
    1285       11942 :                                a->rules[i].src_prefixlen,
    1286       11942 :                                a->rules[i].is_ipv6);
    1287       11942 :       ASSERT (match_type_index != ~0);
    1288             : 
    1289       47768 :       for (tags = 2; tags >= 0; tags--)
    1290             :         {
    1291       35826 :           clib_memset (mask, 0, sizeof (mask));
    1292       35826 :           l3_src_offs = tags * 4 + get_l3_src_offset (is6);
    1293       35826 :           memcpy (&mask[6], a->rules[i].src_mac, 6);
    1294       35826 :           switch (tags)
    1295             :             {
    1296       11942 :             case 0:
    1297             :             default:
    1298       11942 :               tag_table = mvec[match_type_index].table_index;
    1299       11942 :               eth = 12;
    1300       11942 :               break;
    1301       11942 :             case 1:
    1302       11942 :               tag_table = mvec[match_type_index].dot1q_table_index;
    1303       11942 :               mask[12] = 0x81;
    1304       11942 :               mask[13] = 0x00;
    1305       11942 :               eth = 16;
    1306       11942 :               break;
    1307       11942 :             case 2:
    1308       11942 :               tag_table = mvec[match_type_index].dot1ad_table_index;
    1309       11942 :               mask[12] = 0x88;
    1310       11942 :               mask[13] = 0xa8;
    1311       11942 :               mask[16] = 0x81;
    1312       11942 :               mask[17] = 0x00;
    1313       11942 :               eth = 20;
    1314       11942 :               break;
    1315             :             }
    1316       35826 :           if (is6)
    1317             :             {
    1318       17916 :               memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
    1319       17916 :               mask[eth] = 0x86;
    1320       17916 :               mask[eth + 1] = 0xdd;
    1321             :             }
    1322             :           else
    1323             :             {
    1324       17910 :               memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
    1325       17910 :               mask[eth] = 0x08;
    1326       17910 :               mask[eth + 1] = 0x00;
    1327             :             }
    1328             : 
    1329             :           /* add session to table mvec[match_type_index].table_index; */
    1330       35826 :           vnet_classify_add_del_session (cm, tag_table,
    1331       35826 :                                          mask, a->rules[i].is_permit ? ~0 : 0,
    1332             :                                          i, 0, action, metadata, 1);
    1333       35826 :           clib_memset (&mask[12], 0, sizeof (mask) - 12);
    1334             :         }
    1335             : 
    1336             :       /* add ARP table entry too */
    1337       11942 :       if (!is6 && (mvec[match_type_index].arp_table_index != ~0))
    1338             :         {
    1339        5970 :           clib_memset (mask, 0, sizeof (mask));
    1340        5970 :           memcpy (&mask[6], a->rules[i].src_mac, 6);
    1341             : 
    1342       23880 :           for (tags = 2; tags >= 0; tags--)
    1343             :             {
    1344       17910 :               switch (tags)
    1345             :                 {
    1346        5970 :                 case 0:
    1347             :                 default:
    1348        5970 :                   tag_table = mvec[match_type_index].arp_table_index;
    1349        5970 :                   mask[12] = 0x08;
    1350        5970 :                   mask[13] = 0x06;
    1351        5970 :                   l3_src_offs = 14;
    1352        5970 :                   break;
    1353        5970 :                 case 1:
    1354        5970 :                   tag_table = mvec[match_type_index].arp_dot1q_table_index;
    1355        5970 :                   mask[12] = 0x81;
    1356        5970 :                   mask[13] = 0x00;
    1357        5970 :                   mask[16] = 0x08;
    1358        5970 :                   mask[17] = 0x06;
    1359        5970 :                   l3_src_offs = 18;
    1360        5970 :                   break;
    1361        5970 :                 case 2:
    1362        5970 :                   tag_table = mvec[match_type_index].arp_dot1ad_table_index;
    1363        5970 :                   mask[12] = 0x88;
    1364        5970 :                   mask[13] = 0xa8;
    1365        5970 :                   mask[16] = 0x81;
    1366        5970 :                   mask[17] = 0x00;
    1367        5970 :                   mask[20] = 0x08;
    1368        5970 :                   mask[21] = 0x06;
    1369        5970 :                   l3_src_offs = 22;
    1370        5970 :                   break;
    1371             :                 }
    1372             : 
    1373       17910 :               memcpy (&mask[l3_src_offs + 8], a->rules[i].src_mac, 6);
    1374       17910 :               memcpy (&mask[l3_src_offs + 14], &a->rules[i].src_ip_addr.ip4,
    1375             :                       4);
    1376       17910 :               vnet_classify_add_del_session (cm, tag_table, mask,
    1377       17910 :                                              a->rules[i].is_permit ? ~0 : 0,
    1378             :                                              i, 0, action, metadata, 1);
    1379             :             }
    1380             :         }
    1381       11942 :       if (macip_permit_also_egress (a->rules[i].is_permit))
    1382             :         {
    1383             :           /* Add the egress entry with destination set */
    1384           0 :           for (tags = 2; tags >= 0; tags--)
    1385             :             {
    1386           0 :               clib_memset (mask, 0, sizeof (mask));
    1387           0 :               l3_dst_offs = tags * 4 + get_l3_dst_offset (is6);
    1388             :               /* src mac in the other direction becomes dst */
    1389           0 :               memcpy (&mask[0], a->rules[i].src_mac, 6);
    1390           0 :               switch (tags)
    1391             :                 {
    1392           0 :                 case 0:
    1393             :                 default:
    1394           0 :                   tag_table = mvec[match_type_index].out_table_index;
    1395           0 :                   eth = 12;
    1396           0 :                   break;
    1397           0 :                 case 1:
    1398           0 :                   tag_table = mvec[match_type_index].out_dot1q_table_index;
    1399           0 :                   mask[12] = 0x81;
    1400           0 :                   mask[13] = 0x00;
    1401           0 :                   eth = 16;
    1402           0 :                   break;
    1403           0 :                 case 2:
    1404           0 :                   tag_table = mvec[match_type_index].out_dot1ad_table_index;
    1405           0 :                   mask[12] = 0x88;
    1406           0 :                   mask[13] = 0xa8;
    1407           0 :                   mask[16] = 0x81;
    1408           0 :                   mask[17] = 0x00;
    1409           0 :                   eth = 20;
    1410           0 :                   break;
    1411             :                 }
    1412           0 :               if (is6)
    1413             :                 {
    1414           0 :                   memcpy (&mask[l3_dst_offs], &a->rules[i].src_ip_addr.ip6,
    1415             :                           16);
    1416           0 :                   mask[eth] = 0x86;
    1417           0 :                   mask[eth + 1] = 0xdd;
    1418             :                 }
    1419             :               else
    1420             :                 {
    1421           0 :                   memcpy (&mask[l3_dst_offs], &a->rules[i].src_ip_addr.ip4,
    1422             :                           4);
    1423           0 :                   mask[eth] = 0x08;
    1424           0 :                   mask[eth + 1] = 0x00;
    1425             :                 }
    1426             : 
    1427             :               /* add session to table mvec[match_type_index].table_index; */
    1428           0 :               vnet_classify_add_del_session (cm, tag_table,
    1429             :                                              mask,
    1430           0 :                                              a->rules[i].is_permit ? ~0 : 0,
    1431             :                                              i, 0, action, metadata, 1);
    1432             :               // clib_memset (&mask[12], 0, sizeof (mask) - 12);
    1433             :             }
    1434             : 
    1435             :           /* add ARP table entry too */
    1436           0 :           if (!is6 && (mvec[match_type_index].out_arp_table_index != ~0))
    1437             :             {
    1438           0 :               for (tags = 2; tags >= 0; tags--)
    1439             :                 {
    1440           0 :                   clib_memset (mask, 0, sizeof (mask));
    1441           0 :                   switch (tags)
    1442             :                     {
    1443           0 :                     case 0:
    1444             :                     default:
    1445           0 :                       tag_table = mvec[match_type_index].out_arp_table_index;
    1446           0 :                       mask[12] = 0x08;
    1447           0 :                       mask[13] = 0x06;
    1448           0 :                       break;
    1449           0 :                     case 1:
    1450           0 :                       tag_table =
    1451           0 :                         mvec[match_type_index].out_arp_dot1q_table_index;
    1452           0 :                       mask[12] = 0x81;
    1453           0 :                       mask[13] = 0x00;
    1454           0 :                       mask[16] = 0x08;
    1455           0 :                       mask[17] = 0x06;
    1456           0 :                       break;
    1457           0 :                     case 2:
    1458           0 :                       tag_table =
    1459           0 :                         mvec[match_type_index].out_arp_dot1ad_table_index;
    1460           0 :                       mask[12] = 0x88;
    1461           0 :                       mask[13] = 0xa8;
    1462           0 :                       mask[16] = 0x81;
    1463           0 :                       mask[17] = 0x00;
    1464           0 :                       mask[20] = 0x08;
    1465           0 :                       mask[21] = 0x06;
    1466           0 :                       break;
    1467             :                     }
    1468             : 
    1469           0 :                   vnet_classify_add_del_session (cm, tag_table,
    1470             :                                                  mask,
    1471           0 :                                                  a->rules[i].
    1472             :                                                  is_permit ? ~0 : 0, i, 0,
    1473             :                                                  action, metadata, 1);
    1474             :                 }
    1475             :             }
    1476             :         }
    1477             :     }
    1478         136 :   return 0;
    1479             : }
    1480             : 
    1481             : static void
    1482         136 : macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
    1483             : {
    1484         136 :   vnet_classify_main_t *cm = &vnet_classify_main;
    1485         136 :   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
    1486             : 
    1487         136 :   if (a->ip4_table_index != ~0)
    1488             :     {
    1489         136 :       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
    1490             :                                         &a->ip4_table_index, 0);
    1491         136 :       a->ip4_table_index = ~0;
    1492             :     }
    1493         136 :   if (a->ip6_table_index != ~0)
    1494             :     {
    1495         136 :       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
    1496             :                                         &a->ip6_table_index, 0);
    1497         136 :       a->ip6_table_index = ~0;
    1498             :     }
    1499         136 :   if (a->l2_table_index != ~0)
    1500             :     {
    1501         136 :       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index,
    1502             :                                         0);
    1503         136 :       a->l2_table_index = ~0;
    1504             :     }
    1505         136 :   if (a->out_ip4_table_index != ~0)
    1506             :     {
    1507           0 :       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
    1508             :                                         &a->out_ip4_table_index, 0);
    1509           0 :       a->out_ip4_table_index = ~0;
    1510             :     }
    1511         136 :   if (a->out_ip6_table_index != ~0)
    1512             :     {
    1513           0 :       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
    1514             :                                         &a->out_ip6_table_index, 0);
    1515           0 :       a->out_ip6_table_index = ~0;
    1516             :     }
    1517         136 :   if (a->out_l2_table_index != ~0)
    1518             :     {
    1519           0 :       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
    1520             :                                         &a->out_l2_table_index, 0);
    1521           0 :       a->out_l2_table_index = ~0;
    1522             :     }
    1523         136 : }
    1524             : 
    1525             : static int
    1526         142 : macip_maybe_apply_unapply_classifier_tables (acl_main_t * am, u32 acl_index,
    1527             :                                              int is_apply)
    1528             : {
    1529         142 :   int rv = 0;
    1530         142 :   int rv0 = 0;
    1531             :   int i;
    1532         142 :   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, acl_index);
    1533             : 
    1534         430 :   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
    1535         288 :     if (vec_elt (am->macip_acl_by_sw_if_index, i) == acl_index)
    1536             :       {
    1537           8 :         rv0 = vnet_set_input_acl_intfc (am->vlib_main, i, a->ip4_table_index,
    1538             :                                         a->ip6_table_index, a->l2_table_index,
    1539             :                                         is_apply);
    1540             :         /* return the first unhappy outcome but make try to plough through. */
    1541           8 :         rv = rv || rv0;
    1542             :         rv0 =
    1543           8 :           vnet_set_output_acl_intfc (am->vlib_main, i, a->out_ip4_table_index,
    1544             :                                      a->out_ip6_table_index,
    1545             :                                      a->out_l2_table_index, is_apply);
    1546             :         /* return the first unhappy outcome but make try to plough through. */
    1547           8 :         rv = rv || rv0;
    1548             :       }
    1549         142 :   return rv;
    1550             : }
    1551             : 
    1552             : static int
    1553         136 : macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
    1554             :                     u32 * acl_list_index, u8 * tag)
    1555             : {
    1556         136 :   acl_main_t *am = &acl_main;
    1557             :   macip_acl_list_t *a;
    1558             :   macip_acl_rule_t *r;
    1559         136 :   macip_acl_rule_t *acl_new_rules = 0;
    1560             :   size_t tag_len;
    1561             :   int i;
    1562         136 :   int rv = 0;
    1563             : 
    1564         136 :   tag_len = clib_strnlen ((const char *) tag, sizeof (a->tag));
    1565         136 :   if (tag_len == sizeof (a->tag))
    1566           0 :     return VNET_API_ERROR_INVALID_VALUE;
    1567             : 
    1568         136 :   if (*acl_list_index != ~0)
    1569             :     {
    1570             :       /* They supplied some number, let's see if this MACIP ACL exists */
    1571           6 :       if (pool_is_free_index (am->macip_acls, *acl_list_index))
    1572             :         {
    1573             :           /* tried to replace a non-existent ACL, no point doing anything */
    1574           0 :           clib_warning
    1575             :             ("acl-plugin-error: Trying to replace nonexistent MACIP ACL %d (tag %s)",
    1576             :              *acl_list_index, tag);
    1577           0 :           return VNET_API_ERROR_NO_SUCH_ENTRY;
    1578             :         }
    1579             :     }
    1580             : 
    1581         136 :   if (0 == count)
    1582             :     {
    1583           0 :       clib_warning
    1584             :         ("acl-plugin-warning: Trying to create empty MACIP ACL (tag %s)",
    1585             :          tag);
    1586             :     }
    1587             :   /* if replacing the ACL, unapply the classifier tables first - they will be gone.. */
    1588         136 :   if (~0 != *acl_list_index)
    1589           6 :     rv = macip_maybe_apply_unapply_classifier_tables (am, *acl_list_index, 0);
    1590             :   /* Create and populate the rules */
    1591         136 :   if (count > 0)
    1592         136 :     vec_validate (acl_new_rules, count - 1);
    1593             : 
    1594       12078 :   for (i = 0; i < count; i++)
    1595             :     {
    1596       11942 :       r = &acl_new_rules[i];
    1597       11942 :       r->is_permit = rules[i].is_permit;
    1598       11942 :       r->is_ipv6 = rules[i].src_prefix.address.af;
    1599       11942 :       mac_address_decode (rules[i].src_mac, (mac_address_t *) & r->src_mac);
    1600       11942 :       mac_address_decode (rules[i].src_mac_mask,
    1601       11942 :                           (mac_address_t *) & r->src_mac_mask);
    1602       11942 :       ip_address_decode (&rules[i].src_prefix.address, &r->src_ip_addr);
    1603       11942 :       r->src_prefixlen = rules[i].src_prefix.len;
    1604             :     }
    1605             : 
    1606         136 :   if (~0 == *acl_list_index)
    1607             :     {
    1608             :       /* Get ACL index */
    1609         130 :       pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
    1610         130 :       clib_memset (a, 0, sizeof (*a));
    1611             :       /* Will return the newly allocated ACL index */
    1612         130 :       *acl_list_index = a - am->macip_acls;
    1613             :     }
    1614             :   else
    1615             :     {
    1616           6 :       a = pool_elt_at_index (am->macip_acls, *acl_list_index);
    1617           6 :       if (a->rules)
    1618             :         {
    1619           6 :           vec_free (a->rules);
    1620             :         }
    1621           6 :       macip_destroy_classify_tables (am, *acl_list_index);
    1622             :     }
    1623             : 
    1624         136 :   a->rules = acl_new_rules;
    1625         136 :   a->count = count;
    1626         136 :   memcpy (a->tag, tag, tag_len + 1);
    1627             : 
    1628             :   /* Create and populate the classifier tables */
    1629         136 :   macip_create_classify_tables (am, *acl_list_index);
    1630             :   /* If the ACL was already applied somewhere, reapply the newly created tables */
    1631         136 :   rv = rv
    1632         136 :     || macip_maybe_apply_unapply_classifier_tables (am, *acl_list_index, 1);
    1633         136 :   return rv;
    1634             : }
    1635             : 
    1636             : /* No check that sw_if_index denotes a valid interface - the callers
    1637             :  * were supposed to validate.
    1638             :  *
    1639             :  * That said, if sw_if_index corresponds to an interface that exists at all,
    1640             :  * this function must return errors accordingly if the ACL is not applied.
    1641             :  */
    1642             : 
    1643             : static int
    1644        4241 : macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
    1645             : {
    1646             :   int rv;
    1647             :   u32 macip_acl_index;
    1648             :   macip_acl_list_t *a;
    1649             : 
    1650             :   /* The vector is too short - MACIP ACL is not applied */
    1651        4241 :   if (sw_if_index >= vec_len (am->macip_acl_by_sw_if_index))
    1652        4175 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
    1653             : 
    1654          66 :   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
    1655             :   /* No point in deleting MACIP ACL which is not applied */
    1656          66 :   if (~0 == macip_acl_index)
    1657           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
    1658             : 
    1659          66 :   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
    1660             :   /* remove the classifier tables off the interface L2 ACL */
    1661             :   rv =
    1662          66 :     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
    1663             :                               a->ip6_table_index, a->l2_table_index, 0);
    1664          66 :   rv |=
    1665          66 :     vnet_set_output_acl_intfc (am->vlib_main, sw_if_index,
    1666             :                                a->out_ip4_table_index, a->out_ip6_table_index,
    1667             :                                a->out_l2_table_index, 0);
    1668             :   /* Unset the MACIP ACL index */
    1669          66 :   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
    1670             :   /* macip_acl_interface_add_acl did a vec_add1() to this previously, so [sw_if_index] should be valid */
    1671          66 :   u32 index = vec_search (am->sw_if_index_vec_by_macip_acl[macip_acl_index],
    1672             :                           sw_if_index);
    1673          66 :   if (index != ~0)
    1674          66 :     vec_del1 (am->sw_if_index_vec_by_macip_acl[macip_acl_index], index);
    1675          66 :   return rv;
    1676             : }
    1677             : 
    1678             : /* No check for validity of sw_if_index - the callers were supposed to validate */
    1679             : 
    1680             : static int
    1681          66 : macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
    1682             :                              u32 macip_acl_index)
    1683             : {
    1684             :   macip_acl_list_t *a;
    1685             :   int rv;
    1686          66 :   if (pool_is_free_index (am->macip_acls, macip_acl_index))
    1687             :     {
    1688           0 :       return VNET_API_ERROR_NO_SUCH_ENTRY;
    1689             :     }
    1690          66 :   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
    1691          89 :   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
    1692          66 :   vec_validate (am->sw_if_index_vec_by_macip_acl, macip_acl_index);
    1693          66 :   vec_add1 (am->sw_if_index_vec_by_macip_acl[macip_acl_index], sw_if_index);
    1694             :   /* If there already a MACIP ACL applied, unapply it */
    1695          66 :   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
    1696           4 :     macip_acl_interface_del_acl (am, sw_if_index);
    1697          66 :   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
    1698             : 
    1699             :   /* Apply the classifier tables for L2 ACLs */
    1700             :   rv =
    1701          66 :     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
    1702             :                               a->ip6_table_index, a->l2_table_index, 1);
    1703          66 :   rv |=
    1704          66 :     vnet_set_output_acl_intfc (am->vlib_main, sw_if_index,
    1705             :                                a->out_ip4_table_index, a->out_ip6_table_index,
    1706             :                                a->out_l2_table_index, 1);
    1707          66 :   return rv;
    1708             : }
    1709             : 
    1710             : static int
    1711         130 : macip_acl_del_list (u32 acl_list_index)
    1712             : {
    1713         130 :   acl_main_t *am = &acl_main;
    1714             :   macip_acl_list_t *a;
    1715             :   int i;
    1716         130 :   if (pool_is_free_index (am->macip_acls, acl_list_index))
    1717             :     {
    1718           0 :       return VNET_API_ERROR_NO_SUCH_ENTRY;
    1719             :     }
    1720             : 
    1721             :   /* delete any references to the ACL */
    1722         510 :   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
    1723             :     {
    1724         380 :       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
    1725             :         {
    1726          20 :           macip_acl_interface_del_acl (am, i);
    1727             :         }
    1728             :     }
    1729             : 
    1730             :   /* Now that classifier tables are detached, clean them up */
    1731         130 :   macip_destroy_classify_tables (am, acl_list_index);
    1732             : 
    1733             :   /* now we can delete the ACL itself */
    1734         130 :   a = pool_elt_at_index (am->macip_acls, acl_list_index);
    1735         130 :   if (a->rules)
    1736             :     {
    1737         130 :       vec_free (a->rules);
    1738             :     }
    1739         130 :   pool_put (am->macip_acls, a);
    1740         130 :   return 0;
    1741             : }
    1742             : 
    1743             : 
    1744             : static int
    1745         104 : macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
    1746             :                                  u32 acl_list_index)
    1747             : {
    1748         104 :   acl_main_t *am = &acl_main;
    1749         104 :   int rv = -1;
    1750         104 :   if (is_add)
    1751             :     {
    1752          66 :       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
    1753             :     }
    1754             :   else
    1755             :     {
    1756          38 :       rv = macip_acl_interface_del_acl (am, sw_if_index);
    1757             :     }
    1758         104 :   return rv;
    1759             : }
    1760             : 
    1761             : /*
    1762             :  * If the client does not allocate enough memory for a variable-length
    1763             :  * message, and then proceed to use it as if the full memory allocated,
    1764             :  * absent the check we happily consume that on the VPP side, and go
    1765             :  * along as if nothing happened. However, the resulting
    1766             :  * effects range from just garbage in the API decode
    1767             :  * (because the decoder snoops too far), to potential memory
    1768             :  * corruptions.
    1769             :  *
    1770             :  * This verifies that the actual length of the message is
    1771             :  * at least expected_len, and complains loudly if it is not.
    1772             :  *
    1773             :  * A failing check here is 100% a software bug on the API user side,
    1774             :  * so we might as well yell.
    1775             :  *
    1776             :  */
    1777             : static int
    1778        2722 : verify_message_len (void *mp, u64 expected_len, char *where)
    1779             : {
    1780        2722 :   u32 supplied_len = vl_msg_api_get_msg_length (mp);
    1781        2722 :   if (supplied_len < expected_len)
    1782             :     {
    1783           0 :       clib_warning ("%s: Supplied message length %d is less than expected %d",
    1784             :                     where, supplied_len, expected_len);
    1785           0 :       return 0;
    1786             :     }
    1787             :   else
    1788             :     {
    1789        2722 :       return 1;
    1790             :     }
    1791             : }
    1792             : 
    1793             : /* API message handler */
    1794             : static void
    1795        2586 : vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
    1796             : {
    1797             :   vl_api_acl_add_replace_reply_t *rmp;
    1798        2586 :   acl_main_t *am = &acl_main;
    1799             :   int rv;
    1800        2586 :   u32 acl_list_index = ntohl (mp->acl_index);
    1801        2586 :   u32 acl_count = ntohl (mp->count);
    1802        2586 :   u64 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
    1803             : 
    1804        2586 :   if (verify_message_len (mp, expected_len, "acl_add_replace"))
    1805             :     {
    1806        2586 :       rv = acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
    1807             :     }
    1808             :   else
    1809             :     {
    1810           0 :       rv = VNET_API_ERROR_INVALID_VALUE;
    1811             :     }
    1812             : 
    1813             :   /* *INDENT-OFF* */
    1814        2586 :   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
    1815             :   ({
    1816             :     rmp->acl_index = htonl(acl_list_index);
    1817             :   }));
    1818             :   /* *INDENT-ON* */
    1819             : }
    1820             : 
    1821             : static void
    1822         427 : vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
    1823             : {
    1824         427 :   acl_main_t *am = &acl_main;
    1825             :   vl_api_acl_del_reply_t *rmp;
    1826             :   int rv;
    1827             : 
    1828         427 :   rv = acl_del_list (ntohl (mp->acl_index));
    1829             : 
    1830         427 :   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
    1831             : }
    1832             : 
    1833             : 
    1834             : static void
    1835           6 :   vl_api_acl_stats_intf_counters_enable_t_handler
    1836             :   (vl_api_acl_stats_intf_counters_enable_t * mp)
    1837             : {
    1838           6 :   acl_main_t *am = &acl_main;
    1839             :   vl_api_acl_stats_intf_counters_enable_reply_t *rmp;
    1840             :   int rv;
    1841             : 
    1842           6 :   rv = acl_stats_intf_counters_enable_disable (am, mp->enable);
    1843             : 
    1844           6 :   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
    1845             : }
    1846             : 
    1847             : 
    1848             : static void
    1849           0 : vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
    1850             : {
    1851           0 :   acl_main_t *am = &acl_main;
    1852           0 :   vnet_interface_main_t *im = &am->vnet_main->interface_main;
    1853           0 :   u32 sw_if_index = ntohl (mp->sw_if_index);
    1854             :   vl_api_acl_interface_add_del_reply_t *rmp;
    1855           0 :   int rv = -1;
    1856             : 
    1857           0 :   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
    1858           0 :     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1859             :   else
    1860             :     rv =
    1861           0 :       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
    1862           0 :                                        mp->is_input, ntohl (mp->acl_index));
    1863             : 
    1864           0 :   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
    1865             : }
    1866             : 
    1867             : static void
    1868         573 :   vl_api_acl_interface_set_acl_list_t_handler
    1869             :   (vl_api_acl_interface_set_acl_list_t * mp)
    1870             : {
    1871         573 :   acl_main_t *am = &acl_main;
    1872             :   vl_api_acl_interface_set_acl_list_reply_t *rmp;
    1873         573 :   int rv = 0;
    1874             :   int i;
    1875         573 :   vnet_interface_main_t *im = &am->vnet_main->interface_main;
    1876         573 :   u32 sw_if_index = ntohl (mp->sw_if_index);
    1877             : 
    1878         573 :   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
    1879           0 :     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1880             :   else
    1881             :     {
    1882         573 :       int may_clear_sessions = 1;
    1883        1590 :       for (i = 0; i < mp->count; i++)
    1884             :         {
    1885        1017 :           if (acl_is_not_defined (am, ntohl (mp->acls[i])))
    1886             :             {
    1887             :               /* ACL does not exist, so we can not apply it */
    1888           1 :               rv = VNET_API_ERROR_NO_SUCH_ENTRY;
    1889             :             }
    1890             :         }
    1891         573 :       if (0 == rv)
    1892             :         {
    1893         572 :           u32 *in_acl_vec = 0;
    1894         572 :           u32 *out_acl_vec = 0;
    1895        1588 :           for (i = 0; i < mp->count; i++)
    1896        1016 :             if (i < mp->n_input)
    1897         543 :               vec_add1 (in_acl_vec, clib_net_to_host_u32 (mp->acls[i]));
    1898             :             else
    1899         473 :               vec_add1 (out_acl_vec, clib_net_to_host_u32 (mp->acls[i]));
    1900             : 
    1901             :           rv =
    1902         572 :             acl_interface_set_inout_acl_list (am, sw_if_index, 0, out_acl_vec,
    1903             :                                               &may_clear_sessions);
    1904         572 :           rv = rv
    1905         572 :             || acl_interface_set_inout_acl_list (am, sw_if_index, 1,
    1906             :                                                  in_acl_vec,
    1907             :                                                  &may_clear_sessions);
    1908         572 :           vec_free (in_acl_vec);
    1909         572 :           vec_free (out_acl_vec);
    1910             :         }
    1911             :     }
    1912             : 
    1913         573 :   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
    1914             : }
    1915             : 
    1916             : static void
    1917        1129 : copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
    1918             : {
    1919        1129 :   api_rule->is_permit = r->is_permit;
    1920        1129 :   ip_address_encode (&r->src, r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
    1921             :                      &api_rule->src_prefix.address);
    1922        1129 :   ip_address_encode (&r->dst, r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
    1923             :                      &api_rule->dst_prefix.address);
    1924        1129 :   api_rule->src_prefix.len = r->src_prefixlen;
    1925        1129 :   api_rule->dst_prefix.len = r->dst_prefixlen;
    1926        1129 :   api_rule->proto = r->proto;
    1927        1129 :   api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
    1928        1129 :   api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
    1929        1129 :   api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
    1930        1129 :   api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
    1931        1129 :   api_rule->tcp_flags_mask = r->tcp_flags_mask;
    1932        1129 :   api_rule->tcp_flags_value = r->tcp_flags_value;
    1933        1129 : }
    1934             : 
    1935             : static void
    1936         206 : send_acl_details (acl_main_t * am, vl_api_registration_t * reg,
    1937             :                   acl_list_t * acl, u32 context)
    1938             : {
    1939             :   vl_api_acl_details_t *mp;
    1940             :   vl_api_acl_rule_t *rules;
    1941             :   int i;
    1942         206 :   acl_rule_t *acl_rules = acl->rules;
    1943         206 :   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * vec_len (acl_rules);
    1944             : 
    1945         206 :   mp = vl_msg_api_alloc (msg_size);
    1946         206 :   clib_memset (mp, 0, msg_size);
    1947         206 :   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
    1948             : 
    1949             :   /* fill in the message */
    1950         206 :   mp->context = context;
    1951         206 :   mp->count = htonl (vec_len (acl_rules));
    1952         206 :   mp->acl_index = htonl (acl - am->acls);
    1953         206 :   snprintf ((char *) mp->tag, sizeof (mp->tag), "%s", acl->tag);
    1954             :   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
    1955         206 :   rules = mp->r;
    1956        1335 :   for (i = 0; i < vec_len (acl_rules); i++)
    1957             :     {
    1958        1129 :       copy_acl_rule_to_api_rule (&rules[i], &acl_rules[i]);
    1959             :     }
    1960             : 
    1961         206 :   vl_api_send_msg (reg, (u8 *) mp);
    1962         206 : }
    1963             : 
    1964             : 
    1965             : static void
    1966         591 : vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
    1967             : {
    1968         591 :   acl_main_t *am = &acl_main;
    1969             :   u32 acl_index;
    1970             :   acl_list_t *acl;
    1971         591 :   int rv = -1;
    1972             :   vl_api_registration_t *reg;
    1973             : 
    1974         591 :   reg = vl_api_client_index_to_registration (mp->client_index);
    1975         591 :   if (!reg)
    1976           0 :     return;
    1977             : 
    1978         591 :   if (mp->acl_index == ~0)
    1979             :     {
    1980             :     /* *INDENT-OFF* */
    1981             :     /* Just dump all ACLs */
    1982           0 :     pool_foreach (acl, am->acls)
    1983             :      {
    1984           0 :       send_acl_details(am, reg, acl, mp->context);
    1985             :     }
    1986             :     /* *INDENT-ON* */
    1987             :     }
    1988             :   else
    1989             :     {
    1990         591 :       acl_index = ntohl (mp->acl_index);
    1991         591 :       if (!pool_is_free_index (am->acls, acl_index))
    1992             :         {
    1993         206 :           acl = pool_elt_at_index (am->acls, acl_index);
    1994         206 :           send_acl_details (am, reg, acl, mp->context);
    1995             :         }
    1996             :     }
    1997             : 
    1998         591 :   if (rv == -1)
    1999             :     {
    2000             :       /* FIXME API: should we signal an error here at all ? */
    2001         591 :       return;
    2002             :     }
    2003             : }
    2004             : 
    2005             : static void
    2006         390 : send_acl_interface_list_details (acl_main_t * am,
    2007             :                                  vl_api_registration_t * reg,
    2008             :                                  u32 sw_if_index, u32 context)
    2009             : {
    2010             :   vl_api_acl_interface_list_details_t *mp;
    2011             :   int msg_size;
    2012             :   int n_input;
    2013             :   int n_output;
    2014             :   int count;
    2015         390 :   int i = 0;
    2016             : 
    2017         390 :   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
    2018         390 :   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
    2019             : 
    2020         390 :   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
    2021         390 :   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
    2022         390 :   count = n_input + n_output;
    2023             : 
    2024         390 :   msg_size = sizeof (*mp);
    2025         390 :   msg_size += sizeof (mp->acls[0]) * count;
    2026             : 
    2027         390 :   mp = vl_msg_api_alloc (msg_size);
    2028         390 :   clib_memset (mp, 0, msg_size);
    2029         390 :   mp->_vl_msg_id =
    2030         390 :     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
    2031             : 
    2032             :   /* fill in the message */
    2033         390 :   mp->context = context;
    2034         390 :   mp->sw_if_index = htonl (sw_if_index);
    2035         390 :   mp->count = count;
    2036         390 :   mp->n_input = n_input;
    2037         549 :   for (i = 0; i < n_input; i++)
    2038             :     {
    2039         159 :       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
    2040             :     }
    2041         490 :   for (i = 0; i < n_output; i++)
    2042             :     {
    2043         100 :       mp->acls[n_input + i] =
    2044         100 :         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
    2045             :     }
    2046         390 :   vl_api_send_msg (reg, (u8 *) mp);
    2047         390 : }
    2048             : 
    2049             : static void
    2050         391 : vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
    2051             :                                           mp)
    2052             : {
    2053         391 :   acl_main_t *am = &acl_main;
    2054             :   vnet_sw_interface_t *swif;
    2055         391 :   vnet_interface_main_t *im = &am->vnet_main->interface_main;
    2056             : 
    2057             :   u32 sw_if_index;
    2058             :   vl_api_registration_t *reg;
    2059             : 
    2060         391 :   reg = vl_api_client_index_to_registration (mp->client_index);
    2061         391 :   if (!reg)
    2062           0 :     return;
    2063             : 
    2064         391 :   if (mp->sw_if_index == ~0)
    2065             :     {
    2066             :     /* *INDENT-OFF* */
    2067           0 :     pool_foreach (swif, im->sw_interfaces)
    2068             :      {
    2069           0 :       send_acl_interface_list_details(am, reg, swif->sw_if_index, mp->context);
    2070             :     }
    2071             :     /* *INDENT-ON* */
    2072             :     }
    2073             :   else
    2074             :     {
    2075         391 :       sw_if_index = ntohl (mp->sw_if_index);
    2076         391 :       if (!pool_is_free_index (im->sw_interfaces, sw_if_index))
    2077         390 :         send_acl_interface_list_details (am, reg, sw_if_index, mp->context);
    2078             :     }
    2079             : }
    2080             : 
    2081             : /* MACIP ACL API handlers */
    2082             : 
    2083             : static void
    2084           0 : vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
    2085             : {
    2086             :   vl_api_macip_acl_add_reply_t *rmp;
    2087           0 :   acl_main_t *am = &acl_main;
    2088             :   int rv;
    2089           0 :   u32 acl_list_index = ~0;
    2090           0 :   u32 acl_count = ntohl (mp->count);
    2091           0 :   u64 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
    2092             : 
    2093           0 :   if (verify_message_len (mp, expected_len, "macip_acl_add"))
    2094             :     {
    2095           0 :       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
    2096             :     }
    2097             :   else
    2098             :     {
    2099           0 :       rv = VNET_API_ERROR_INVALID_VALUE;
    2100             :     }
    2101             : 
    2102             :   /* *INDENT-OFF* */
    2103           0 :   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
    2104             :   ({
    2105             :     rmp->acl_index = htonl(acl_list_index);
    2106             :   }));
    2107             :   /* *INDENT-ON* */
    2108             : }
    2109             : 
    2110             : static void
    2111         136 : vl_api_macip_acl_add_replace_t_handler (vl_api_macip_acl_add_replace_t * mp)
    2112             : {
    2113             :   vl_api_macip_acl_add_replace_reply_t *rmp;
    2114         136 :   acl_main_t *am = &acl_main;
    2115             :   int rv;
    2116         136 :   u32 acl_list_index = ntohl (mp->acl_index);
    2117         136 :   u32 acl_count = ntohl (mp->count);
    2118         136 :   u64 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
    2119             : 
    2120         136 :   if (verify_message_len (mp, expected_len, "macip_acl_add_replace"))
    2121             :     {
    2122         136 :       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
    2123             :     }
    2124             :   else
    2125             :     {
    2126           0 :       rv = VNET_API_ERROR_INVALID_VALUE;
    2127             :     }
    2128             : 
    2129             :   /* *INDENT-OFF* */
    2130         136 :   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLACE_REPLY,
    2131             :   ({
    2132             :     rmp->acl_index = htonl(acl_list_index);
    2133             :   }));
    2134             :   /* *INDENT-ON* */
    2135             : }
    2136             : 
    2137             : static void
    2138         130 : vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
    2139             : {
    2140         130 :   acl_main_t *am = &acl_main;
    2141             :   vl_api_macip_acl_del_reply_t *rmp;
    2142             :   int rv;
    2143             : 
    2144         130 :   rv = macip_acl_del_list (ntohl (mp->acl_index));
    2145             : 
    2146         130 :   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
    2147             : }
    2148             : 
    2149             : static void
    2150         104 :   vl_api_macip_acl_interface_add_del_t_handler
    2151             :   (vl_api_macip_acl_interface_add_del_t * mp)
    2152             : {
    2153         104 :   acl_main_t *am = &acl_main;
    2154             :   vl_api_macip_acl_interface_add_del_reply_t *rmp;
    2155         104 :   int rv = -1;
    2156         104 :   vnet_interface_main_t *im = &am->vnet_main->interface_main;
    2157         104 :   u32 sw_if_index = ntohl (mp->sw_if_index);
    2158             : 
    2159         104 :   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
    2160           0 :     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
    2161             :   else
    2162             :     rv =
    2163         104 :       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
    2164             :                                        ntohl (mp->acl_index));
    2165             : 
    2166         104 :   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
    2167             : }
    2168             : 
    2169             : static void
    2170         218 : send_macip_acl_details (acl_main_t * am, vl_api_registration_t * reg,
    2171             :                         macip_acl_list_t * acl, u32 context)
    2172             : {
    2173             :   vl_api_macip_acl_details_t *mp;
    2174             :   vl_api_macip_acl_rule_t *rules;
    2175             :   macip_acl_rule_t *r;
    2176             :   int i;
    2177         218 :   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
    2178             : 
    2179         218 :   mp = vl_msg_api_alloc (msg_size);
    2180         218 :   clib_memset (mp, 0, msg_size);
    2181         218 :   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
    2182             : 
    2183             :   /* fill in the message */
    2184         218 :   mp->context = context;
    2185         218 :   if (acl)
    2186             :     {
    2187         218 :       snprintf ((char *) mp->tag, sizeof (mp->tag), "%s", acl->tag);
    2188         218 :       mp->count = htonl (acl->count);
    2189         218 :       mp->acl_index = htonl (acl - am->macip_acls);
    2190         218 :       rules = mp->r;
    2191       23896 :       for (i = 0; i < acl->count; i++)
    2192             :         {
    2193       23678 :           r = &acl->rules[i];
    2194       23678 :           rules[i].is_permit = r->is_permit;
    2195       23678 :           mac_address_encode ((mac_address_t *) & r->src_mac,
    2196       23678 :                               rules[i].src_mac);
    2197       23678 :           mac_address_encode ((mac_address_t *) & r->src_mac_mask,
    2198       23678 :                               rules[i].src_mac_mask);
    2199       23678 :           ip_address_encode (&r->src_ip_addr,
    2200       23678 :                              r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
    2201       23678 :                              &rules[i].src_prefix.address);
    2202       23678 :           rules[i].src_prefix.len = r->src_prefixlen;
    2203             :         }
    2204             :     }
    2205             :   else
    2206             :     {
    2207             :       /* No martini, no party - no ACL applied to this interface. */
    2208           0 :       mp->acl_index = ~0;
    2209           0 :       mp->count = 0;
    2210             :     }
    2211             : 
    2212         218 :   vl_api_send_msg (reg, (u8 *) mp);
    2213         218 : }
    2214             : 
    2215             : 
    2216             : static void
    2217         272 : vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
    2218             : {
    2219         272 :   acl_main_t *am = &acl_main;
    2220             :   macip_acl_list_t *acl;
    2221             : 
    2222             :   vl_api_registration_t *reg;
    2223             : 
    2224         272 :   reg = vl_api_client_index_to_registration (mp->client_index);
    2225         272 :   if (!reg)
    2226           0 :     return;
    2227             : 
    2228         272 :   if (mp->acl_index == ~0)
    2229             :     {
    2230             :       /* Just dump all ACLs for now, with sw_if_index = ~0 */
    2231             :       /* *INDENT-OFF* */
    2232         100 :       pool_foreach (acl, am->macip_acls)
    2233             :          {
    2234          88 :           send_macip_acl_details (am, reg, acl, mp->context);
    2235             :         }
    2236             :       /* *INDENT-ON* */
    2237             :     }
    2238             :   else
    2239             :     {
    2240         260 :       u32 acl_index = ntohl (mp->acl_index);
    2241         260 :       if (!pool_is_free_index (am->macip_acls, acl_index))
    2242             :         {
    2243         130 :           acl = pool_elt_at_index (am->macip_acls, acl_index);
    2244         130 :           send_macip_acl_details (am, reg, acl, mp->context);
    2245             :         }
    2246             :     }
    2247             : }
    2248             : 
    2249             : static void
    2250          26 : vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
    2251             :                                           mp)
    2252             : {
    2253          26 :   acl_main_t *am = &acl_main;
    2254             :   vl_api_macip_acl_interface_get_reply_t *rmp;
    2255          26 :   u32 count = vec_len (am->macip_acl_by_sw_if_index);
    2256          26 :   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
    2257             :   vl_api_registration_t *reg;
    2258             :   int i;
    2259             : 
    2260          26 :   reg = vl_api_client_index_to_registration (mp->client_index);
    2261          26 :   if (!reg)
    2262           0 :     return;
    2263             : 
    2264          26 :   rmp = vl_msg_api_alloc (msg_size);
    2265          26 :   clib_memset (rmp, 0, msg_size);
    2266          26 :   rmp->_vl_msg_id =
    2267          26 :     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
    2268          26 :   rmp->context = mp->context;
    2269          26 :   rmp->count = htonl (count);
    2270         138 :   for (i = 0; i < count; i++)
    2271             :     {
    2272         112 :       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
    2273             :     }
    2274             : 
    2275          26 :   vl_api_send_msg (reg, (u8 *) rmp);
    2276             : }
    2277             : 
    2278             : static void
    2279         123 : send_macip_acl_interface_list_details (acl_main_t * am,
    2280             :                                        vl_api_registration_t * reg,
    2281             :                                        u32 sw_if_index,
    2282             :                                        u32 acl_index, u32 context)
    2283             : {
    2284             :   vl_api_macip_acl_interface_list_details_t *rmp;
    2285             :   /* at this time there is only ever 1 mac ip acl per interface */
    2286         123 :   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]);
    2287             : 
    2288         123 :   rmp = vl_msg_api_alloc (msg_size);
    2289         123 :   clib_memset (rmp, 0, msg_size);
    2290         123 :   rmp->_vl_msg_id =
    2291         123 :     ntohs (VL_API_MACIP_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
    2292             : 
    2293             :   /* fill in the message */
    2294         123 :   rmp->context = context;
    2295         123 :   rmp->count = 1;
    2296         123 :   rmp->sw_if_index = htonl (sw_if_index);
    2297         123 :   rmp->acls[0] = htonl (acl_index);
    2298             : 
    2299         123 :   vl_api_send_msg (reg, (u8 *) rmp);
    2300         123 : }
    2301             : 
    2302             : static void
    2303         123 :   vl_api_macip_acl_interface_list_dump_t_handler
    2304             :   (vl_api_macip_acl_interface_list_dump_t * mp)
    2305             : {
    2306             :   vl_api_registration_t *reg;
    2307         123 :   acl_main_t *am = &acl_main;
    2308         123 :   u32 sw_if_index = ntohl (mp->sw_if_index);
    2309             : 
    2310         123 :   reg = vl_api_client_index_to_registration (mp->client_index);
    2311         123 :   if (!reg)
    2312           0 :     return;
    2313             : 
    2314         123 :   if (sw_if_index == ~0)
    2315             :     {
    2316           0 :       vec_foreach_index (sw_if_index, am->macip_acl_by_sw_if_index)
    2317             :       {
    2318           0 :         if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
    2319             :           {
    2320           0 :             send_macip_acl_interface_list_details (am, reg, sw_if_index,
    2321           0 :                                                    am->
    2322             :                                                    macip_acl_by_sw_if_index
    2323           0 :                                                    [sw_if_index],
    2324             :                                                    mp->context);
    2325             :           }
    2326             :       }
    2327             :     }
    2328             :   else
    2329             :     {
    2330         123 :       if (vec_len (am->macip_acl_by_sw_if_index) > sw_if_index)
    2331             :         {
    2332         123 :           send_macip_acl_interface_list_details (am, reg, sw_if_index,
    2333         123 :                                                  am->macip_acl_by_sw_if_index
    2334         123 :                                                  [sw_if_index], mp->context);
    2335             :         }
    2336             :     }
    2337             : }
    2338             : 
    2339             : static void
    2340          12 :   vl_api_acl_interface_set_etype_whitelist_t_handler
    2341             :   (vl_api_acl_interface_set_etype_whitelist_t * mp)
    2342             : {
    2343          12 :   acl_main_t *am = &acl_main;
    2344             :   vl_api_acl_interface_set_etype_whitelist_reply_t *rmp;
    2345          12 :   int rv = 0;
    2346             :   int i;
    2347          12 :   vnet_interface_main_t *im = &am->vnet_main->interface_main;
    2348          12 :   u32 sw_if_index = ntohl (mp->sw_if_index);
    2349          12 :   u16 *vec_in = 0, *vec_out = 0;
    2350             : 
    2351          12 :   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
    2352           0 :     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
    2353             :   else
    2354             :     {
    2355          18 :       for (i = 0; i < mp->count; i++)
    2356             :         {
    2357           6 :           if (i < mp->n_input)
    2358           6 :             vec_add1 (vec_in, ntohs (mp->whitelist[i]));
    2359             :           else
    2360           0 :             vec_add1 (vec_out, ntohs (mp->whitelist[i]));
    2361             :         }
    2362          12 :       rv = acl_set_etype_whitelists (am, sw_if_index, vec_in, vec_out);
    2363             :     }
    2364             : 
    2365          12 :   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ETYPE_WHITELIST_REPLY);
    2366             : }
    2367             : 
    2368             : static void
    2369           6 : send_acl_interface_etype_whitelist_details (acl_main_t * am,
    2370             :                                             vl_api_registration_t * reg,
    2371             :                                             u32 sw_if_index, u32 context)
    2372             : {
    2373             :   vl_api_acl_interface_etype_whitelist_details_t *mp;
    2374             :   int msg_size;
    2375           6 :   int n_input = 0;
    2376           6 :   int n_output = 0;
    2377           6 :   int count = 0;
    2378           6 :   int i = 0;
    2379             : 
    2380           6 :   u16 *whitelist_in = 0;
    2381           6 :   u16 *whitelist_out = 0;
    2382             : 
    2383           6 :   if (intf_has_etype_whitelist (am, sw_if_index, 0))
    2384           0 :     whitelist_out =
    2385           0 :       vec_elt (am->output_etype_whitelist_by_sw_if_index, sw_if_index);
    2386             : 
    2387           6 :   if (intf_has_etype_whitelist (am, sw_if_index, 1))
    2388           0 :     whitelist_in =
    2389           0 :       vec_elt (am->input_etype_whitelist_by_sw_if_index, sw_if_index);
    2390             : 
    2391           6 :   if ((0 == whitelist_in) && (0 == whitelist_out))
    2392           6 :     return;                     /* nothing to do */
    2393             : 
    2394           0 :   n_input = vec_len (whitelist_in);
    2395           0 :   n_output = vec_len (whitelist_out);
    2396           0 :   count = n_input + n_output;
    2397             : 
    2398           0 :   msg_size = sizeof (*mp);
    2399           0 :   msg_size += sizeof (mp->whitelist[0]) * count;
    2400             : 
    2401           0 :   mp = vl_msg_api_alloc (msg_size);
    2402           0 :   clib_memset (mp, 0, msg_size);
    2403           0 :   mp->_vl_msg_id =
    2404           0 :     ntohs (VL_API_ACL_INTERFACE_ETYPE_WHITELIST_DETAILS + am->msg_id_base);
    2405             : 
    2406             :   /* fill in the message */
    2407           0 :   mp->context = context;
    2408           0 :   mp->sw_if_index = htonl (sw_if_index);
    2409           0 :   mp->count = count;
    2410           0 :   mp->n_input = n_input;
    2411           0 :   for (i = 0; i < n_input; i++)
    2412             :     {
    2413           0 :       mp->whitelist[i] = htons (whitelist_in[i]);
    2414             :     }
    2415           0 :   for (i = 0; i < n_output; i++)
    2416             :     {
    2417           0 :       mp->whitelist[n_input + i] = htons (whitelist_out[i]);
    2418             :     }
    2419           0 :   vl_api_send_msg (reg, (u8 *) mp);
    2420             : }
    2421             : 
    2422             : 
    2423             : static void
    2424           6 :   vl_api_acl_interface_etype_whitelist_dump_t_handler
    2425             :   (vl_api_acl_interface_list_dump_t * mp)
    2426             : {
    2427           6 :   acl_main_t *am = &acl_main;
    2428             :   vnet_sw_interface_t *swif;
    2429           6 :   vnet_interface_main_t *im = &am->vnet_main->interface_main;
    2430             : 
    2431             :   u32 sw_if_index;
    2432             :   vl_api_registration_t *reg;
    2433             : 
    2434           6 :   reg = vl_api_client_index_to_registration (mp->client_index);
    2435           6 :   if (!reg)
    2436           0 :     return;
    2437             : 
    2438           6 :   if (mp->sw_if_index == ~0)
    2439             :     {
    2440             :     /* *INDENT-OFF* */
    2441           0 :     pool_foreach (swif, im->sw_interfaces)
    2442             :      {
    2443           0 :       send_acl_interface_etype_whitelist_details(am, reg, swif->sw_if_index, mp->context);
    2444             :     }
    2445             :     /* *INDENT-ON* */
    2446             :     }
    2447             :   else
    2448             :     {
    2449           6 :       sw_if_index = ntohl (mp->sw_if_index);
    2450           6 :       if (!pool_is_free_index (im->sw_interfaces, sw_if_index))
    2451           6 :         send_acl_interface_etype_whitelist_details (am, reg, sw_if_index,
    2452             :                                                     mp->context);
    2453             :     }
    2454             : }
    2455             : 
    2456             : static void
    2457           0 : vl_api_acl_plugin_use_hash_lookup_set_t_handler (
    2458             :   vl_api_acl_plugin_use_hash_lookup_set_t *mp)
    2459             : {
    2460           0 :   acl_main_t *am = &acl_main;
    2461             :   vl_api_acl_plugin_use_hash_lookup_set_reply_t *rmp;
    2462             :   vl_api_registration_t *reg;
    2463           0 :   int rv = 0;
    2464             : 
    2465           0 :   reg = vl_api_client_index_to_registration (mp->client_index);
    2466           0 :   if (!reg)
    2467           0 :     return;
    2468             : 
    2469           0 :   am->use_hash_acl_matching = mp->enable;
    2470           0 :   REPLY_MACRO (VL_API_ACL_PLUGIN_USE_HASH_LOOKUP_SET_REPLY);
    2471             : }
    2472             : 
    2473             : static void
    2474           0 : vl_api_acl_plugin_use_hash_lookup_get_t_handler (
    2475             :   vl_api_acl_plugin_use_hash_lookup_get_t *mp)
    2476             : {
    2477           0 :   acl_main_t *am = &acl_main;
    2478             :   vl_api_acl_plugin_use_hash_lookup_get_reply_t *rmp;
    2479           0 :   int msg_size = sizeof (*rmp);
    2480             :   vl_api_registration_t *reg;
    2481             : 
    2482           0 :   reg = vl_api_client_index_to_registration (mp->client_index);
    2483           0 :   if (!reg)
    2484           0 :     return;
    2485             : 
    2486           0 :   rmp = vl_msg_api_alloc (msg_size);
    2487           0 :   clib_memset (rmp, 0, msg_size);
    2488           0 :   rmp->_vl_msg_id =
    2489           0 :     ntohs (VL_API_ACL_PLUGIN_USE_HASH_LOOKUP_GET_REPLY + am->msg_id_base);
    2490           0 :   rmp->context = mp->context;
    2491           0 :   rmp->enable = am->use_hash_acl_matching;
    2492           0 :   vl_api_send_msg (reg, (u8 *) rmp);
    2493             : }
    2494             : 
    2495             : static void
    2496           1 : acl_set_timeout_sec (int timeout_type, u32 value)
    2497             : {
    2498           1 :   acl_main_t *am = &acl_main;
    2499           1 :   clib_time_t *ct = &am->vlib_main->clib_time;
    2500             : 
    2501           1 :   if (timeout_type < ACL_N_TIMEOUTS)
    2502             :     {
    2503           1 :       am->session_timeout_sec[timeout_type] = value;
    2504             :     }
    2505             :   else
    2506             :     {
    2507           0 :       clib_warning ("Unknown timeout type %d", timeout_type);
    2508           0 :       return;
    2509             :     }
    2510           1 :   am->session_timeout[timeout_type] =
    2511           1 :     (u64) (((f64) value) / ct->seconds_per_clock);
    2512             : }
    2513             : 
    2514             : static void
    2515           0 : acl_set_session_max_entries (u32 value)
    2516             : {
    2517           0 :   acl_main_t *am = &acl_main;
    2518           0 :   am->fa_conn_table_max_entries = value;
    2519           0 : }
    2520             : 
    2521             : static int
    2522           0 : acl_set_skip_ipv6_eh (u32 eh, u32 value)
    2523             : {
    2524           0 :   acl_main_t *am = &acl_main;
    2525             : 
    2526           0 :   if ((eh < 256) && (value < 2))
    2527             :     {
    2528           0 :       am->fa_ipv6_known_eh_bitmap =
    2529           0 :         clib_bitmap_set (am->fa_ipv6_known_eh_bitmap, eh, value);
    2530           0 :       return 1;
    2531             :     }
    2532             :   else
    2533           0 :     return 0;
    2534             : }
    2535             : 
    2536             : 
    2537             : static clib_error_t *
    2538       11597 : acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
    2539             : {
    2540       11597 :   acl_main_t *am = &acl_main;
    2541       11597 :   if (0 == is_add)
    2542             :     {
    2543        4179 :       int may_clear_sessions = 1;
    2544        4179 :       vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
    2545             :                                  ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX,
    2546             :                                  sw_if_index);
    2547             :       /* also unapply any ACLs in case the users did not do so. */
    2548        4179 :       macip_acl_interface_del_acl (am, sw_if_index);
    2549        4179 :       acl_interface_reset_inout_acls (sw_if_index, 0, &may_clear_sessions);
    2550        4179 :       acl_interface_reset_inout_acls (sw_if_index, 1, &may_clear_sessions);
    2551             :     }
    2552       11597 :   return 0;
    2553             : }
    2554             : 
    2555        2803 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
    2556             : 
    2557             : 
    2558             : 
    2559             : static clib_error_t *
    2560           1 : acl_set_aclplugin_fn (vlib_main_t * vm,
    2561             :                       unformat_input_t * input, vlib_cli_command_t * cmd)
    2562             : {
    2563           1 :   clib_error_t *error = 0;
    2564           1 :   u32 timeout = 0;
    2565           1 :   u32 val = 0;
    2566           1 :   u32 eh_val = 0;
    2567           1 :   uword memory_size = 0;
    2568           1 :   acl_main_t *am = &acl_main;
    2569             : 
    2570           1 :   if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val))
    2571             :     {
    2572           0 :       if (!acl_set_skip_ipv6_eh (eh_val, val))
    2573             :         {
    2574           0 :           error = clib_error_return (0, "expecting eh=0..255, value=0..1");
    2575             :         }
    2576           0 :       goto done;
    2577             :     }
    2578           1 :   if (unformat (input, "use-hash-acl-matching %u", &val))
    2579             :     {
    2580           0 :       am->use_hash_acl_matching = (val != 0);
    2581           0 :       goto done;
    2582             :     }
    2583           1 :   if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
    2584             :     {
    2585           0 :       am->l4_match_nonfirst_fragment = (val != 0);
    2586           0 :       goto done;
    2587             :     }
    2588           1 :   if (unformat (input, "reclassify-sessions %u", &val))
    2589             :     {
    2590           0 :       am->reclassify_sessions = (val != 0);
    2591           0 :       goto done;
    2592             :     }
    2593           1 :   if (unformat (input, "event-trace"))
    2594             :     {
    2595           0 :       if (!unformat (input, "%u", &val))
    2596             :         {
    2597           0 :           error = clib_error_return (0,
    2598             :                                      "expecting trace level, got `%U`",
    2599             :                                      format_unformat_error, input);
    2600           0 :           goto done;
    2601             :         }
    2602             :       else
    2603             :         {
    2604           0 :           am->trace_acl = val;
    2605           0 :           goto done;
    2606             :         }
    2607             :     }
    2608           1 :   if (unformat (input, "heap"))
    2609             :     {
    2610           0 :       if (unformat (input, "main"))
    2611             :         {
    2612           0 :           if (unformat (input, "validate %u", &val))
    2613           0 :             clib_warning ("ACL local heap is deprecated");
    2614           0 :           else if (unformat (input, "trace %u", &val))
    2615           0 :             clib_warning ("ACL local heap is deprecated");
    2616           0 :           goto done;
    2617             :         }
    2618           0 :       else if (unformat (input, "hash"))
    2619             :         {
    2620           0 :           if (unformat (input, "validate %u", &val))
    2621           0 :             clib_warning ("ACL local heap is deprecated");
    2622           0 :           else if (unformat (input, "trace %u", &val))
    2623           0 :             clib_warning ("ACL local heap is deprecated");
    2624           0 :           goto done;
    2625             :         }
    2626           0 :       goto done;
    2627             :     }
    2628           1 :   if (unformat (input, "session"))
    2629             :     {
    2630           1 :       if (unformat (input, "table"))
    2631             :         {
    2632             :           /* The commands here are for tuning/testing. No user-serviceable parts inside */
    2633           0 :           if (unformat (input, "max-entries"))
    2634             :             {
    2635           0 :               if (!unformat (input, "%u", &val))
    2636             :                 {
    2637           0 :                   error = clib_error_return (0,
    2638             :                                              "expecting maximum number of entries, got `%U`",
    2639             :                                              format_unformat_error, input);
    2640           0 :                   goto done;
    2641             :                 }
    2642             :               else
    2643             :                 {
    2644           0 :                   acl_set_session_max_entries (val);
    2645           0 :                   goto done;
    2646             :                 }
    2647             :             }
    2648           0 :           if (unformat (input, "hash-table-buckets"))
    2649             :             {
    2650           0 :               if (!unformat (input, "%u", &val))
    2651             :                 {
    2652           0 :                   error = clib_error_return (0,
    2653             :                                              "expecting maximum number of hash table buckets, got `%U`",
    2654             :                                              format_unformat_error, input);
    2655           0 :                   goto done;
    2656             :                 }
    2657             :               else
    2658             :                 {
    2659           0 :                   am->fa_conn_table_hash_num_buckets = val;
    2660           0 :                   goto done;
    2661             :                 }
    2662             :             }
    2663           0 :           if (unformat (input, "hash-table-memory"))
    2664             :             {
    2665           0 :               if (!unformat (input, "%U", unformat_memory_size, &memory_size))
    2666             :                 {
    2667           0 :                   error = clib_error_return (0,
    2668             :                                              "expecting maximum amount of hash table memory, got `%U`",
    2669             :                                              format_unformat_error, input);
    2670           0 :                   goto done;
    2671             :                 }
    2672             :               else
    2673             :                 {
    2674           0 :                   am->fa_conn_table_hash_memory_size = memory_size;
    2675           0 :                   goto done;
    2676             :                 }
    2677             :             }
    2678           0 :           if (unformat (input, "event-trace"))
    2679             :             {
    2680           0 :               if (!unformat (input, "%u", &val))
    2681             :                 {
    2682           0 :                   error = clib_error_return (0,
    2683             :                                              "expecting trace level, got `%U`",
    2684             :                                              format_unformat_error, input);
    2685           0 :                   goto done;
    2686             :                 }
    2687             :               else
    2688             :                 {
    2689           0 :                   am->trace_sessions = val;
    2690           0 :                   goto done;
    2691             :                 }
    2692             :             }
    2693           0 :           goto done;
    2694             :         }
    2695           1 :       if (unformat (input, "timeout"))
    2696             :         {
    2697           1 :           if (unformat (input, "udp"))
    2698             :             {
    2699           1 :               if (unformat (input, "idle"))
    2700             :                 {
    2701           1 :                   if (!unformat (input, "%u", &timeout))
    2702             :                     {
    2703           0 :                       error = clib_error_return (0,
    2704             :                                                  "expecting timeout value in seconds, got `%U`",
    2705             :                                                  format_unformat_error,
    2706             :                                                  input);
    2707           0 :                       goto done;
    2708             :                     }
    2709             :                   else
    2710             :                     {
    2711           1 :                       acl_set_timeout_sec (ACL_TIMEOUT_UDP_IDLE, timeout);
    2712           1 :                       goto done;
    2713             :                     }
    2714             :                 }
    2715             :             }
    2716           0 :           if (unformat (input, "tcp"))
    2717             :             {
    2718           0 :               if (unformat (input, "idle"))
    2719             :                 {
    2720           0 :                   if (!unformat (input, "%u", &timeout))
    2721             :                     {
    2722           0 :                       error = clib_error_return (0,
    2723             :                                                  "expecting timeout value in seconds, got `%U`",
    2724             :                                                  format_unformat_error,
    2725             :                                                  input);
    2726           0 :                       goto done;
    2727             :                     }
    2728             :                   else
    2729             :                     {
    2730           0 :                       acl_set_timeout_sec (ACL_TIMEOUT_TCP_IDLE, timeout);
    2731           0 :                       goto done;
    2732             :                     }
    2733             :                 }
    2734           0 :               if (unformat (input, "transient"))
    2735             :                 {
    2736           0 :                   if (!unformat (input, "%u", &timeout))
    2737             :                     {
    2738           0 :                       error = clib_error_return (0,
    2739             :                                                  "expecting timeout value in seconds, got `%U`",
    2740             :                                                  format_unformat_error,
    2741             :                                                  input);
    2742           0 :                       goto done;
    2743             :                     }
    2744             :                   else
    2745             :                     {
    2746           0 :                       acl_set_timeout_sec (ACL_TIMEOUT_TCP_TRANSIENT,
    2747             :                                            timeout);
    2748           0 :                       goto done;
    2749             :                     }
    2750             :                 }
    2751             :             }
    2752           0 :           goto done;
    2753             :         }
    2754             :     }
    2755           0 : done:
    2756           1 :   return error;
    2757             : }
    2758             : 
    2759             : static u8 *
    2760       23904 : my_format_mac_address (u8 * s, va_list * args)
    2761             : {
    2762       23904 :   u8 *a = va_arg (*args, u8 *);
    2763       47808 :   return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
    2764       23904 :                  a[0], a[1], a[2], a[3], a[4], a[5]);
    2765             : }
    2766             : 
    2767             : static inline u8 *
    2768       11952 : my_macip_acl_rule_t_pretty_format (u8 * out, va_list * args)
    2769             : {
    2770       11952 :   macip_acl_rule_t *a = va_arg (*args, macip_acl_rule_t *);
    2771             : 
    2772       23904 :   out = format (out, "%s action %d ip %U/%d mac %U mask %U",
    2773       11952 :                 a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit,
    2774             :                 format_ip46_address, &a->src_ip_addr,
    2775       11952 :                 a->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
    2776       11952 :                 a->src_prefixlen,
    2777       11952 :                 my_format_mac_address, a->src_mac,
    2778       11952 :                 my_format_mac_address, a->src_mac_mask);
    2779       11952 :   return (out);
    2780             : }
    2781             : 
    2782             : static void
    2783         138 : macip_acl_print (acl_main_t * am, u32 macip_acl_index)
    2784             : {
    2785         138 :   vlib_main_t *vm = am->vlib_main;
    2786             :   int i;
    2787             : 
    2788             :   /* Don't try to print someone else's memory */
    2789         138 :   if (macip_acl_index >= vec_len (am->macip_acls))
    2790           0 :     return;
    2791             : 
    2792         138 :   macip_acl_list_t *a = vec_elt_at_index (am->macip_acls, macip_acl_index);
    2793         138 :   int free_pool_slot = pool_is_free_index (am->macip_acls, macip_acl_index);
    2794             : 
    2795         138 :   vlib_cli_output (vm,
    2796             :                    "MACIP acl_index: %d, count: %d (true len %d) tag {%s} is free pool slot: %d\n",
    2797         138 :                    macip_acl_index, a->count, vec_len (a->rules), a->tag,
    2798             :                    free_pool_slot);
    2799         138 :   vlib_cli_output (vm,
    2800             :                    "  ip4_table_index %d, ip6_table_index %d, l2_table_index %d\n",
    2801             :                    a->ip4_table_index, a->ip6_table_index, a->l2_table_index);
    2802         138 :   vlib_cli_output (vm,
    2803             :                    "  out_ip4_table_index %d, out_ip6_table_index %d, out_l2_table_index %d\n",
    2804             :                    a->out_ip4_table_index, a->out_ip6_table_index,
    2805             :                    a->out_l2_table_index);
    2806       12090 :   for (i = 0; i < vec_len (a->rules); i++)
    2807       11952 :     vlib_cli_output (vm, "    rule %d: %U\n", i,
    2808             :                      my_macip_acl_rule_t_pretty_format,
    2809       11952 :                      vec_elt_at_index (a->rules, i));
    2810             : 
    2811             : }
    2812             : 
    2813             : static clib_error_t *
    2814           0 : acl_set_aclplugin_interface_fn (vlib_main_t * vm,
    2815             :                                 unformat_input_t * input,
    2816             :                                 vlib_cli_command_t * cmd)
    2817             : {
    2818           0 :   unformat_input_t _line_input, *line_input = &_line_input;
    2819             :   u32 sw_if_index, is_add, is_input, acl_index;
    2820             : 
    2821           0 :   is_add = is_input = 1;
    2822           0 :   acl_index = sw_if_index = ~0;
    2823             : 
    2824           0 :   if (!unformat_user (input, unformat_line_input, line_input))
    2825           0 :     return 0;
    2826             : 
    2827           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    2828             :     {
    2829           0 :       if (unformat (line_input, "%U",
    2830             :                     unformat_vnet_sw_interface, vnet_get_main (),
    2831             :                     &sw_if_index))
    2832             :         ;
    2833           0 :       else if (unformat (line_input, "add"))
    2834           0 :         is_add = 1;
    2835           0 :       else if (unformat (line_input, "del"))
    2836           0 :         is_add = 0;
    2837           0 :       else if (unformat (line_input, "acl %d", &acl_index))
    2838             :         ;
    2839           0 :       else if (unformat (line_input, "input"))
    2840           0 :         is_input = 1;
    2841           0 :       else if (unformat (line_input, "output"))
    2842           0 :         is_input = 0;
    2843             :       else
    2844           0 :         break;
    2845             :     }
    2846             : 
    2847           0 :   unformat_free (line_input);
    2848           0 :   if (~0 == sw_if_index)
    2849           0 :     return (clib_error_return (0, "invalid interface"));
    2850           0 :   if (~0 == acl_index)
    2851           0 :     return (clib_error_return (0, "invalid acl"));
    2852             : 
    2853           0 :   acl_interface_add_del_inout_acl (sw_if_index, is_add, is_input, acl_index);
    2854             : 
    2855           0 :   return (NULL);
    2856             : }
    2857             : 
    2858             : #define vec_validate_acl_rules(v, idx) \
    2859             :   do {                                 \
    2860             :     if (vec_len(v) < idx+1) {  \
    2861             :       vec_validate(v, idx); \
    2862             :       v[idx].is_permit = 0x1; \
    2863             :       v[idx].srcport_or_icmptype_last = 0xffff; \
    2864             :       v[idx].dstport_or_icmpcode_last = 0xffff; \
    2865             :     } \
    2866             :   } while (0)
    2867             : 
    2868             : static clib_error_t *
    2869           0 : acl_set_aclplugin_acl_fn (vlib_main_t * vm,
    2870             :                           unformat_input_t * input, vlib_cli_command_t * cmd)
    2871             : {
    2872           0 :   unformat_input_t _line_input, *line_input = &_line_input;
    2873           0 :   vl_api_acl_rule_t *rules = 0;
    2874             :   int rv;
    2875           0 :   int rule_idx = 0;
    2876           0 :   int n_rules_override = -1;
    2877           0 :   u32 acl_index = ~0;
    2878           0 :   u32 proto = 0;
    2879           0 :   u32 port1 = 0;
    2880           0 :   u32 port2 = 0;
    2881           0 :   u32 action = 0;
    2882             :   u32 tcpflags, tcpmask;
    2883             :   ip_prefix_t src, dst;
    2884           0 :   u8 *tag = 0;
    2885             : 
    2886           0 :   if (!unformat_user (input, unformat_line_input, line_input))
    2887           0 :     return 0;
    2888             : 
    2889           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    2890             :     {
    2891           0 :       if (unformat (line_input, "index %d", &acl_index))
    2892             :         {
    2893             :           /* operate on this acl index (which must exist),
    2894             :            * If not specified, or set to -1, create a new ACL
    2895             :            */
    2896             :         }
    2897           0 :       else if (unformat (line_input, "permit+reflect"))
    2898             :         {
    2899           0 :           vec_validate_acl_rules (rules, rule_idx);
    2900           0 :           rules[rule_idx].is_permit = 2;
    2901             :         }
    2902           0 :       else if (unformat (line_input, "permit"))
    2903             :         {
    2904           0 :           vec_validate_acl_rules (rules, rule_idx);
    2905           0 :           rules[rule_idx].is_permit = 1;
    2906             :         }
    2907           0 :       else if (unformat (line_input, "deny"))
    2908             :         {
    2909           0 :           vec_validate_acl_rules (rules, rule_idx);
    2910           0 :           rules[rule_idx].is_permit = 0;
    2911             :         }
    2912           0 :       else if (unformat (line_input, "count %d", &n_rules_override))
    2913             :         {
    2914             :           /* we will use this later */
    2915             :         }
    2916           0 :       else if (unformat (line_input, "action %d", &action))
    2917             :         {
    2918           0 :           vec_validate_acl_rules (rules, rule_idx);
    2919           0 :           rules[rule_idx].is_permit = action;
    2920             :         }
    2921           0 :       else if (unformat (line_input, "src %U", unformat_ip_prefix, &src))
    2922             :         {
    2923           0 :           vec_validate_acl_rules (rules, rule_idx);
    2924           0 :           ip_prefix_encode2 (&src, &rules[rule_idx].src_prefix);
    2925             :         }
    2926           0 :       else if (unformat (line_input, "dst %U", unformat_ip_prefix, &dst))
    2927             :         {
    2928           0 :           vec_validate_acl_rules (rules, rule_idx);
    2929           0 :           ip_prefix_encode2 (&dst, &rules[rule_idx].dst_prefix);
    2930             :         }
    2931           0 :       else if (unformat (line_input, "sport %d-%d", &port1, &port2))
    2932             :         {
    2933           0 :           vec_validate_acl_rules (rules, rule_idx);
    2934           0 :           rules[rule_idx].srcport_or_icmptype_first = htons (port1);
    2935           0 :           rules[rule_idx].srcport_or_icmptype_last = htons (port2);
    2936             :         }
    2937           0 :       else if (unformat (line_input, "sport %d", &port1))
    2938             :         {
    2939           0 :           vec_validate_acl_rules (rules, rule_idx);
    2940           0 :           rules[rule_idx].srcport_or_icmptype_first = htons (port1);
    2941           0 :           rules[rule_idx].srcport_or_icmptype_last = htons (port1);
    2942             :         }
    2943           0 :       else if (unformat (line_input, "dport %d-%d", &port1, &port2))
    2944             :         {
    2945           0 :           vec_validate_acl_rules (rules, rule_idx);
    2946           0 :           rules[rule_idx].dstport_or_icmpcode_first = htons (port1);
    2947           0 :           rules[rule_idx].dstport_or_icmpcode_last = htons (port2);
    2948             :         }
    2949           0 :       else if (unformat (line_input, "dport %d", &port1))
    2950             :         {
    2951           0 :           vec_validate_acl_rules (rules, rule_idx);
    2952           0 :           rules[rule_idx].dstport_or_icmpcode_first = htons (port1);
    2953           0 :           rules[rule_idx].dstport_or_icmpcode_last = htons (port1);
    2954             :         }
    2955           0 :       else if (unformat (line_input, "tcpflags %d %d", &tcpflags, &tcpmask))
    2956             :         {
    2957           0 :           vec_validate_acl_rules (rules, rule_idx);
    2958           0 :           rules[rule_idx].tcp_flags_value = tcpflags;
    2959           0 :           rules[rule_idx].tcp_flags_mask = tcpmask;
    2960             :         }
    2961             :       else
    2962           0 :         if (unformat (line_input, "tcpflags %d mask %d", &tcpflags, &tcpmask))
    2963             :         {
    2964           0 :           vec_validate_acl_rules (rules, rule_idx);
    2965           0 :           rules[rule_idx].tcp_flags_value = tcpflags;
    2966           0 :           rules[rule_idx].tcp_flags_mask = tcpmask;
    2967             :         }
    2968           0 :       else if (unformat (line_input, "proto %d", &proto))
    2969             :         {
    2970           0 :           vec_validate_acl_rules (rules, rule_idx);
    2971           0 :           rules[rule_idx].proto = proto;
    2972             :         }
    2973           0 :       else if (unformat (line_input, "tag %s", &tag))
    2974             :         {
    2975             :         }
    2976           0 :       else if (unformat (line_input, ","))
    2977             :         {
    2978           0 :           rule_idx++;
    2979           0 :           vec_validate_acl_rules (rules, rule_idx);
    2980             :         }
    2981             :       else
    2982           0 :         break;
    2983             :     }
    2984             : 
    2985           0 :   if (!tag)
    2986           0 :     vec_add (tag, "cli", 4);
    2987             : 
    2988           0 :   rv = acl_add_list (vec_len (rules), rules, &acl_index, tag);
    2989             : 
    2990           0 :   vec_free (rules);
    2991           0 :   vec_free (tag);
    2992             : 
    2993           0 :   unformat_free (line_input);
    2994           0 :   if (rv)
    2995           0 :     return (clib_error_return (0, "failed"));
    2996             : 
    2997           0 :   vlib_cli_output (vm, "ACL index:%d", acl_index);
    2998             : 
    2999           0 :   return (NULL);
    3000             : }
    3001             : 
    3002             : static clib_error_t *
    3003           0 : acl_delete_aclplugin_acl_fn (vlib_main_t *vm, unformat_input_t *input,
    3004             :                              vlib_cli_command_t *cmd)
    3005             : {
    3006           0 :   unformat_input_t _line_input, *line_input = &_line_input;
    3007             :   int rv;
    3008           0 :   u32 acl_index = ~0;
    3009             : 
    3010           0 :   if (!unformat_user (input, unformat_line_input, line_input))
    3011           0 :     return 0;
    3012             : 
    3013           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    3014             :     {
    3015           0 :       if (unformat (line_input, "index %d", &acl_index))
    3016             :         {
    3017             :           /* operate on this acl index (which must exist) */
    3018             :         }
    3019             :       else
    3020           0 :         break;
    3021             :     }
    3022             : 
    3023           0 :   rv = acl_del_list (acl_index);
    3024             : 
    3025           0 :   unformat_free (line_input);
    3026           0 :   if (rv)
    3027           0 :     return (clib_error_return (0, "failed"));
    3028             : 
    3029           0 :   vlib_cli_output (vm, "Deleted ACL index:%d", acl_index);
    3030           0 :   return (NULL);
    3031             : }
    3032             : 
    3033             : static clib_error_t *
    3034          66 : acl_show_aclplugin_macip_acl_fn (vlib_main_t * vm,
    3035             :                                  unformat_input_t *
    3036             :                                  input, vlib_cli_command_t * cmd)
    3037             : {
    3038          66 :   clib_error_t *error = 0;
    3039          66 :   acl_main_t *am = &acl_main;
    3040             :   int i;
    3041          66 :   u32 acl_index = ~0;
    3042             : 
    3043          66 :   (void) unformat (input, "index %u", &acl_index);
    3044             : 
    3045         459 :   for (i = 0; i < vec_len (am->macip_acls); i++)
    3046             :     {
    3047             :       /* Don't attempt to show the ACLs that do not exist */
    3048         393 :       if (pool_is_free_index (am->macip_acls, i))
    3049         239 :         continue;
    3050             : 
    3051         154 :       if ((acl_index != ~0) && (acl_index != i))
    3052             :         {
    3053          16 :           continue;
    3054             :         }
    3055             : 
    3056         138 :       macip_acl_print (am, i);
    3057         138 :       if (i < vec_len (am->sw_if_index_vec_by_macip_acl))
    3058             :         {
    3059         120 :           vlib_cli_output (vm, "  applied on sw_if_index(s): %U\n",
    3060             :                            format_vec32,
    3061         120 :                            vec_elt (am->sw_if_index_vec_by_macip_acl, i),
    3062             :                            "%d");
    3063             :         }
    3064             :     }
    3065             : 
    3066          66 :   return error;
    3067             : }
    3068             : 
    3069             : static clib_error_t *
    3070          63 : acl_show_aclplugin_macip_interface_fn (vlib_main_t * vm,
    3071             :                                        unformat_input_t *
    3072             :                                        input, vlib_cli_command_t * cmd)
    3073             : {
    3074          63 :   clib_error_t *error = 0;
    3075          63 :   acl_main_t *am = &acl_main;
    3076             :   int i;
    3077         241 :   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
    3078             :     {
    3079         178 :       vlib_cli_output (vm, "  sw_if_index %d: %d\n", i,
    3080         178 :                        vec_elt (am->macip_acl_by_sw_if_index, i));
    3081             :     }
    3082          63 :   return error;
    3083             : }
    3084             : 
    3085             : static void
    3086         140 : acl_plugin_show_acl (acl_main_t * am, u32 acl_index)
    3087             : {
    3088             :   u32 i;
    3089         140 :   vlib_main_t *vm = am->vlib_main;
    3090             : 
    3091         488 :   for (i = 0; i < vec_len (am->acls); i++)
    3092             :     {
    3093         348 :       if (acl_is_not_defined (am, i))
    3094             :         {
    3095             :           /* don't attempt to show the ACLs that do not exist */
    3096         185 :           continue;
    3097             :         }
    3098         163 :       if ((acl_index != ~0) && (acl_index != i))
    3099             :         {
    3100           0 :           continue;
    3101             :         }
    3102         163 :       acl_print_acl (vm, am, i);
    3103             : 
    3104         163 :       if (i < vec_len (am->input_sw_if_index_vec_by_acl))
    3105             :         {
    3106         163 :           vlib_cli_output (vm, "  applied inbound on sw_if_index: %U\n",
    3107         163 :                            format_vec32, am->input_sw_if_index_vec_by_acl[i],
    3108             :                            "%d");
    3109             :         }
    3110         163 :       if (i < vec_len (am->output_sw_if_index_vec_by_acl))
    3111             :         {
    3112         163 :           vlib_cli_output (vm, "  applied outbound on sw_if_index: %U\n",
    3113         163 :                            format_vec32, am->output_sw_if_index_vec_by_acl[i],
    3114             :                            "%d");
    3115             :         }
    3116         163 :       if (i < vec_len (am->lc_index_vec_by_acl))
    3117             :         {
    3118         163 :           vlib_cli_output (vm, "  used in lookup context index: %U\n",
    3119         163 :                            format_vec32, am->lc_index_vec_by_acl[i], "%d");
    3120             :         }
    3121             :     }
    3122         140 : }
    3123             : 
    3124             : static clib_error_t *
    3125         140 : acl_show_aclplugin_acl_fn (vlib_main_t * vm,
    3126             :                            unformat_input_t * input, vlib_cli_command_t * cmd)
    3127             : {
    3128         140 :   clib_error_t *error = 0;
    3129         140 :   acl_main_t *am = &acl_main;
    3130             : 
    3131         140 :   u32 acl_index = ~0;
    3132         140 :   (void) unformat (input, "index %u", &acl_index);
    3133             : 
    3134         140 :   acl_plugin_show_acl (am, acl_index);
    3135         140 :   return error;
    3136             : }
    3137             : 
    3138             : static clib_error_t *
    3139           0 : acl_show_aclplugin_lookup_context_fn (vlib_main_t * vm,
    3140             :                                       unformat_input_t * input,
    3141             :                                       vlib_cli_command_t * cmd)
    3142             : {
    3143           0 :   clib_error_t *error = 0;
    3144             : 
    3145           0 :   u32 lc_index = ~0;
    3146           0 :   (void) unformat (input, "index %u", &lc_index);
    3147             : 
    3148           0 :   acl_plugin_show_lookup_context (lc_index);
    3149           0 :   return error;
    3150             : }
    3151             : 
    3152             : static clib_error_t *
    3153           0 : acl_show_aclplugin_lookup_user_fn (vlib_main_t * vm,
    3154             :                                    unformat_input_t * input,
    3155             :                                    vlib_cli_command_t * cmd)
    3156             : {
    3157           0 :   clib_error_t *error = 0;
    3158             : 
    3159           0 :   u32 lc_index = ~0;
    3160           0 :   (void) unformat (input, "index %u", &lc_index);
    3161             : 
    3162           0 :   acl_plugin_show_lookup_user (lc_index);
    3163           0 :   return error;
    3164             : }
    3165             : 
    3166             : 
    3167             : static void
    3168         138 : acl_plugin_show_interface (acl_main_t * am, u32 sw_if_index, int show_acl,
    3169             :                            int detail)
    3170             : {
    3171         138 :   vlib_main_t *vm = am->vlib_main;
    3172             :   u32 swi;
    3173             :   u32 *pj;
    3174         657 :   for (swi = 0; (swi < vec_len (am->input_acl_vec_by_sw_if_index)) ||
    3175         519 :        (swi < vec_len (am->output_acl_vec_by_sw_if_index)); swi++)
    3176             :     {
    3177             :       /* if we need a particular interface, skip all the others */
    3178         381 :       if ((sw_if_index != ~0) && (sw_if_index != swi))
    3179           0 :         continue;
    3180             : 
    3181         381 :       vlib_cli_output (vm, "sw_if_index %d:\n", swi);
    3182         381 :       if (swi < vec_len (am->input_policy_epoch_by_sw_if_index))
    3183           0 :         vlib_cli_output (vm, "   input policy epoch: %x\n",
    3184           0 :                          vec_elt (am->input_policy_epoch_by_sw_if_index,
    3185             :                                   swi));
    3186         381 :       if (swi < vec_len (am->output_policy_epoch_by_sw_if_index))
    3187           0 :         vlib_cli_output (vm, "   output policy epoch: %x\n",
    3188           0 :                          vec_elt (am->output_policy_epoch_by_sw_if_index,
    3189             :                                   swi));
    3190             : 
    3191             : 
    3192         381 :       if (intf_has_etype_whitelist (am, swi, 1))
    3193             :         {
    3194           0 :           vlib_cli_output (vm, "  input etype whitelist: %U", format_vec16,
    3195           0 :                            am->input_etype_whitelist_by_sw_if_index[swi],
    3196             :                            "%04x");
    3197             :         }
    3198         381 :       if (intf_has_etype_whitelist (am, swi, 0))
    3199             :         {
    3200           0 :           vlib_cli_output (vm, " output etype whitelist: %U", format_vec16,
    3201           0 :                            am->output_etype_whitelist_by_sw_if_index[swi],
    3202             :                            "%04x");
    3203             :         }
    3204             : 
    3205         381 :       if ((swi < vec_len (am->input_acl_vec_by_sw_if_index)) &&
    3206         381 :           (vec_len (am->input_acl_vec_by_sw_if_index[swi]) > 0))
    3207             :         {
    3208         158 :           vlib_cli_output (vm, "  input acl(s): %U", format_vec32,
    3209         158 :                            am->input_acl_vec_by_sw_if_index[swi], "%d");
    3210         158 :           if (show_acl)
    3211             :             {
    3212           0 :               vlib_cli_output (vm, "\n");
    3213           0 :               vec_foreach (pj, am->input_acl_vec_by_sw_if_index[swi])
    3214             :               {
    3215           0 :                 acl_print_acl (vm, am, *pj);
    3216             :               }
    3217           0 :               vlib_cli_output (vm, "\n");
    3218             :             }
    3219             :         }
    3220             : 
    3221         381 :       if ((swi < vec_len (am->output_acl_vec_by_sw_if_index)) &&
    3222         381 :           (vec_len (am->output_acl_vec_by_sw_if_index[swi]) > 0))
    3223             :         {
    3224          96 :           vlib_cli_output (vm, "  output acl(s): %U", format_vec32,
    3225          96 :                            am->output_acl_vec_by_sw_if_index[swi], "%d");
    3226          96 :           if (show_acl)
    3227             :             {
    3228           0 :               vlib_cli_output (vm, "\n");
    3229           0 :               vec_foreach (pj, am->output_acl_vec_by_sw_if_index[swi])
    3230             :               {
    3231           0 :                 acl_print_acl (vm, am, *pj);
    3232             :               }
    3233           0 :               vlib_cli_output (vm, "\n");
    3234             :             }
    3235             :         }
    3236         381 :       if (detail && (swi < vec_len (am->input_lc_index_by_sw_if_index)))
    3237             :         {
    3238           0 :           vlib_cli_output (vm, "   input lookup context index: %d",
    3239           0 :                            am->input_lc_index_by_sw_if_index[swi]);
    3240             :         }
    3241         381 :       if (detail && (swi < vec_len (am->output_lc_index_by_sw_if_index)))
    3242             :         {
    3243           0 :           vlib_cli_output (vm, "  output lookup context index: %d",
    3244           0 :                            am->output_lc_index_by_sw_if_index[swi]);
    3245             :         }
    3246             :     }
    3247             : 
    3248         138 : }
    3249             : 
    3250             : 
    3251             : static clib_error_t *
    3252           0 : acl_show_aclplugin_decode_5tuple_fn (vlib_main_t * vm,
    3253             :                                      unformat_input_t * input,
    3254             :                                      vlib_cli_command_t * cmd)
    3255             : {
    3256           0 :   clib_error_t *error = 0;
    3257           0 :   u64 five_tuple[6] = { 0, 0, 0, 0, 0, 0 };
    3258             : 
    3259           0 :   if (unformat
    3260             :       (input, "%llx %llx %llx %llx %llx %llx", &five_tuple[0], &five_tuple[1],
    3261             :        &five_tuple[2], &five_tuple[3], &five_tuple[4], &five_tuple[5]))
    3262           0 :     vlib_cli_output (vm, "5-tuple structure decode: %U\n\n",
    3263             :                      format_acl_plugin_5tuple, five_tuple);
    3264             :   else
    3265           0 :     error = clib_error_return (0, "expecting 6 hex integers");
    3266           0 :   return error;
    3267             : }
    3268             : 
    3269             : 
    3270             : static clib_error_t *
    3271         138 : acl_show_aclplugin_interface_fn (vlib_main_t * vm,
    3272             :                                  unformat_input_t *
    3273             :                                  input, vlib_cli_command_t * cmd)
    3274             : {
    3275         138 :   clib_error_t *error = 0;
    3276         138 :   acl_main_t *am = &acl_main;
    3277             : 
    3278         138 :   u32 sw_if_index = ~0;
    3279         138 :   (void) unformat (input, "sw_if_index %u", &sw_if_index);
    3280         138 :   int show_acl = unformat (input, "acl");
    3281         138 :   int detail = unformat (input, "detail");
    3282             : 
    3283         138 :   acl_plugin_show_interface (am, sw_if_index, show_acl, detail);
    3284         138 :   return error;
    3285             : }
    3286             : 
    3287             : static clib_error_t *
    3288           0 : acl_show_aclplugin_memory_fn (vlib_main_t * vm,
    3289             :                               unformat_input_t * input,
    3290             :                               vlib_cli_command_t * cmd)
    3291             : {
    3292           0 :   clib_error_t *error = 0;
    3293           0 :   vlib_cli_output (vm, "ACL memory is now part of the main heap");
    3294           0 :   return error;
    3295             : }
    3296             : 
    3297             : static void
    3298          41 : acl_plugin_show_sessions (acl_main_t * am,
    3299             :                           u32 show_session_thread_id,
    3300             :                           u32 show_session_session_index)
    3301             : {
    3302          41 :   vlib_main_t *vm = am->vlib_main;
    3303             :   u16 wk;
    3304          41 :   vnet_interface_main_t *im = &am->vnet_main->interface_main;
    3305             :   vnet_sw_interface_t *swif;
    3306          41 :   u64 now = clib_cpu_time_now ();
    3307          41 :   u64 clocks_per_second = am->vlib_main->clib_time.clocks_per_second;
    3308             : 
    3309             :   {
    3310          41 :     u64 n_adds = am->fa_session_total_adds;
    3311          41 :     u64 n_dels = am->fa_session_total_dels;
    3312          41 :     u64 n_deact = am->fa_session_total_deactivations;
    3313          41 :     vlib_cli_output (vm, "Sessions total: add %lu - del %lu = %lu", n_adds,
    3314             :                      n_dels, n_adds - n_dels);
    3315          41 :     vlib_cli_output (vm, "Sessions active: add %lu - deact %lu = %lu", n_adds,
    3316             :                      n_deact, n_adds - n_deact);
    3317          41 :     vlib_cli_output (vm, "Sessions being purged: deact %lu - del %lu = %lu",
    3318             :                      n_deact, n_dels, n_deact - n_dels);
    3319             :   }
    3320          41 :   vlib_cli_output (vm, "now: %lu clocks per second: %lu", now,
    3321             :                    clocks_per_second);
    3322          41 :   vlib_cli_output (vm, "\n\nPer-thread data:");
    3323          82 :   for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
    3324             :     {
    3325          41 :       acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
    3326          41 :       vlib_cli_output (vm, "Thread #%d:", wk);
    3327          41 :       if (show_session_thread_id == wk
    3328           0 :           && show_session_session_index < pool_len (pw->fa_sessions_pool))
    3329             :         {
    3330           0 :           vlib_cli_output (vm, "  session index %u:",
    3331             :                            show_session_session_index);
    3332           0 :           fa_session_t *sess =
    3333           0 :             pw->fa_sessions_pool + show_session_session_index;
    3334           0 :           u64 *m = (u64 *) & sess->info;
    3335           0 :           vlib_cli_output (vm,
    3336             :                            "    info: %016llx %016llx %016llx %016llx %016llx %016llx",
    3337           0 :                            m[0], m[1], m[2], m[3], m[4], m[5]);
    3338           0 :           vlib_cli_output (vm, "    sw_if_index: %u", sess->sw_if_index);
    3339           0 :           vlib_cli_output (vm, "    tcp_flags_seen: %x",
    3340           0 :                            sess->tcp_flags_seen.as_u16);
    3341           0 :           vlib_cli_output (vm, "    last active time: %lu",
    3342             :                            sess->last_active_time);
    3343           0 :           vlib_cli_output (vm, "    thread index: %u", sess->thread_index);
    3344           0 :           vlib_cli_output (vm, "    link enqueue time: %lu",
    3345             :                            sess->link_enqueue_time);
    3346           0 :           vlib_cli_output (vm, "    link next index: %u",
    3347             :                            sess->link_next_idx);
    3348           0 :           vlib_cli_output (vm, "    link prev index: %u",
    3349             :                            sess->link_prev_idx);
    3350           0 :           vlib_cli_output (vm, "    link list id: %u", sess->link_list_id);
    3351             :         }
    3352          41 :       vlib_cli_output (vm, "  connection add/del stats:", wk);
    3353             :       /* *INDENT-OFF* */
    3354         246 :       pool_foreach (swif, im->sw_interfaces)
    3355             :          {
    3356         205 :           u32 sw_if_index = swif->sw_if_index;
    3357         205 :           u64 n_adds =
    3358         205 :             (sw_if_index < vec_len (pw->fa_session_adds_by_sw_if_index) ?
    3359         205 :              pw->fa_session_adds_by_sw_if_index[sw_if_index] :
    3360             :              0);
    3361         205 :           u64 n_dels =
    3362         205 :             (sw_if_index < vec_len (pw->fa_session_dels_by_sw_if_index) ?
    3363         205 :              pw->fa_session_dels_by_sw_if_index[sw_if_index] :
    3364             :              0);
    3365         205 :           u64 n_epoch_changes =
    3366         205 :             (sw_if_index < vec_len (pw->fa_session_epoch_change_by_sw_if_index) ?
    3367         205 :              pw->fa_session_epoch_change_by_sw_if_index[sw_if_index] :
    3368             :              0);
    3369         205 :           vlib_cli_output (vm,
    3370             :                            "    sw_if_index %d: add %lu - del %lu = %lu; epoch chg: %lu",
    3371             :                            sw_if_index,
    3372             :                            n_adds,
    3373             :                            n_dels,
    3374             :                            n_adds -
    3375             :                            n_dels,
    3376             :                            n_epoch_changes);
    3377             :         }
    3378             :       /* *INDENT-ON* */
    3379             : 
    3380          41 :       vlib_cli_output (vm, "  connection timeout type lists:", wk);
    3381          41 :       u8 tt = 0;
    3382         246 :       for (tt = 0; tt < ACL_N_TIMEOUTS; tt++)
    3383             :         {
    3384         205 :           u32 head_session_index = pw->fa_conn_list_head[tt];
    3385         205 :           vlib_cli_output (vm, "  fa_conn_list_head[%d]: %d", tt,
    3386             :                            head_session_index);
    3387         205 :           if (~0 != head_session_index)
    3388             :             {
    3389          24 :               fa_session_t *sess = pw->fa_sessions_pool + head_session_index;
    3390          24 :               vlib_cli_output (vm, "    last active time: %lu",
    3391             :                                sess->last_active_time);
    3392          24 :               vlib_cli_output (vm, "    link enqueue time: %lu",
    3393             :                                sess->link_enqueue_time);
    3394             :             }
    3395             :         }
    3396             : 
    3397          41 :       vlib_cli_output (vm, "  Next expiry time: %lu", pw->next_expiry_time);
    3398          41 :       vlib_cli_output (vm, "  Requeue until time: %lu",
    3399             :                        pw->requeue_until_time);
    3400          41 :       vlib_cli_output (vm, "  Current time wait interval: %lu",
    3401             :                        pw->current_time_wait_interval);
    3402          41 :       vlib_cli_output (vm, "  Count of deleted sessions: %lu",
    3403             :                        pw->cnt_deleted_sessions);
    3404          41 :       vlib_cli_output (vm, "  Delete already deleted: %lu",
    3405             :                        pw->cnt_already_deleted_sessions);
    3406          41 :       vlib_cli_output (vm, "  Session timers restarted: %lu",
    3407             :                        pw->cnt_session_timer_restarted);
    3408          41 :       vlib_cli_output (vm, "  Swipe until this time: %lu",
    3409             :                        pw->swipe_end_time);
    3410          41 :       vlib_cli_output (vm, "  sw_if_index serviced bitmap: %U",
    3411             :                        format_bitmap_hex, pw->serviced_sw_if_index_bitmap);
    3412          41 :       vlib_cli_output (vm, "  pending clear intfc bitmap : %U",
    3413             :                        format_bitmap_hex,
    3414             :                        pw->pending_clear_sw_if_index_bitmap);
    3415          41 :       vlib_cli_output (vm, "  clear in progress: %u", pw->clear_in_process);
    3416          41 :       vlib_cli_output (vm, "  interrupt is pending: %d",
    3417             :                        pw->interrupt_is_pending);
    3418          41 :       vlib_cli_output (vm, "  interrupt is needed: %d",
    3419             :                        pw->interrupt_is_needed);
    3420          41 :       vlib_cli_output (vm, "  interrupt is unwanted: %d",
    3421             :                        pw->interrupt_is_unwanted);
    3422          41 :       vlib_cli_output (vm, "  interrupt generation: %d",
    3423             :                        pw->interrupt_generation);
    3424          41 :       vlib_cli_output (vm, "  received session change requests: %d",
    3425             :                        pw->rcvd_session_change_requests);
    3426          41 :       vlib_cli_output (vm, "  sent session change requests: %d",
    3427             :                        pw->sent_session_change_requests);
    3428             :     }
    3429          41 :   vlib_cli_output (vm, "\n\nConn cleaner thread counters:");
    3430             : #define _(cnt, desc) vlib_cli_output(vm, "             %20lu: %s", am->cnt, desc);
    3431          41 :   foreach_fa_cleaner_counter;
    3432             : #undef _
    3433          41 :   vlib_cli_output (vm, "Interrupt generation: %d",
    3434             :                    am->fa_interrupt_generation);
    3435          41 :   vlib_cli_output (vm,
    3436             :                    "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
    3437             :                    am->fa_min_deleted_sessions_per_interval,
    3438             :                    am->fa_max_deleted_sessions_per_interval,
    3439          41 :                    am->fa_cleaner_wait_time_increment * 1000.0,
    3440          41 :                    ((f64) am->fa_current_cleaner_timer_wait_interval) *
    3441          41 :                    1000.0 / (f64) vm->clib_time.clocks_per_second);
    3442          41 :   vlib_cli_output (vm, "Reclassify sessions: %d", am->reclassify_sessions);
    3443          41 : }
    3444             : 
    3445             : static clib_error_t *
    3446          41 : acl_show_aclplugin_sessions_fn (vlib_main_t * vm,
    3447             :                                 unformat_input_t * input,
    3448             :                                 vlib_cli_command_t * cmd)
    3449             : {
    3450          41 :   clib_error_t *error = 0;
    3451          41 :   acl_main_t *am = &acl_main;
    3452             : 
    3453          41 :   u32 show_bihash_verbose = 0;
    3454          41 :   u32 show_session_thread_id = ~0;
    3455          41 :   u32 show_session_session_index = ~0;
    3456          41 :   (void) unformat (input, "thread %u index %u", &show_session_thread_id,
    3457             :                    &show_session_session_index);
    3458          41 :   (void) unformat (input, "verbose %u", &show_bihash_verbose);
    3459             : 
    3460          41 :   acl_plugin_show_sessions (am, show_session_thread_id,
    3461             :                             show_session_session_index);
    3462          41 :   show_fa_sessions_hash (vm, show_bihash_verbose);
    3463          41 :   return error;
    3464             : }
    3465             : 
    3466             : static clib_error_t *
    3467         140 : acl_show_aclplugin_tables_fn (vlib_main_t * vm,
    3468             :                               unformat_input_t * input,
    3469             :                               vlib_cli_command_t * cmd)
    3470             : {
    3471         140 :   clib_error_t *error = 0;
    3472             : 
    3473         140 :   u32 acl_index = ~0;
    3474         140 :   u32 lc_index = ~0;
    3475         140 :   int show_acl_hash_info = 0;
    3476         140 :   int show_applied_info = 0;
    3477         140 :   int show_mask_type = 0;
    3478         140 :   int show_bihash = 0;
    3479         140 :   u32 show_bihash_verbose = 0;
    3480             : 
    3481         140 :   if (unformat (input, "acl"))
    3482             :     {
    3483           0 :       show_acl_hash_info = 1;
    3484             :       /* mask-type is handy to see as well right there */
    3485           0 :       show_mask_type = 1;
    3486           0 :       unformat (input, "index %u", &acl_index);
    3487             :     }
    3488         140 :   else if (unformat (input, "applied"))
    3489             :     {
    3490           0 :       show_applied_info = 1;
    3491           0 :       unformat (input, "lc_index %u", &lc_index);
    3492             :     }
    3493         140 :   else if (unformat (input, "mask"))
    3494             :     {
    3495           0 :       show_mask_type = 1;
    3496             :     }
    3497         140 :   else if (unformat (input, "hash"))
    3498             :     {
    3499           0 :       show_bihash = 1;
    3500           0 :       unformat (input, "verbose %u", &show_bihash_verbose);
    3501             :     }
    3502             : 
    3503         280 :   if (!
    3504         140 :       (show_mask_type || show_acl_hash_info || show_applied_info
    3505             :        || show_bihash))
    3506             :     {
    3507             :       /* if no qualifiers specified, show all */
    3508         140 :       show_mask_type = 1;
    3509         140 :       show_acl_hash_info = 1;
    3510         140 :       show_applied_info = 1;
    3511         140 :       show_bihash = 1;
    3512             :     }
    3513         140 :   vlib_cli_output (vm, "Stats counters enabled for interface ACLs: %d",
    3514             :                    acl_main.interface_acl_counters_enabled);
    3515         140 :   vlib_cli_output (vm, "Use hash-based lookup for ACLs: %d",
    3516             :                    acl_main.use_hash_acl_matching);
    3517         140 :   if (show_mask_type)
    3518         140 :     acl_plugin_show_tables_mask_type ();
    3519         140 :   if (show_acl_hash_info)
    3520         140 :     acl_plugin_show_tables_acl_hash_info (acl_index);
    3521         140 :   if (show_applied_info)
    3522         140 :     acl_plugin_show_tables_applied_info (lc_index);
    3523         140 :   if (show_bihash)
    3524         140 :     acl_plugin_show_tables_bihash (show_bihash_verbose);
    3525             : 
    3526         140 :   return error;
    3527             : }
    3528             : 
    3529             : static clib_error_t *
    3530           0 : acl_clear_aclplugin_fn (vlib_main_t * vm,
    3531             :                         unformat_input_t * input, vlib_cli_command_t * cmd)
    3532             : {
    3533           0 :   clib_error_t *error = 0;
    3534           0 :   acl_main_t *am = &acl_main;
    3535           0 :   vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
    3536             :                              ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
    3537           0 :   return error;
    3538             : }
    3539             : 
    3540             :  /* *INDENT-OFF* */
    3541      262247 : VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
    3542             :     .path = "set acl-plugin",
    3543             :     .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
    3544             :     .function = acl_set_aclplugin_fn,
    3545             : };
    3546             : 
    3547      262247 : VLIB_CLI_COMMAND (aclplugin_show_acl_command, static) = {
    3548             :     .path = "show acl-plugin acl",
    3549             :     .short_help = "show acl-plugin acl [index N]",
    3550             :     .function = acl_show_aclplugin_acl_fn,
    3551             : };
    3552             : 
    3553      262247 : VLIB_CLI_COMMAND (aclplugin_show_lookup_context_command, static) = {
    3554             :     .path = "show acl-plugin lookup context",
    3555             :     .short_help = "show acl-plugin lookup context [index N]",
    3556             :     .function = acl_show_aclplugin_lookup_context_fn,
    3557             : };
    3558             : 
    3559      262247 : VLIB_CLI_COMMAND (aclplugin_show_lookup_user_command, static) = {
    3560             :     .path = "show acl-plugin lookup user",
    3561             :     .short_help = "show acl-plugin lookup user [index N]",
    3562             :     .function = acl_show_aclplugin_lookup_user_fn,
    3563             : };
    3564             : 
    3565      262247 : VLIB_CLI_COMMAND (aclplugin_show_decode_5tuple_command, static) = {
    3566             :     .path = "show acl-plugin decode 5tuple",
    3567             :     .short_help = "show acl-plugin decode 5tuple XXXX XXXX XXXX XXXX XXXX XXXX",
    3568             :     .function = acl_show_aclplugin_decode_5tuple_fn,
    3569             : };
    3570             : 
    3571      262247 : VLIB_CLI_COMMAND (aclplugin_show_interface_command, static) = {
    3572             :     .path = "show acl-plugin interface",
    3573             :     .short_help = "show acl-plugin interface [sw_if_index N] [acl]",
    3574             :     .function = acl_show_aclplugin_interface_fn,
    3575             : };
    3576             : 
    3577      262247 : VLIB_CLI_COMMAND (aclplugin_show_memory_command, static) = {
    3578             :     .path = "show acl-plugin memory",
    3579             :     .short_help = "show acl-plugin memory",
    3580             :     .function = acl_show_aclplugin_memory_fn,
    3581             : };
    3582             : 
    3583      262247 : VLIB_CLI_COMMAND (aclplugin_show_sessions_command, static) = {
    3584             :     .path = "show acl-plugin sessions",
    3585             :     .short_help = "show acl-plugin sessions",
    3586             :     .function = acl_show_aclplugin_sessions_fn,
    3587             : };
    3588             : 
    3589      262247 : VLIB_CLI_COMMAND (aclplugin_show_tables_command, static) = {
    3590             :     .path = "show acl-plugin tables",
    3591             :     .short_help = "show acl-plugin tables [ acl [index N] | applied [ lc_index N ] | mask | hash [verbose N] ]",
    3592             :     .function = acl_show_aclplugin_tables_fn,
    3593             : };
    3594             : 
    3595      262247 : VLIB_CLI_COMMAND (aclplugin_show_macip_acl_command, static) = {
    3596             :     .path = "show acl-plugin macip acl",
    3597             :     .short_help = "show acl-plugin macip acl [index N]",
    3598             :     .function = acl_show_aclplugin_macip_acl_fn,
    3599             : };
    3600             : 
    3601      262247 : VLIB_CLI_COMMAND (aclplugin_show_macip_interface_command, static) = {
    3602             :     .path = "show acl-plugin macip interface",
    3603             :     .short_help = "show acl-plugin macip interface",
    3604             :     .function = acl_show_aclplugin_macip_interface_fn,
    3605             : };
    3606             : 
    3607      262247 : VLIB_CLI_COMMAND (aclplugin_clear_command, static) = {
    3608             :     .path = "clear acl-plugin sessions",
    3609             :     .short_help = "clear acl-plugin sessions",
    3610             :     .function = acl_clear_aclplugin_fn,
    3611             : };
    3612             : 
    3613             : /*?
    3614             :  * [un]Apply an ACL to an interface.
    3615             :  *  The ACL is applied in a given direction, either input or output.
    3616             :  *  The ACL being applied must already exist.
    3617             :  *
    3618             :  * @cliexpar
    3619             :  * <b><em> set acl-plugin interface <input|output> acl <index> [del]  </b></em>
    3620             :  * @cliexend
    3621             :  ?*/
    3622      262247 : VLIB_CLI_COMMAND (aclplugin_set_interface_command, static) = {
    3623             :     .path = "set acl-plugin interface",
    3624             :     .short_help = "set acl-plugin interface <interface> <input|output> <acl INDEX> [del] ",
    3625             :     .function = acl_set_aclplugin_interface_fn,
    3626             : };
    3627             : 
    3628             : /*?
    3629             :  * Create an Access Control List (ACL)
    3630             :  *  If index is not specified, a new one will be created. Otherwise, replace
    3631             :  *  the one at this index.
    3632             :  *
    3633             :  *  An ACL is composed of more than one Access control element (ACE). Multiple
    3634             :  *  ACEs can be specified with this command using a comma separated list.
    3635             :  *
    3636             :  * Each ACE describes a tuple of src+dst IP prefix, ip protocol, src+dst port
    3637             :  * ranges. (the ACL plugin also support ICMP types/codes instead of UDP/TCP
    3638             :  * ports, but this CLI does not).
    3639             :  *
    3640             :  * An ACL can optionally be assigned a 'tag' - which is an identifier
    3641             :  * understood by the client. VPP does not examine it in any way.
    3642             :  *
    3643             :  * @cliexcmd{set acl-plugin acl <permit|deny|permit+reflect> src <PREFIX> dst
    3644             :  * <PREFIX> proto <TCP|UDP> sport <X-Y> dport <X-Y> tcpflags <X> mask <X>
    3645             :  * [tag FOO]}
    3646             :  ?*/
    3647      262247 : VLIB_CLI_COMMAND (aclplugin_set_acl_command, static) = {
    3648             :   .path = "set acl-plugin acl",
    3649             :   .short_help =
    3650             :     "set acl-plugin acl [index <idx>] <permit|deny|permit+reflect> src "
    3651             :     "<PREFIX> dst <PREFIX> [proto X] [sport X[-Y]] [dport X[-Y]] [tcpflags "
    3652             :     "<int> mask <int>] [tag FOO] {use comma separated list for multiple "
    3653             :     "rules}",
    3654             :   .function = acl_set_aclplugin_acl_fn,
    3655             : };
    3656             : /* *INDENT-ON* */
    3657             : 
    3658             : /*?
    3659             :  * Delete an Access Control List (ACL)
    3660             :  *  Removes an ACL at the specified index, which must exist but not in use by
    3661             :  *  any interface.
    3662             :  *
    3663             :  * @cliexcmd{delete acl-plugin acl index <idx>}
    3664             :  ?*/
    3665      262247 : VLIB_CLI_COMMAND (aclplugin_delete_acl_command, static) = {
    3666             :   .path = "delete acl-plugin acl",
    3667             :   .short_help = "delete acl-plugin acl index <idx>",
    3668             :   .function = acl_delete_aclplugin_acl_fn,
    3669             : };
    3670             : 
    3671             : static clib_error_t *
    3672         559 : acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
    3673             : {
    3674         559 :   acl_main_t *am = &acl_main;
    3675             :   u32 conn_table_hash_buckets;
    3676             :   uword conn_table_hash_memory_size;
    3677             :   u32 conn_table_max_entries;
    3678             :   uword main_heap_size;
    3679             :   uword hash_heap_size;
    3680             :   u32 hash_lookup_hash_buckets;
    3681             :   uword hash_lookup_hash_memory;
    3682             :   u32 reclassify_sessions;
    3683             :   u32 use_tuple_merge;
    3684             :   u32 tuple_merge_split_threshold;
    3685             : 
    3686         559 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    3687             :     {
    3688           0 :       if (unformat
    3689             :           (input, "connection hash buckets %d", &conn_table_hash_buckets))
    3690           0 :         am->fa_conn_table_hash_num_buckets = conn_table_hash_buckets;
    3691             :       else
    3692           0 :         if (unformat
    3693             :             (input, "connection hash memory %U", unformat_memory_size,
    3694             :              &conn_table_hash_memory_size))
    3695           0 :         am->fa_conn_table_hash_memory_size = conn_table_hash_memory_size;
    3696           0 :       else if (unformat (input, "connection count max %d",
    3697             :                          &conn_table_max_entries))
    3698           0 :         am->fa_conn_table_max_entries = conn_table_max_entries;
    3699             :       else
    3700           0 :         if (unformat
    3701             :             (input, "main heap size %U", unformat_memory_size,
    3702             :              &main_heap_size))
    3703           0 :         clib_warning
    3704             :           ("WARNING: ACL heap is now part of the main heap. 'main heap size' is ineffective.");
    3705             :       else
    3706           0 :         if (unformat
    3707             :             (input, "hash lookup heap size %U", unformat_memory_size,
    3708             :              &hash_heap_size))
    3709           0 :         clib_warning
    3710             :           ("WARNING: ACL heap is now part of the main heap. 'hash lookup heap size' is ineffective.");
    3711             :       else
    3712           0 :         if (unformat
    3713             :             (input, "hash lookup hash buckets %d", &hash_lookup_hash_buckets))
    3714           0 :         am->hash_lookup_hash_buckets = hash_lookup_hash_buckets;
    3715             :       else
    3716           0 :         if (unformat
    3717             :             (input, "hash lookup hash memory %U", unformat_memory_size,
    3718             :              &hash_lookup_hash_memory))
    3719           0 :         am->hash_lookup_hash_memory = hash_lookup_hash_memory;
    3720           0 :       else if (unformat (input, "use tuple merge %d", &use_tuple_merge))
    3721           0 :         am->use_tuple_merge = use_tuple_merge;
    3722             :       else
    3723           0 :         if (unformat
    3724             :             (input, "tuple merge split threshold %d",
    3725             :              &tuple_merge_split_threshold))
    3726           0 :         am->tuple_merge_split_threshold = tuple_merge_split_threshold;
    3727             : 
    3728           0 :       else if (unformat (input, "reclassify sessions %d",
    3729             :                          &reclassify_sessions))
    3730           0 :         am->reclassify_sessions = reclassify_sessions;
    3731             : 
    3732             :       else
    3733           0 :         return clib_error_return (0, "unknown input '%U'",
    3734             :                                   format_unformat_error, input);
    3735             :     }
    3736         559 :   return 0;
    3737             : }
    3738             : 
    3739        6746 : VLIB_CONFIG_FUNCTION (acl_plugin_config, "acl-plugin");
    3740             : 
    3741             : /* Set up the API message handling tables */
    3742             : #include <vnet/format_fns.h>
    3743             : #include <acl/acl.api.c>
    3744             : 
    3745             : static clib_error_t *
    3746         559 : acl_init (vlib_main_t * vm)
    3747             : {
    3748         559 :   acl_main_t *am = &acl_main;
    3749         559 :   clib_error_t *error = 0;
    3750         559 :   clib_memset (am, 0, sizeof (*am));
    3751         559 :   am->vlib_main = vm;
    3752         559 :   am->vnet_main = vnet_get_main ();
    3753         559 :   am->log_default = vlib_log_register_class ("acl_plugin", 0);
    3754             : 
    3755             :   /* Ask for a correctly-sized block of API message decode slots */
    3756         559 :   am->msg_id_base = setup_message_id_table ();
    3757             : 
    3758         559 :   error = acl_plugin_exports_init (&acl_plugin);
    3759             : 
    3760         559 :   if (error)
    3761           0 :     return error;
    3762             : 
    3763         559 :   am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
    3764         559 :   am->hash_lookup_hash_memory = ACL_PLUGIN_HASH_LOOKUP_HASH_MEMORY;
    3765             : 
    3766         559 :   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] =
    3767             :     TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
    3768         559 :   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] =
    3769             :     TCP_SESSION_IDLE_TIMEOUT_SEC;
    3770         559 :   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] =
    3771             :     UDP_SESSION_IDLE_TIMEOUT_SEC;
    3772             : 
    3773         559 :   am->fa_conn_table_hash_num_buckets =
    3774             :     ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
    3775         559 :   am->fa_conn_table_hash_memory_size =
    3776             :     ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
    3777         559 :   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
    3778         559 :   am->reclassify_sessions = 0;
    3779         559 :   vlib_thread_main_t *tm = vlib_get_thread_main ();
    3780             : 
    3781         559 :   am->fa_min_deleted_sessions_per_interval =
    3782             :     ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
    3783         559 :   am->fa_max_deleted_sessions_per_interval =
    3784             :     ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
    3785         559 :   am->fa_cleaner_wait_time_increment =
    3786             :     ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
    3787             : 
    3788         559 :   vec_validate (am->per_worker_data, tm->n_vlib_mains - 1);
    3789             :   {
    3790             :     u16 wk;
    3791        1172 :     for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
    3792             :       {
    3793         613 :         acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
    3794         613 :         if (tm->n_vlib_mains > 1)
    3795             :           {
    3796          90 :             clib_spinlock_init (&pw->pending_session_change_request_lock);
    3797             :           }
    3798         613 :         vec_validate (pw->expired,
    3799             :                       ACL_N_TIMEOUTS *
    3800             :                       am->fa_max_deleted_sessions_per_interval);
    3801         613 :         vec_set_len (pw->expired, 0);
    3802        3678 :         vec_validate_init_empty (pw->fa_conn_list_head, ACL_N_TIMEOUTS - 1,
    3803             :                                  FA_SESSION_BOGUS_INDEX);
    3804        3678 :         vec_validate_init_empty (pw->fa_conn_list_tail, ACL_N_TIMEOUTS - 1,
    3805             :                                  FA_SESSION_BOGUS_INDEX);
    3806        3678 :         vec_validate_init_empty (pw->fa_conn_list_head_expiry_time,
    3807             :                                  ACL_N_TIMEOUTS - 1, ~0ULL);
    3808             :       }
    3809             :   }
    3810             : 
    3811         559 :   am->fa_cleaner_cnt_delete_by_sw_index = 0;
    3812         559 :   am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
    3813         559 :   am->fa_cleaner_cnt_unknown_event = 0;
    3814         559 :   am->fa_cleaner_cnt_timer_restarted = 0;
    3815         559 :   am->fa_cleaner_cnt_wait_with_timeout = 0;
    3816             : 
    3817             : 
    3818             : #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
    3819         559 :   foreach_acl_eh
    3820             : #undef _
    3821         559 :     am->l4_match_nonfirst_fragment = 1;
    3822             : 
    3823             :   /* use the new fancy hash-based matching */
    3824         559 :   am->use_hash_acl_matching = 1;
    3825             :   /* use tuplemerge by default */
    3826         559 :   am->use_tuple_merge = 1;
    3827             :   /* Set the default threshold */
    3828         559 :   am->tuple_merge_split_threshold = TM_SPLIT_THRESHOLD;
    3829             : 
    3830         559 :   am->interface_acl_user_id =
    3831         559 :     acl_plugin.register_user_module ("interface ACL", "sw_if_index",
    3832             :                                      "is_input");
    3833             : 
    3834         559 :   am->acl_counter_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
    3835             :                                                  CLIB_CACHE_LINE_BYTES);
    3836         559 :   am->acl_counter_lock[0] = 0;       /* should be no need */
    3837             : 
    3838         559 :   return error;
    3839             : }
    3840             : 
    3841        1119 : VLIB_INIT_FUNCTION (acl_init);
    3842             : 
    3843             : 
    3844             : /*
    3845             :  * fd.io coding-style-patch-verification: ON
    3846             :  *
    3847             :  * Local Variables:
    3848             :  * eval: (c-set-style "gnu")
    3849             :  * End:
    3850             :  */

Generated by: LCOV version 1.14