LCOV - code coverage report
Current view: top level - plugins/snort - dequeue.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 2 171 1.2 %
Date: 2023-07-05 22:20:52 Functions: 6 18 33.3 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: Apache-2.0
       2             :  * Copyright(c) 2021 Cisco Systems, Inc.
       3             :  */
       4             : 
       5             : #include <vlib/vlib.h>
       6             : #include <vnet/feature/feature.h>
       7             : #include <snort/snort.h>
       8             : 
       9             : typedef struct
      10             : {
      11             :   u32 next_index;
      12             :   u32 sw_if_index;
      13             : } snort_deq_trace_t;
      14             : 
      15             : static u8 *
      16           0 : format_snort_deq_trace (u8 *s, va_list *args)
      17             : {
      18           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      19           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      20           0 :   snort_deq_trace_t *t = va_arg (*args, snort_deq_trace_t *);
      21             : 
      22           0 :   s = format (s, "snort-deq: sw_if_index %d, next index %d\n", t->sw_if_index,
      23             :               t->next_index);
      24             : 
      25           0 :   return s;
      26             : }
      27             : 
      28             : #define foreach_snort_deq_error                                               \
      29             :   _ (BAD_DESC, "bad descriptor")                                              \
      30             :   _ (BAD_DESC_INDEX, "bad descriptor index")
      31             : 
      32             : typedef enum
      33             : {
      34             : #define _(sym, str) SNORT_DEQ_ERROR_##sym,
      35             :   foreach_snort_deq_error
      36             : #undef _
      37             :     SNORT_DEQ_N_ERROR,
      38             : } snort_deq_error_t;
      39             : 
      40             : static char *snort_deq_error_strings[] = {
      41             : #define _(sym, string) string,
      42             :   foreach_snort_deq_error
      43             : #undef _
      44             : };
      45             : 
      46             : static_always_inline uword
      47           0 : snort_deq_instance (vlib_main_t *vm, u32 instance_index, snort_qpair_t *qp,
      48             :                     u32 *buffer_indices, u16 *nexts, u32 max_recv)
      49             : {
      50           0 :   snort_main_t *sm = &snort_main;
      51           0 :   snort_per_thread_data_t *ptd =
      52           0 :     vec_elt_at_index (sm->per_thread_data, vm->thread_index);
      53           0 :   u32 mask = pow2_mask (qp->log2_queue_size);
      54           0 :   u32 head, next, n_recv = 0, n_left;
      55             : 
      56           0 :   head = __atomic_load_n (qp->deq_head, __ATOMIC_ACQUIRE);
      57           0 :   next = qp->next_desc;
      58             : 
      59           0 :   n_left = head - next;
      60             : 
      61           0 :   if (n_left == 0)
      62           0 :     return 0;
      63             : 
      64           0 :   if (n_left > max_recv)
      65             :     {
      66           0 :       n_left = max_recv;
      67           0 :       clib_interrupt_set (ptd->interrupts, instance_index);
      68           0 :       vlib_node_set_interrupt_pending (vm, snort_deq_node.index);
      69             :     }
      70             : 
      71           0 :   while (n_left)
      72             :     {
      73             :       u32 desc_index, bi;
      74             :       daq_vpp_desc_t *d;
      75             : 
      76             :       /* check if descriptor index taken from dequqe ring is valid */
      77           0 :       if ((desc_index = qp->deq_ring[next & mask]) & ~mask)
      78             :         {
      79           0 :           vlib_node_increment_counter (vm, snort_deq_node.index,
      80             :                                        SNORT_DEQ_ERROR_BAD_DESC_INDEX, 1);
      81           0 :           goto next;
      82             :         }
      83             : 
      84             :       /* check if descriptor index taken from dequeue ring points to enqueued
      85             :        * buffer */
      86           0 :       if ((bi = qp->buffer_indices[desc_index]) == ~0)
      87             :         {
      88           0 :           vlib_node_increment_counter (vm, snort_deq_node.index,
      89             :                                        SNORT_DEQ_ERROR_BAD_DESC, 1);
      90           0 :           goto next;
      91             :         }
      92             : 
      93             :       /* put descriptor back to freelist */
      94           0 :       vec_add1 (qp->freelist, desc_index);
      95           0 :       d = qp->descriptors + desc_index;
      96           0 :       buffer_indices++[0] = bi;
      97           0 :       if (d->action == DAQ_VPP_ACTION_FORWARD)
      98           0 :         nexts[0] = qp->next_indices[desc_index];
      99             :       else
     100           0 :         nexts[0] = SNORT_ENQ_NEXT_DROP;
     101           0 :       qp->buffer_indices[desc_index] = ~0;
     102           0 :       nexts++;
     103           0 :       n_recv++;
     104             : 
     105             :       /* next */
     106           0 :     next:
     107           0 :       next = next + 1;
     108           0 :       n_left--;
     109             :     }
     110             : 
     111           0 :   qp->next_desc = next;
     112             : 
     113           0 :   return n_recv;
     114             : }
     115             : 
     116             : static_always_inline u32
     117           0 : snort_process_all_buffer_indices (snort_qpair_t *qp, u32 *b, u16 *nexts,
     118             :                                   u32 max_recv, u8 drop_on_disconnect)
     119             : {
     120           0 :   u32 *bi, n_processed = 0;
     121           0 :   u32 desc_index = 0;
     122             : 
     123           0 :   vec_foreach (bi, qp->buffer_indices)
     124             :     {
     125           0 :       if (n_processed >= max_recv)
     126           0 :         break;
     127             : 
     128           0 :       if (bi[0] == ~0)
     129           0 :         continue;
     130             : 
     131           0 :       desc_index = bi - qp->buffer_indices;
     132             : 
     133           0 :       b[0] = bi[0];
     134           0 :       if (drop_on_disconnect)
     135           0 :         nexts[0] = SNORT_ENQ_NEXT_DROP;
     136             :       else
     137           0 :         nexts[0] = qp->next_indices[desc_index];
     138           0 :       qp->buffer_indices[desc_index] = ~0;
     139             : 
     140           0 :       nexts += 1;
     141           0 :       b += 1;
     142           0 :       n_processed += 1;
     143             :     }
     144           0 :   return n_processed;
     145             : }
     146             : 
     147             : static_always_inline uword
     148           0 : snort_deq_instance_all_interrupt (vlib_main_t *vm, u32 instance_index,
     149             :                                   snort_qpair_t *qp, u32 *buffer_indices,
     150             :                                   u16 *nexts, u32 max_recv,
     151             :                                   u8 drop_on_disconnect)
     152             : {
     153           0 :   snort_main_t *sm = &snort_main;
     154           0 :   snort_per_thread_data_t *ptd =
     155           0 :     vec_elt_at_index (sm->per_thread_data, vm->thread_index);
     156             :   u32 n_processed;
     157             : 
     158           0 :   n_processed = snort_process_all_buffer_indices (
     159             :     qp, buffer_indices, nexts, max_recv, drop_on_disconnect);
     160             : 
     161           0 :   if (n_processed == max_recv)
     162             :     {
     163           0 :       clib_interrupt_set (ptd->interrupts, instance_index);
     164           0 :       vlib_node_set_interrupt_pending (vm, snort_deq_node.index);
     165             :     }
     166             :   else
     167             :     {
     168           0 :       *qp->enq_head = *qp->deq_head = qp->next_desc = 0;
     169           0 :       snort_freelist_init (qp->freelist);
     170           0 :       __atomic_store_n (&qp->ready, 1, __ATOMIC_RELEASE);
     171             :     }
     172             : 
     173           0 :   return n_processed;
     174             : }
     175             : 
     176             : static u32
     177           0 : snort_deq_node_interrupt (vlib_main_t *vm, vlib_node_runtime_t *node,
     178             :                           vlib_frame_t *frame)
     179             : {
     180           0 :   snort_main_t *sm = &snort_main;
     181           0 :   snort_per_thread_data_t *ptd =
     182           0 :     vec_elt_at_index (sm->per_thread_data, vm->thread_index);
     183           0 :   u32 buffer_indices[VLIB_FRAME_SIZE], *bi = buffer_indices;
     184           0 :   u16 next_indices[VLIB_FRAME_SIZE], *nexts = next_indices;
     185           0 :   u32 n_left = VLIB_FRAME_SIZE, n;
     186             :   snort_qpair_t *qp;
     187             :   snort_instance_t *si;
     188           0 :   int inst = -1;
     189             : 
     190           0 :   while ((inst = clib_interrupt_get_next (ptd->interrupts, inst)) != -1)
     191             :     {
     192           0 :       clib_interrupt_clear (ptd->interrupts, inst);
     193           0 :       si = vec_elt_at_index (sm->instances, inst);
     194           0 :       qp = vec_elt_at_index (si->qpairs, vm->thread_index);
     195           0 :       u32 ready = __atomic_load_n (&qp->ready, __ATOMIC_ACQUIRE);
     196           0 :       if (!ready)
     197           0 :         n = snort_deq_instance_all_interrupt (vm, inst, qp, bi, nexts, n_left,
     198           0 :                                               si->drop_on_disconnect);
     199             :       else
     200           0 :         n = snort_deq_instance (vm, inst, qp, bi, nexts, n_left);
     201             : 
     202           0 :       n_left -= n;
     203           0 :       bi += n;
     204           0 :       nexts += n;
     205             : 
     206           0 :       if (n_left == 0)
     207           0 :         goto enq;
     208             :     }
     209             : 
     210           0 :   if (n_left == VLIB_FRAME_SIZE)
     211           0 :     return 0;
     212             : 
     213           0 : enq:
     214           0 :   n = VLIB_FRAME_SIZE - n_left;
     215           0 :   vlib_buffer_enqueue_to_next (vm, node, buffer_indices, next_indices, n);
     216           0 :   return n;
     217             : }
     218             : 
     219             : static_always_inline uword
     220           0 : snort_deq_instance_poll (vlib_main_t *vm, snort_qpair_t *qp,
     221             :                          u32 *buffer_indices, u16 *nexts, u32 max_recv)
     222             : {
     223           0 :   u32 mask = pow2_mask (qp->log2_queue_size);
     224           0 :   u32 head, next, n_recv = 0, n_left;
     225             : 
     226           0 :   head = __atomic_load_n (qp->deq_head, __ATOMIC_ACQUIRE);
     227           0 :   next = qp->next_desc;
     228             : 
     229           0 :   n_left = head - next;
     230             : 
     231           0 :   if (n_left == 0)
     232           0 :     return 0;
     233             : 
     234           0 :   if (n_left > max_recv)
     235           0 :     n_left = max_recv;
     236             : 
     237           0 :   while (n_left)
     238             :     {
     239             :       u32 desc_index, bi;
     240             :       daq_vpp_desc_t *d;
     241             : 
     242             :       /* check if descriptor index taken from dequqe ring is valid */
     243           0 :       if ((desc_index = qp->deq_ring[next & mask]) & ~mask)
     244             :         {
     245           0 :           vlib_node_increment_counter (vm, snort_deq_node.index,
     246             :                                        SNORT_DEQ_ERROR_BAD_DESC_INDEX, 1);
     247           0 :           goto next;
     248             :         }
     249             : 
     250             :       /* check if descriptor index taken from dequeue ring points to enqueued
     251             :        * buffer */
     252           0 :       if ((bi = qp->buffer_indices[desc_index]) == ~0)
     253             :         {
     254           0 :           vlib_node_increment_counter (vm, snort_deq_node.index,
     255             :                                        SNORT_DEQ_ERROR_BAD_DESC, 1);
     256           0 :           goto next;
     257             :         }
     258             : 
     259             :       /* put descriptor back to freelist */
     260           0 :       vec_add1 (qp->freelist, desc_index);
     261           0 :       d = qp->descriptors + desc_index;
     262           0 :       buffer_indices++[0] = bi;
     263           0 :       if (d->action == DAQ_VPP_ACTION_FORWARD)
     264           0 :         nexts[0] = qp->next_indices[desc_index];
     265             :       else
     266           0 :         nexts[0] = SNORT_ENQ_NEXT_DROP;
     267           0 :       qp->buffer_indices[desc_index] = ~0;
     268           0 :       nexts++;
     269           0 :       n_recv++;
     270             : 
     271             :       /* next */
     272           0 :     next:
     273           0 :       next = next + 1;
     274           0 :       n_left--;
     275             :     }
     276             : 
     277           0 :   qp->next_desc = next;
     278             : 
     279           0 :   return n_recv;
     280             : }
     281             : 
     282             : static_always_inline uword
     283           0 : snort_deq_instance_all_poll (vlib_main_t *vm, snort_qpair_t *qp,
     284             :                              u32 *buffer_indices, u16 *nexts, u32 max_recv,
     285             :                              u8 drop_on_disconnect)
     286             : {
     287           0 :   u32 n_processed = snort_process_all_buffer_indices (
     288             :     qp, buffer_indices, nexts, max_recv, drop_on_disconnect);
     289           0 :   if (n_processed < max_recv)
     290             :     {
     291           0 :       *qp->enq_head = *qp->deq_head = qp->next_desc = 0;
     292           0 :       snort_freelist_init (qp->freelist);
     293           0 :       __atomic_store_n (&qp->ready, 1, __ATOMIC_RELEASE);
     294             :     }
     295             : 
     296           0 :   return n_processed;
     297             : }
     298             : 
     299             : static u32
     300           0 : snort_deq_node_polling (vlib_main_t *vm, vlib_node_runtime_t *node,
     301             :                         vlib_frame_t *frame)
     302             : {
     303           0 :   snort_main_t *sm = &snort_main;
     304           0 :   u32 buffer_indices[VLIB_FRAME_SIZE], *bi = buffer_indices;
     305           0 :   u16 next_indices[VLIB_FRAME_SIZE], *nexts = next_indices;
     306           0 :   u32 n_left = VLIB_FRAME_SIZE, n, n_total = 0;
     307             :   snort_qpair_t *qp;
     308             :   snort_instance_t *si;
     309             : 
     310           0 :   vec_foreach (si, sm->instances)
     311             :     {
     312           0 :       qp = vec_elt_at_index (si->qpairs, vm->thread_index);
     313           0 :       u32 ready = __atomic_load_n (&qp->ready, __ATOMIC_ACQUIRE);
     314           0 :       if (!ready)
     315           0 :         n = snort_deq_instance_all_poll (vm, qp, bi, nexts, n_left,
     316           0 :                                          si->drop_on_disconnect);
     317             :       else
     318           0 :         n = snort_deq_instance_poll (vm, qp, bi, nexts, n_left);
     319             : 
     320           0 :       n_left -= n;
     321           0 :       bi += n;
     322           0 :       nexts += n;
     323             : 
     324           0 :       if (n_left == 0)
     325             :         {
     326           0 :           n = VLIB_FRAME_SIZE - n_left;
     327           0 :           vlib_buffer_enqueue_to_next (vm, node, buffer_indices, next_indices,
     328             :                                        n);
     329           0 :           n_left = VLIB_FRAME_SIZE;
     330           0 :           bi = buffer_indices;
     331           0 :           nexts = next_indices;
     332           0 :           n_total += n;
     333             :         }
     334             :     }
     335             : 
     336           0 :   if (n_left < VLIB_FRAME_SIZE)
     337             :     {
     338           0 :       n = VLIB_FRAME_SIZE - n_left;
     339           0 :       vlib_buffer_enqueue_to_next (vm, node, buffer_indices, next_indices, n);
     340           0 :       n_total += n;
     341             :     }
     342           0 :   return n_total;
     343             : }
     344             : 
     345        2236 : VLIB_NODE_FN (snort_deq_node)
     346             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
     347             : {
     348           0 :   snort_main_t *sm = &snort_main;
     349           0 :   if (sm->input_mode == VLIB_NODE_STATE_POLLING)
     350           0 :     return snort_deq_node_polling (vm, node, frame);
     351           0 :   return snort_deq_node_interrupt (vm, node, frame);
     352             : }
     353             : 
     354       41439 : VLIB_REGISTER_NODE (snort_deq_node) = {
     355             :   .name = "snort-deq",
     356             :   .vector_size = sizeof (u32),
     357             :   .format_trace = format_snort_deq_trace,
     358             :   .type = VLIB_NODE_TYPE_INPUT,
     359             :   .state = VLIB_NODE_STATE_DISABLED,
     360             :   .sibling_of = "snort-enq",
     361             : 
     362             :   .n_errors = ARRAY_LEN (snort_deq_error_strings),
     363             :   .error_strings = snort_deq_error_strings,
     364             : 
     365             :   .n_next_nodes = 0,
     366             : };

Generated by: LCOV version 1.14