LCOV - code coverage report
Current view: top level - plugins/acl - dataplane_node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 269 306 87.9 %
Date: 2023-10-26 01:39:38 Functions: 85 111 76.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016-2018 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : #include <stddef.h>
      16             : #include <netinet/in.h>
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <vnet/vnet.h>
      20             : #include <vppinfra/error.h>
      21             : 
      22             : 
      23             : #include <acl/acl.h>
      24             : #include <vnet/ip/icmp46_packet.h>
      25             : 
      26             : #include <plugins/acl/fa_node.h>
      27             : #include <plugins/acl/acl.h>
      28             : #include <plugins/acl/lookup_context.h>
      29             : #include <plugins/acl/public_inlines.h>
      30             : #include <plugins/acl/session_inlines.h>
      31             : 
      32             : #include <vppinfra/bihash_40_8.h>
      33             : #include <vppinfra/bihash_template.h>
      34             : 
      35             : typedef struct
      36             : {
      37             :   u32 next_index;
      38             :   u32 sw_if_index;
      39             :   u32 lc_index;
      40             :   u32 match_acl_in_index;
      41             :   u32 match_rule_index;
      42             :   u64 packet_info[6];
      43             :   u32 trace_bitmap;
      44             :   u8 action;
      45             : } acl_fa_trace_t;
      46             : 
      47             : /* *INDENT-OFF* */
      48             : #define foreach_acl_fa_error \
      49             : _(ACL_DROP, "ACL deny packets")  \
      50             : _(ACL_PERMIT, "ACL permit packets")  \
      51             : _(ACL_NEW_SESSION, "new sessions added") \
      52             : _(ACL_EXIST_SESSION, "existing session packets") \
      53             : _(ACL_CHECK, "checked packets") \
      54             : _(ACL_RESTART_SESSION_TIMER, "restart session timer") \
      55             : _(ACL_TOO_MANY_SESSIONS, "too many sessions to add new") \
      56             : /* end  of errors */
      57             : 
      58             : typedef enum
      59             : {
      60             : #define _(sym,str) ACL_FA_ERROR_##sym,
      61             :   foreach_acl_fa_error
      62             : #undef _
      63             :     ACL_FA_N_ERROR,
      64             : } acl_fa_error_t;
      65             : 
      66             : /* *INDENT-ON* */
      67             : 
      68             : always_inline u16
      69          84 : get_current_policy_epoch (acl_main_t * am, int is_input, u32 sw_if_index0)
      70             : {
      71          84 :   u32 **p_epoch_vec =
      72          84 :     is_input ? &am->input_policy_epoch_by_sw_if_index :
      73             :     &am->output_policy_epoch_by_sw_if_index;
      74          84 :   u16 current_policy_epoch =
      75          84 :     sw_if_index0 < vec_len (*p_epoch_vec) ? vec_elt (*p_epoch_vec,
      76             :                                                      sw_if_index0)
      77             :     : (is_input * FA_POLICY_EPOCH_IS_INPUT);
      78          84 :   return current_policy_epoch;
      79             : }
      80             : 
      81             : always_inline void
      82        9496 : maybe_trace_buffer (vlib_main_t * vm, vlib_node_runtime_t * node,
      83             :                     vlib_buffer_t * b, u32 sw_if_index0, u32 lc_index0,
      84             :                     u16 next0, int match_acl_in_index, int match_rule_index,
      85             :                     fa_5tuple_t * fa_5tuple, u8 action, u32 trace_bitmap)
      86             : {
      87        9496 :   if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
      88             :     {
      89        9496 :       acl_fa_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
      90        9496 :       t->sw_if_index = sw_if_index0;
      91        9496 :       t->lc_index = lc_index0;
      92        9496 :       t->next_index = next0;
      93        9496 :       t->match_acl_in_index = match_acl_in_index;
      94        9496 :       t->match_rule_index = match_rule_index;
      95        9496 :       t->packet_info[0] = fa_5tuple->kv_40_8.key[0];
      96        9496 :       t->packet_info[1] = fa_5tuple->kv_40_8.key[1];
      97        9496 :       t->packet_info[2] = fa_5tuple->kv_40_8.key[2];
      98        9496 :       t->packet_info[3] = fa_5tuple->kv_40_8.key[3];
      99        9496 :       t->packet_info[4] = fa_5tuple->kv_40_8.key[4];
     100        9496 :       t->packet_info[5] = fa_5tuple->kv_40_8.value;
     101        9496 :       t->action = action;
     102        9496 :       t->trace_bitmap = trace_bitmap;
     103             :     }
     104        9496 : }
     105             : 
     106             : 
     107             : always_inline int
     108           0 : stale_session_deleted (acl_main_t * am, int is_input,
     109             :                        acl_fa_per_worker_data_t * pw, u64 now,
     110             :                        u32 sw_if_index0, fa_full_session_id_t f_sess_id)
     111             : {
     112             :   u16 current_policy_epoch =
     113           0 :     get_current_policy_epoch (am, is_input, sw_if_index0);
     114             : 
     115             :   /* if the MSB of policy epoch matches but not the LSB means it is a stale session */
     116           0 :   if ((0 ==
     117             :        ((current_policy_epoch ^
     118           0 :          f_sess_id.intf_policy_epoch) &
     119             :         FA_POLICY_EPOCH_IS_INPUT))
     120           0 :       && (current_policy_epoch != f_sess_id.intf_policy_epoch))
     121             :     {
     122             :       /* delete session and increment the counter */
     123           0 :       vec_validate (pw->fa_session_epoch_change_by_sw_if_index, sw_if_index0);
     124           0 :       vec_elt (pw->fa_session_epoch_change_by_sw_if_index, sw_if_index0)++;
     125           0 :       if (acl_fa_conn_list_delete_session (am, f_sess_id, now))
     126             :         {
     127             :           /* delete the session only if we were able to unlink it */
     128           0 :           acl_fa_two_stage_delete_session (am, sw_if_index0, f_sess_id, now);
     129             :         }
     130           0 :       return 1;
     131             :     }
     132             :   else
     133           0 :     return 0;
     134             : }
     135             : 
     136             : 
     137             : 
     138             : 
     139             : 
     140             : always_inline void
     141        4569 : get_sw_if_index_xN (int vector_sz, int is_input, vlib_buffer_t ** b,
     142             :                     u32 * out_sw_if_index)
     143             : {
     144             :   int ii;
     145       14067 :   for (ii = 0; ii < vector_sz; ii++)
     146        9498 :     if (is_input)
     147        2390 :       out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_RX];
     148             :     else
     149        7108 :       out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_TX];
     150        4569 : }
     151             : 
     152             : always_inline void
     153        4569 : fill_5tuple_xN (int vector_sz, acl_main_t * am, int is_ip6, int is_input,
     154             :                 int is_l2_path, vlib_buffer_t ** b, u32 * sw_if_index,
     155             :                 fa_5tuple_t * out_fa_5tuple)
     156             : {
     157             :   int ii;
     158       14067 :   for (ii = 0; ii < vector_sz; ii++)
     159        9498 :     acl_fill_5tuple (am, sw_if_index[ii], b[ii], is_ip6,
     160        9498 :                      is_input, is_l2_path, &out_fa_5tuple[ii]);
     161        4569 : }
     162             : 
     163             : always_inline void
     164        4569 : make_session_hash_xN (int vector_sz, acl_main_t * am, int is_ip6,
     165             :                       u32 * sw_if_index, fa_5tuple_t * fa_5tuple,
     166             :                       u64 * out_hash)
     167             : {
     168             :   int ii;
     169       14067 :   for (ii = 0; ii < vector_sz; ii++)
     170        9498 :     out_hash[ii] =
     171        9498 :       acl_fa_make_session_hash (am, is_ip6, sw_if_index[ii], &fa_5tuple[ii]);
     172        4569 : }
     173             : 
     174             : always_inline void
     175          59 : prefetch_session_entry (acl_main_t * am, fa_full_session_id_t f_sess_id)
     176             : {
     177          59 :   fa_session_t *sess = get_session_ptr_no_check (am, f_sess_id.thread_index,
     178             :                                                  f_sess_id.session_index);
     179          59 :   CLIB_PREFETCH (sess, sizeof (*sess), STORE);
     180          59 : }
     181             : 
     182             : always_inline u8
     183         168 : process_established_session (vlib_main_t * vm, acl_main_t * am,
     184             :                              u32 counter_node_index, int is_input, u64 now,
     185             :                              fa_full_session_id_t f_sess_id,
     186             :                              u32 * sw_if_index, fa_5tuple_t * fa_5tuple,
     187             :                              u32 pkt_len, int node_trace_on,
     188             :                              u32 * trace_bitmap)
     189             : {
     190         168 :   u8 action = 0;
     191         168 :   fa_session_t *sess = get_session_ptr_no_check (am, f_sess_id.thread_index,
     192             :                                                  f_sess_id.session_index);
     193             : 
     194         168 :   int old_timeout_type = fa_session_get_timeout_type (am, sess);
     195             :   action =
     196         168 :     acl_fa_track_session (am, is_input, sw_if_index[0], now,
     197             :                           sess, &fa_5tuple[0], pkt_len);
     198         168 :   int new_timeout_type = fa_session_get_timeout_type (am, sess);
     199             :   /* Tracking might have changed the session timeout type, e.g. from transient to established */
     200         168 :   if (PREDICT_FALSE (old_timeout_type != new_timeout_type))
     201             :     {
     202           0 :       acl_fa_restart_timer_for_session (am, now, f_sess_id);
     203           0 :       vlib_node_increment_counter (vm, counter_node_index,
     204             :                                    ACL_FA_ERROR_ACL_RESTART_SESSION_TIMER, 1);
     205           0 :       if (node_trace_on)
     206           0 :         *trace_bitmap |=
     207           0 :           0x00010000 + ((0xff & old_timeout_type) << 8) +
     208           0 :           (0xff & new_timeout_type);
     209             :     }
     210             :   /*
     211             :    * I estimate the likelihood to be very low - the VPP needs
     212             :    * to have >64K interfaces to start with and then on
     213             :    * exactly 64K indices apart needs to be exactly the same
     214             :    * 5-tuple... Anyway, since this probability is nonzero -
     215             :    * print an error and drop the unlucky packet.
     216             :    * If this shows up in real world, we would need to bump
     217             :    * the hash key length.
     218             :    */
     219         168 :   if (PREDICT_FALSE (sess->sw_if_index != sw_if_index[0]))
     220             :     {
     221           0 :       clib_warning
     222             :         ("BUG: session LSB16(sw_if_index)=%d and 5-tuple=%d collision!",
     223             :          sess->sw_if_index, sw_if_index[0]);
     224           0 :       action = 0;
     225             :     }
     226         168 :   return action;
     227             : 
     228             : }
     229             : 
     230             : #define ACL_PLUGIN_VECTOR_SIZE 4
     231             : #define ACL_PLUGIN_PREFETCH_GAP 3
     232             : 
     233             : always_inline void
     234         279 : acl_fa_node_common_prepare_fn (vlib_main_t * vm,
     235             :                                vlib_node_runtime_t * node,
     236             :                                vlib_frame_t * frame, int is_ip6, int is_input,
     237             :                                int is_l2_path, int with_stateful_datapath)
     238             :         /* , int node_trace_on,
     239             :            int reclassify_sessions) */
     240             : {
     241             :   u32 n_left, *from;
     242         279 :   acl_main_t *am = &acl_main;
     243         279 :   uword thread_index = os_get_thread_index ();
     244         279 :   acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index];
     245             : 
     246             :   vlib_buffer_t **b;
     247             :   u32 *sw_if_index;
     248             :   fa_5tuple_t *fa_5tuple;
     249             :   u64 *hash;
     250             : 
     251             : 
     252             : 
     253         279 :   from = vlib_frame_vector_args (frame);
     254         279 :   vlib_get_buffers (vm, from, pw->bufs, frame->n_vectors);
     255             : 
     256             :   /* set the initial values for the current buffer the next pointers */
     257         279 :   b = pw->bufs;
     258         279 :   sw_if_index = pw->sw_if_indices;
     259         279 :   fa_5tuple = pw->fa_5tuples;
     260         279 :   hash = pw->hashes;
     261             : 
     262             : 
     263             :   /*
     264             :    * fill the sw_if_index, 5tuple and session hash,
     265             :    * First in strides of size ACL_PLUGIN_VECTOR_SIZE,
     266             :    * with buffer prefetch being
     267             :    * ACL_PLUGIN_PREFETCH_GAP * ACL_PLUGIN_VECTOR_SIZE entries
     268             :    * in front. Then with a simple single loop.
     269             :    */
     270             : 
     271         279 :   n_left = frame->n_vectors;
     272        1922 :   while (n_left >= (ACL_PLUGIN_PREFETCH_GAP + 1) * ACL_PLUGIN_VECTOR_SIZE)
     273             :     {
     274        1643 :       const int vec_sz = ACL_PLUGIN_VECTOR_SIZE;
     275             :       {
     276             :         int ii;
     277        1643 :         for (ii = ACL_PLUGIN_PREFETCH_GAP * vec_sz;
     278        8215 :              ii < (ACL_PLUGIN_PREFETCH_GAP + 1) * vec_sz; ii++)
     279             :           {
     280        6572 :             clib_prefetch_load (b[ii]);
     281        6572 :             CLIB_PREFETCH (b[ii]->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
     282             :           }
     283             :       }
     284             : 
     285             : 
     286        1643 :       get_sw_if_index_xN (vec_sz, is_input, b, sw_if_index);
     287        1643 :       fill_5tuple_xN (vec_sz, am, is_ip6, is_input, is_l2_path, &b[0],
     288             :                       &sw_if_index[0], &fa_5tuple[0]);
     289        1643 :       if (with_stateful_datapath)
     290        1643 :         make_session_hash_xN (vec_sz, am, is_ip6, &sw_if_index[0],
     291             :                               &fa_5tuple[0], &hash[0]);
     292             : 
     293        1643 :       n_left -= vec_sz;
     294             : 
     295        1643 :       fa_5tuple += vec_sz;
     296        1643 :       b += vec_sz;
     297        1643 :       sw_if_index += vec_sz;
     298        1643 :       hash += vec_sz;
     299             :     }
     300             : 
     301        3205 :   while (n_left > 0)
     302             :     {
     303        2926 :       const int vec_sz = 1;
     304             : 
     305        2926 :       get_sw_if_index_xN (vec_sz, is_input, b, sw_if_index);
     306        2926 :       fill_5tuple_xN (vec_sz, am, is_ip6, is_input, is_l2_path, &b[0],
     307             :                       &sw_if_index[0], &fa_5tuple[0]);
     308        2926 :       if (with_stateful_datapath)
     309        2926 :         make_session_hash_xN (vec_sz, am, is_ip6, &sw_if_index[0],
     310             :                               &fa_5tuple[0], &hash[0]);
     311             : 
     312        2926 :       n_left -= vec_sz;
     313             : 
     314        2926 :       fa_5tuple += vec_sz;
     315        2926 :       b += vec_sz;
     316        2926 :       sw_if_index += vec_sz;
     317        2926 :       hash += vec_sz;
     318             :     }
     319         279 : }
     320             : 
     321             : 
     322             : always_inline uword
     323         279 : acl_fa_inner_node_fn (vlib_main_t * vm,
     324             :                       vlib_node_runtime_t * node, vlib_frame_t * frame,
     325             :                       int is_ip6, int is_input, int is_l2_path,
     326             :                       int with_stateful_datapath, int node_trace_on,
     327             :                       int reclassify_sessions)
     328             : {
     329             :   u32 n_left;
     330         279 :   u32 pkts_exist_session = 0;
     331         279 :   u32 pkts_new_session = 0;
     332         279 :   u32 pkts_acl_permit = 0;
     333         279 :   u32 trace_bitmap = 0;
     334         279 :   acl_main_t *am = &acl_main;
     335             :   vlib_node_runtime_t *error_node;
     336             :   vlib_error_t no_error_existing_session;
     337         279 :   u64 now = clib_cpu_time_now ();
     338         279 :   uword thread_index = os_get_thread_index ();
     339         279 :   acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index];
     340             : 
     341             :   u16 *next;
     342             :   vlib_buffer_t **b;
     343             :   u32 *sw_if_index;
     344             :   fa_5tuple_t *fa_5tuple;
     345             :   u64 *hash;
     346             :   /* for the delayed counters */
     347         279 :   u32 saved_matched_acl_index = 0;
     348         279 :   u32 saved_matched_ace_index = 0;
     349         279 :   u32 saved_packet_count = 0;
     350         279 :   u32 saved_byte_count = 0;
     351             : 
     352         279 :   error_node = vlib_node_get_runtime (vm, node->node_index);
     353         279 :   no_error_existing_session =
     354         279 :     error_node->errors[ACL_FA_ERROR_ACL_EXIST_SESSION];
     355             : 
     356         279 :   b = pw->bufs;
     357         279 :   next = pw->nexts;
     358         279 :   sw_if_index = pw->sw_if_indices;
     359         279 :   fa_5tuple = pw->fa_5tuples;
     360         279 :   hash = pw->hashes;
     361             : 
     362             :   /*
     363             :    * Now the "hard" work of session lookups and ACL lookups for new sessions.
     364             :    * Due to the complexity, do it for the time being in single loop with
     365             :    * the pipeline of three prefetches:
     366             :    *    1) bucket for the session bihash
     367             :    *    2) data for the session bihash
     368             :    *    3) worker session record
     369             :    */
     370             : 
     371         279 :   fa_full_session_id_t f_sess_id_next = {.as_u64 = ~0ULL };
     372             : 
     373             :   /* find the "next" session so we can kickstart the pipeline */
     374         279 :   if (with_stateful_datapath)
     375         279 :     acl_fa_find_session_with_hash (am, is_ip6, sw_if_index[0], hash[0],
     376             :                                    &fa_5tuple[0], &f_sess_id_next.as_u64);
     377             : 
     378         279 :   n_left = frame->n_vectors;
     379        9777 :   while (n_left > 0)
     380             :     {
     381        9498 :       u8 action = 0;
     382        9498 :       u32 lc_index0 = ~0;
     383        9498 :       int acl_check_needed = 1;
     384        9498 :       u32 match_acl_in_index = ~0;
     385        9498 :       u32 match_acl_pos = ~0;
     386        9498 :       u32 match_rule_index = ~0;
     387             : 
     388        9498 :       next[0] = 0;              /* drop by default */
     389             : 
     390             :       /* Try to match an existing session first */
     391             : 
     392        9498 :       if (with_stateful_datapath)
     393             :         {
     394        9498 :           fa_full_session_id_t f_sess_id = f_sess_id_next;
     395        9498 :           switch (n_left)
     396             :             {
     397        8152 :             default:
     398        8152 :               acl_fa_prefetch_session_bucket_for_hash (am, is_ip6, hash[5]);
     399             :               /* fallthrough */
     400        8665 :             case 5:
     401             :             case 4:
     402        8665 :               acl_fa_prefetch_session_data_for_hash (am, is_ip6, hash[3]);
     403             :               /* fallthrough */
     404        9219 :             case 3:
     405             :             case 2:
     406        9219 :               acl_fa_find_session_with_hash (am, is_ip6, sw_if_index[1],
     407        9219 :                                              hash[1], &fa_5tuple[1],
     408             :                                              &f_sess_id_next.as_u64);
     409        9219 :               if (f_sess_id_next.as_u64 != ~0ULL)
     410             :                 {
     411          59 :                   prefetch_session_entry (am, f_sess_id_next);
     412             :                 }
     413             :               /* fallthrough */
     414             :             case 1:
     415        9498 :               if (f_sess_id.as_u64 != ~0ULL)
     416             :                 {
     417          84 :                   if (node_trace_on)
     418             :                     {
     419          84 :                       trace_bitmap |= 0x80000000;
     420             :                     }
     421          84 :                   ASSERT (f_sess_id.thread_index < vlib_get_n_threads ());
     422          84 :                   b[0]->error = no_error_existing_session;
     423          84 :                   acl_check_needed = 0;
     424          84 :                   pkts_exist_session += 1;
     425          84 :                   action =
     426          84 :                     process_established_session (vm, am, node->node_index,
     427             :                                                  is_input, now, f_sess_id,
     428             :                                                  &sw_if_index[0],
     429             :                                                  &fa_5tuple[0],
     430          84 :                                                  b[0]->current_length,
     431             :                                                  node_trace_on,
     432             :                                                  &trace_bitmap);
     433             : 
     434             :                   /* expose the session id to the tracer */
     435          84 :                   if (node_trace_on)
     436             :                     {
     437          84 :                       match_rule_index = f_sess_id.session_index;
     438             :                     }
     439             : 
     440          84 :                   if (reclassify_sessions)
     441             :                     {
     442           0 :                       if (PREDICT_FALSE
     443             :                           (stale_session_deleted
     444             :                            (am, is_input, pw, now, sw_if_index[0],
     445             :                             f_sess_id)))
     446             :                         {
     447           0 :                           acl_check_needed = 1;
     448           0 :                           if (node_trace_on)
     449             :                             {
     450           0 :                               trace_bitmap |= 0x40000000;
     451             :                             }
     452             :                           /*
     453             :                            * If we have just deleted the session, and the next
     454             :                            * buffer is the same 5-tuple, that session prediction
     455             :                            * is wrong, correct it.
     456             :                            */
     457           0 :                           if ((f_sess_id_next.as_u64 != ~0ULL)
     458           0 :                               && 0 == memcmp (&fa_5tuple[1], &fa_5tuple[0],
     459             :                                               sizeof (fa_5tuple[1])))
     460           0 :                             f_sess_id_next.as_u64 = ~0ULL;
     461             :                         }
     462             :                     }
     463             :                 }
     464             :             }
     465             : 
     466        9498 :           if (acl_check_needed)
     467             :             {
     468        9414 :               if (is_input)
     469        2346 :                 lc_index0 = am->input_lc_index_by_sw_if_index[sw_if_index[0]];
     470             :               else
     471        7068 :                 lc_index0 =
     472        7068 :                   am->output_lc_index_by_sw_if_index[sw_if_index[0]];
     473             : 
     474        9414 :               action = 0;       /* deny by default */
     475        9414 :               int is_match = acl_plugin_match_5tuple_inline (am, lc_index0,
     476             :                                                              (fa_5tuple_opaque_t *) & fa_5tuple[0], is_ip6,
     477             :                                                              &action,
     478             :                                                              &match_acl_pos,
     479             :                                                              &match_acl_in_index,
     480             :                                                              &match_rule_index,
     481             :                                                              &trace_bitmap);
     482        9414 :               if (PREDICT_FALSE
     483             :                   (is_match && am->interface_acl_counters_enabled))
     484             :                 {
     485         904 :                   u32 buf_len = vlib_buffer_length_in_chain (vm, b[0]);
     486         904 :                   vlib_increment_combined_counter (am->combined_acl_counters +
     487             :                                                    saved_matched_acl_index,
     488             :                                                    thread_index,
     489             :                                                    saved_matched_ace_index,
     490             :                                                    saved_packet_count,
     491             :                                                    saved_byte_count);
     492         904 :                   saved_matched_acl_index = match_acl_in_index;
     493         904 :                   saved_matched_ace_index = match_rule_index;
     494         904 :                   saved_packet_count = 1;
     495         904 :                   saved_byte_count = buf_len;
     496             :                   /* prefetch the counter that we are going to increment */
     497         904 :                   vlib_prefetch_combined_counter (am->combined_acl_counters +
     498             :                                                   saved_matched_acl_index,
     499             :                                                   thread_index,
     500             :                                                   saved_matched_ace_index);
     501             :                 }
     502             : 
     503        9414 :               b[0]->error = error_node->errors[action];
     504             : 
     505        9414 :               if (1 == action)
     506        8165 :                 pkts_acl_permit++;
     507             : 
     508        9414 :               if (2 == action)
     509             :                 {
     510          84 :                   if (!acl_fa_can_add_session (am, is_input, sw_if_index[0]))
     511           0 :                     acl_fa_try_recycle_session (am, is_input,
     512             :                                                 thread_index,
     513             :                                                 sw_if_index[0], now);
     514             : 
     515          84 :                   if (acl_fa_can_add_session (am, is_input, sw_if_index[0]))
     516             :                     {
     517             :                       u16 current_policy_epoch =
     518          84 :                         get_current_policy_epoch (am, is_input,
     519             :                                                   sw_if_index[0]);
     520             :                       fa_full_session_id_t f_sess_id =
     521          84 :                         acl_fa_add_session (am, is_input, is_ip6,
     522             :                                             sw_if_index[0],
     523             :                                             now, &fa_5tuple[0],
     524             :                                             current_policy_epoch);
     525             : 
     526             :                       /* perform the accounting for the newly added session */
     527          84 :                       process_established_session (vm, am,
     528             :                                                    node->node_index,
     529             :                                                    is_input, now,
     530             :                                                    f_sess_id,
     531             :                                                    &sw_if_index[0],
     532             :                                                    &fa_5tuple[0],
     533          84 :                                                    b[0]->current_length,
     534             :                                                    node_trace_on,
     535             :                                                    &trace_bitmap);
     536          84 :                       pkts_new_session++;
     537             :                       /*
     538             :                        * If the next 5tuple is the same and we just added the session,
     539             :                        * the f_sess_id_next can not be ~0. Correct it.
     540             :                        */
     541          84 :                       if ((f_sess_id_next.as_u64 == ~0ULL)
     542          84 :                           && 0 == memcmp (&fa_5tuple[1], &fa_5tuple[0],
     543             :                                           sizeof (fa_5tuple[1])))
     544           0 :                         f_sess_id_next = f_sess_id;
     545             :                     }
     546             :                   else
     547             :                     {
     548           0 :                       action = 0;
     549           0 :                       b[0]->error =
     550           0 :                         error_node->errors
     551             :                         [ACL_FA_ERROR_ACL_TOO_MANY_SESSIONS];
     552             :                     }
     553             :                 }
     554             : 
     555             :             }
     556             : 
     557             :           {
     558             :             /* speculatively get the next0 */
     559        9498 :             vnet_feature_next_u16 (&next[0], b[0]);
     560             :             /* if the action is not deny - then use that next */
     561        9498 :             next[0] = action ? next[0] : 0;
     562             :           }
     563             : 
     564        9498 :           if (node_trace_on)    // PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
     565             :             {
     566        9496 :               maybe_trace_buffer (vm, node, b[0], sw_if_index[0], lc_index0,
     567        9496 :                                   next[0], match_acl_in_index,
     568             :                                   match_rule_index, &fa_5tuple[0], action,
     569             :                                   trace_bitmap);
     570             :             }
     571             : 
     572        9498 :           next++;
     573        9498 :           b++;
     574        9498 :           fa_5tuple++;
     575        9498 :           sw_if_index++;
     576        9498 :           hash++;
     577        9498 :           n_left -= 1;
     578             :         }
     579             :     }
     580             : 
     581             :   /*
     582             :    * if we were had an acl match then we have a counter to increment.
     583             :    * else it is all zeroes, so this will be harmless.
     584             :    */
     585         279 :   vlib_increment_combined_counter (am->combined_acl_counters +
     586             :                                    saved_matched_acl_index,
     587             :                                    thread_index,
     588             :                                    saved_matched_ace_index,
     589             :                                    saved_packet_count, saved_byte_count);
     590             : 
     591         279 :   vlib_node_increment_counter (vm, node->node_index,
     592         279 :                                ACL_FA_ERROR_ACL_CHECK, frame->n_vectors);
     593         279 :   vlib_node_increment_counter (vm, node->node_index,
     594             :                                ACL_FA_ERROR_ACL_EXIST_SESSION,
     595             :                                pkts_exist_session);
     596         279 :   vlib_node_increment_counter (vm, node->node_index,
     597             :                                ACL_FA_ERROR_ACL_NEW_SESSION,
     598             :                                pkts_new_session);
     599         279 :   vlib_node_increment_counter (vm, node->node_index,
     600             :                                ACL_FA_ERROR_ACL_PERMIT, pkts_acl_permit);
     601         279 :   return frame->n_vectors;
     602             : }
     603             : 
     604             : always_inline uword
     605         279 : acl_fa_outer_node_fn (vlib_main_t * vm,
     606             :                       vlib_node_runtime_t * node, vlib_frame_t * frame,
     607             :                       int is_ip6, int is_input, int is_l2_path,
     608             :                       int do_stateful_datapath)
     609             : {
     610         279 :   acl_main_t *am = &acl_main;
     611             : 
     612         279 :   acl_fa_node_common_prepare_fn (vm, node, frame, is_ip6, is_input,
     613             :                                  is_l2_path, do_stateful_datapath);
     614             : 
     615         279 :   if (am->reclassify_sessions)
     616             :     {
     617           0 :       if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
     618           0 :         return acl_fa_inner_node_fn (vm, node, frame, is_ip6, is_input,
     619             :                                      is_l2_path, do_stateful_datapath,
     620             :                                      1 /* trace */ ,
     621             :                                      1 /* reclassify */ );
     622             :       else
     623           0 :         return acl_fa_inner_node_fn (vm, node, frame, is_ip6, is_input,
     624             :                                      is_l2_path, do_stateful_datapath, 0,
     625             :                                      1 /* reclassify */ );
     626             :     }
     627             :   else
     628             :     {
     629         279 :       if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
     630         277 :         return acl_fa_inner_node_fn (vm, node, frame, is_ip6, is_input,
     631             :                                      is_l2_path, do_stateful_datapath,
     632             :                                      1 /* trace */ ,
     633             :                                      0);
     634             :       else
     635           2 :         return acl_fa_inner_node_fn (vm, node, frame, is_ip6, is_input,
     636             :                                      is_l2_path, do_stateful_datapath, 0, 0);
     637             :     }
     638             : }
     639             : 
     640             : always_inline uword
     641         279 : acl_fa_node_fn (vlib_main_t * vm,
     642             :                 vlib_node_runtime_t * node, vlib_frame_t * frame, int is_ip6,
     643             :                 int is_input, int is_l2_path)
     644             : {
     645             :   /* select the reclassify/no-reclassify version of the datapath */
     646         279 :   acl_main_t *am = &acl_main;
     647         279 :   acl_fa_per_worker_data_t *pw = &am->per_worker_data[vm->thread_index];
     648             :   uword rv;
     649             : 
     650         279 :   if (am->fa_sessions_hash_is_initialized)
     651         279 :     rv = acl_fa_outer_node_fn (vm, node, frame, is_ip6, is_input,
     652             :                                is_l2_path, 1);
     653             :   else
     654           0 :     rv = acl_fa_outer_node_fn (vm, node, frame, is_ip6, is_input,
     655             :                                is_l2_path, 0);
     656             : 
     657         279 :   vlib_buffer_enqueue_to_next (vm, node, vlib_frame_vector_args (frame),
     658         279 :                                pw->nexts, frame->n_vectors);
     659         279 :   return rv;
     660             : }
     661             : 
     662             : 
     663             : static u8 *
     664        8019 : format_fa_5tuple (u8 * s, va_list * args)
     665             : {
     666        8019 :   fa_5tuple_t *p5t = va_arg (*args, fa_5tuple_t *);
     667             :   void *paddr0;
     668             :   void *paddr1;
     669             :   void *format_address_func;
     670             :   void *ip_af;
     671        8019 :   void *ip_frag_txt =
     672        8019 :     p5t->pkt.is_nonfirst_fragment ? " non-initial fragment" : "";
     673             : 
     674        8019 :   if (p5t->pkt.is_ip6)
     675             :     {
     676        1112 :       ip_af = "ip6";
     677        1112 :       format_address_func = format_ip6_address;
     678        1112 :       paddr0 = &p5t->ip6_addr[0];
     679        1112 :       paddr1 = &p5t->ip6_addr[1];
     680             :     }
     681             :   else
     682             :     {
     683        6907 :       ip_af = "ip4";
     684        6907 :       format_address_func = format_ip4_address;
     685        6907 :       paddr0 = &p5t->ip4_addr[0];
     686        6907 :       paddr1 = &p5t->ip4_addr[1];
     687             :     }
     688             : 
     689             :   s =
     690        8019 :     format (s, "lc_index %d l3 %s%s ", p5t->pkt.lc_index, ip_af, ip_frag_txt);
     691             :   s =
     692        8019 :     format (s, "%U -> %U ", format_address_func, paddr0, format_address_func,
     693             :             paddr1);
     694        8019 :   s = format (s, "%U ", format_fa_session_l4_key, &p5t->l4);
     695        8019 :   s = format (s, "tcp flags (%s) %02x rsvd %x",
     696        8019 :               p5t->pkt.tcp_flags_valid ? "valid" : "invalid",
     697        8019 :               p5t->pkt.tcp_flags, p5t->pkt.flags_reserved);
     698        8019 :   return s;
     699             : }
     700             : 
     701             : #ifndef CLIB_MARCH_VARIANT
     702             : u8 *
     703           0 : format_acl_plugin_5tuple (u8 * s, va_list * args)
     704             : {
     705           0 :   return format_fa_5tuple (s, args);
     706             : }
     707             : #endif
     708             : 
     709             : /* packet trace format function */
     710             : static u8 *
     711        8019 : format_acl_plugin_trace (u8 * s, va_list * args)
     712             : {
     713        8019 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     714        8019 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     715        8019 :   acl_fa_trace_t *t = va_arg (*args, acl_fa_trace_t *);
     716             : 
     717             :   s =
     718        8019 :     format (s,
     719             :             "acl-plugin: lc_index: %d, sw_if_index %d, next index %d, action: %d, match: acl %d rule %d trace_bits %08x\n"
     720             :             "  pkt info %016llx %016llx %016llx %016llx %016llx %016llx",
     721        8019 :             t->lc_index, t->sw_if_index, t->next_index, t->action,
     722             :             t->match_acl_in_index, t->match_rule_index, t->trace_bitmap,
     723             :             t->packet_info[0], t->packet_info[1], t->packet_info[2],
     724             :             t->packet_info[3], t->packet_info[4], t->packet_info[5]);
     725             : 
     726             :   /* Now also print out the packet_info in a form usable by humans */
     727        8019 :   s = format (s, "\n   %U", format_fa_5tuple, t->packet_info);
     728        8019 :   return s;
     729             : }
     730             : 
     731             : /* *INDENT-OFF* */
     732             : 
     733             : static char *acl_fa_error_strings[] = {
     734             : #define _(sym,string) string,
     735             :   foreach_acl_fa_error
     736             : #undef _
     737             : };
     738             : 
     739        2334 : VLIB_NODE_FN (acl_in_l2_ip6_node) (vlib_main_t * vm,
     740             :                                    vlib_node_runtime_t * node,
     741             :                                    vlib_frame_t * frame)
     742             : {
     743          34 :   return acl_fa_node_fn (vm, node, frame, 1, 1, 1);
     744             : }
     745             : 
     746        2337 : VLIB_NODE_FN (acl_in_l2_ip4_node) (vlib_main_t * vm,
     747             :                                    vlib_node_runtime_t * node,
     748             :                                    vlib_frame_t * frame)
     749             : {
     750          37 :   return acl_fa_node_fn (vm, node, frame, 0, 1, 1);
     751             : }
     752             : 
     753        2316 : VLIB_NODE_FN (acl_out_l2_ip6_node) (vlib_main_t * vm,
     754             :                                     vlib_node_runtime_t * node,
     755             :                                     vlib_frame_t * frame)
     756             : {
     757          16 :   return acl_fa_node_fn (vm, node, frame, 1, 0, 1);
     758             : }
     759             : 
     760        2317 : VLIB_NODE_FN (acl_out_l2_ip4_node) (vlib_main_t * vm,
     761             :                                     vlib_node_runtime_t * node,
     762             :                                     vlib_frame_t * frame)
     763             : {
     764          17 :   return acl_fa_node_fn (vm, node, frame, 0, 0, 1);
     765             : }
     766             : 
     767             : /**** L3 processing path nodes ****/
     768             : 
     769        2318 : VLIB_NODE_FN (acl_in_fa_ip6_node) (vlib_main_t * vm,
     770             :                                    vlib_node_runtime_t * node,
     771             :                                    vlib_frame_t * frame)
     772             : {
     773          18 :   return acl_fa_node_fn (vm, node, frame, 1, 1, 0);
     774             : }
     775             : 
     776        2321 : VLIB_NODE_FN (acl_in_fa_ip4_node) (vlib_main_t * vm,
     777             :                                    vlib_node_runtime_t * node,
     778             :                                    vlib_frame_t * frame)
     779             : {
     780          21 :   return acl_fa_node_fn (vm, node, frame, 0, 1, 0);
     781             : }
     782             : 
     783        2318 : VLIB_NODE_FN (acl_out_fa_ip6_node) (vlib_main_t * vm,
     784             :                                     vlib_node_runtime_t * node,
     785             :                                     vlib_frame_t * frame)
     786             : {
     787          18 :   return acl_fa_node_fn (vm, node, frame, 1, 0, 0);
     788             : }
     789             : 
     790        2418 : VLIB_NODE_FN (acl_out_fa_ip4_node) (vlib_main_t * vm,
     791             :                                     vlib_node_runtime_t * node,
     792             :                                     vlib_frame_t * frame)
     793             : {
     794         118 :   return acl_fa_node_fn (vm, node, frame, 0, 0, 0);
     795             : }
     796             : 
     797      175724 : VLIB_REGISTER_NODE (acl_in_l2_ip6_node) =
     798             : {
     799             :   .name = "acl-plugin-in-ip6-l2",
     800             :   .vector_size = sizeof (u32),
     801             :   .format_trace = format_acl_plugin_trace,
     802             :   .type = VLIB_NODE_TYPE_INTERNAL,
     803             :   .n_errors = ARRAY_LEN (acl_fa_error_strings),
     804             :   .error_strings = acl_fa_error_strings,
     805             :   .n_next_nodes = ACL_FA_N_NEXT,
     806             :   .next_nodes =
     807             :   {
     808             :     [ACL_FA_ERROR_DROP] = "error-drop",
     809             :   }
     810             : };
     811             : 
     812       69723 : VNET_FEATURE_INIT (acl_in_l2_ip6_fa_feature, static) =
     813             : {
     814             :   .arc_name = "l2-input-ip6",
     815             :   .node_name = "acl-plugin-in-ip6-l2",
     816             :   .runs_before = VNET_FEATURES ("l2-input-feat-arc-end"),
     817             : };
     818             : 
     819      175724 : VLIB_REGISTER_NODE (acl_in_l2_ip4_node) =
     820             : {
     821             :   .name = "acl-plugin-in-ip4-l2",
     822             :   .vector_size = sizeof (u32),
     823             :   .format_trace = format_acl_plugin_trace,
     824             :   .type = VLIB_NODE_TYPE_INTERNAL,
     825             :   .n_errors = ARRAY_LEN (acl_fa_error_strings),
     826             :   .error_strings = acl_fa_error_strings,
     827             :   .n_next_nodes = ACL_FA_N_NEXT,
     828             :   .next_nodes =
     829             :   {
     830             :     [ACL_FA_ERROR_DROP] = "error-drop",
     831             :   }
     832             : };
     833             : 
     834       69723 : VNET_FEATURE_INIT (acl_in_l2_ip4_fa_feature, static) =
     835             : {
     836             :   .arc_name = "l2-input-ip4",
     837             :   .node_name = "acl-plugin-in-ip4-l2",
     838             :   .runs_before = VNET_FEATURES ("l2-input-feat-arc-end"),
     839             : };
     840             : 
     841             : 
     842      175724 : VLIB_REGISTER_NODE (acl_out_l2_ip6_node) =
     843             : {
     844             :   .name = "acl-plugin-out-ip6-l2",
     845             :   .vector_size = sizeof (u32),
     846             :   .format_trace = format_acl_plugin_trace,
     847             :   .type = VLIB_NODE_TYPE_INTERNAL,
     848             :   .n_errors = ARRAY_LEN (acl_fa_error_strings),
     849             :   .error_strings = acl_fa_error_strings,
     850             :   .n_next_nodes = ACL_FA_N_NEXT,
     851             :   .next_nodes =
     852             :   {
     853             :     [ACL_FA_ERROR_DROP] = "error-drop",
     854             :   }
     855             : };
     856             : 
     857       69723 : VNET_FEATURE_INIT (acl_out_l2_ip6_fa_feature, static) =
     858             : {
     859             :   .arc_name = "l2-output-ip6",
     860             :   .node_name = "acl-plugin-out-ip6-l2",
     861             :   .runs_before = VNET_FEATURES ("l2-output-feat-arc-end"),
     862             : };
     863             : 
     864             : 
     865      175724 : VLIB_REGISTER_NODE (acl_out_l2_ip4_node) =
     866             : {
     867             :   .name = "acl-plugin-out-ip4-l2",
     868             :   .vector_size = sizeof (u32),
     869             :   .format_trace = format_acl_plugin_trace,
     870             :   .type = VLIB_NODE_TYPE_INTERNAL,
     871             :   .n_errors = ARRAY_LEN (acl_fa_error_strings),
     872             :   .error_strings = acl_fa_error_strings,
     873             :   .n_next_nodes = ACL_FA_N_NEXT,
     874             :   .next_nodes =
     875             :   {
     876             :     [ACL_FA_ERROR_DROP] = "error-drop",
     877             :   }
     878             : };
     879             : 
     880       69723 : VNET_FEATURE_INIT (acl_out_l2_ip4_fa_feature, static) =
     881             : {
     882             :   .arc_name = "l2-output-ip4",
     883             :   .node_name = "acl-plugin-out-ip4-l2",
     884             :   .runs_before = VNET_FEATURES ("l2-output-feat-arc-end"),
     885             : };
     886             : 
     887             : 
     888      175724 : VLIB_REGISTER_NODE (acl_in_fa_ip6_node) =
     889             : {
     890             :   .name = "acl-plugin-in-ip6-fa",
     891             :   .vector_size = sizeof (u32),
     892             :   .format_trace = format_acl_plugin_trace,
     893             :   .type = VLIB_NODE_TYPE_INTERNAL,
     894             :   .n_errors = ARRAY_LEN (acl_fa_error_strings),
     895             :   .error_strings = acl_fa_error_strings,
     896             :   .n_next_nodes = ACL_FA_N_NEXT,
     897             :   .next_nodes =
     898             :   {
     899             :     [ACL_FA_ERROR_DROP] = "error-drop",
     900             :   }
     901             : };
     902             : 
     903       69723 : VNET_FEATURE_INIT (acl_in_ip6_fa_feature, static) =
     904             : {
     905             :   .arc_name = "ip6-unicast",
     906             :   .node_name = "acl-plugin-in-ip6-fa",
     907             :   .runs_before = VNET_FEATURES ("ip6-flow-classify"),
     908             : };
     909             : 
     910      175724 : VLIB_REGISTER_NODE (acl_in_fa_ip4_node) =
     911             : {
     912             :   .name = "acl-plugin-in-ip4-fa",
     913             :   .vector_size = sizeof (u32),
     914             :   .format_trace = format_acl_plugin_trace,
     915             :   .type = VLIB_NODE_TYPE_INTERNAL,
     916             :   .n_errors = ARRAY_LEN (acl_fa_error_strings),
     917             :   .error_strings = acl_fa_error_strings,
     918             :   .n_next_nodes = ACL_FA_N_NEXT,
     919             :   .next_nodes =
     920             :   {
     921             :     [ACL_FA_ERROR_DROP] = "error-drop",
     922             :   }
     923             : };
     924             : 
     925       69723 : VNET_FEATURE_INIT (acl_in_ip4_fa_feature, static) =
     926             : {
     927             :   .arc_name = "ip4-unicast",
     928             :   .node_name = "acl-plugin-in-ip4-fa",
     929             :   .runs_before = VNET_FEATURES ("ip4-flow-classify"),
     930             : };
     931             : 
     932             : 
     933      175724 : VLIB_REGISTER_NODE (acl_out_fa_ip6_node) =
     934             : {
     935             :   .name = "acl-plugin-out-ip6-fa",
     936             :   .vector_size = sizeof (u32),
     937             :   .format_trace = format_acl_plugin_trace,
     938             :   .type = VLIB_NODE_TYPE_INTERNAL,
     939             :   .n_errors = ARRAY_LEN (acl_fa_error_strings),
     940             :   .error_strings = acl_fa_error_strings,
     941             :   .n_next_nodes = ACL_FA_N_NEXT,
     942             :   .next_nodes =
     943             :   {
     944             :     [ACL_FA_ERROR_DROP] = "error-drop",
     945             :   }
     946             : };
     947             : 
     948       69723 : VNET_FEATURE_INIT (acl_out_ip6_fa_feature, static) = {
     949             :   .arc_name = "ip6-output",
     950             :   .node_name = "acl-plugin-out-ip6-fa",
     951             :   .runs_before = VNET_FEATURES ("ip6-dvr-reinject", "interface-output"),
     952             : };
     953             : 
     954      175724 : VLIB_REGISTER_NODE (acl_out_fa_ip4_node) =
     955             : {
     956             :   .name = "acl-plugin-out-ip4-fa",
     957             :   .vector_size = sizeof (u32),
     958             :   .format_trace = format_acl_plugin_trace,
     959             :   .type = VLIB_NODE_TYPE_INTERNAL,
     960             :   .n_errors = ARRAY_LEN (acl_fa_error_strings),
     961             :   .error_strings = acl_fa_error_strings,
     962             :   .n_next_nodes = ACL_FA_N_NEXT,
     963             :     /* edit / add dispositions here */
     964             :   .next_nodes =
     965             :   {
     966             :     [ACL_FA_ERROR_DROP] = "error-drop",
     967             :   }
     968             : };
     969             : 
     970       69723 : VNET_FEATURE_INIT (acl_out_ip4_fa_feature, static) = {
     971             :   .arc_name = "ip4-output",
     972             :   .node_name = "acl-plugin-out-ip4-fa",
     973             :   .runs_before = VNET_FEATURES ("ip4-dvr-reinject", "interface-output"),
     974             : };
     975             : 
     976             : /* *INDENT-ON* */
     977             : 
     978             : /*
     979             :  * fd.io coding-style-patch-verification: ON
     980             :  *
     981             :  * Local Variables:
     982             :  * eval: (c-set-style "gnu")
     983             :  * End:
     984             :  */

Generated by: LCOV version 1.14