<commit_before>/*
 *------------------------------------------------------------------
 * Copyright (c) 2018 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *------------------------------------------------------------------
 */

#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vlib/pci/pci.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/devices/devices.h>

#include <vmxnet3/vmxnet3.h>

#define foreach_vmxnet3_input_error \
  _(BUFFER_ALLOC, "buffer alloc error") \
  _(RX_PACKET, "Rx packet error") \
  _(NO_BUFFER, "Rx no buffer error")

typedef enum
{
#define _(f,s) VMXNET3_INPUT_ERROR_##f,
  foreach_vmxnet3_input_error
#undef _
    VMXNET3_INPUT_N_ERROR,
} vmxnet3_input_error_t;

static __clib_unused char *vmxnet3_input_error_strings[] = {
#define _(n,s) s,
  foreach_vmxnet3_input_error
#undef _
};

static_always_inline u16
vmxnet3_find_rid (vmxnet3_device_t * vd, vmxnet3_rx_comp * rx_comp)
{
  u32 rid;

  // rid is bits 16-25 (10 bits number)
  rid = rx_comp->index & (0xffffffff >> 6);
  rid >>= 16;
  if ((rid >= vd->num_rx_queues) && (rid < (vd->num_rx_queues << 1)))
    return 1;
  else
    return 0;
}

static_always_inline void
vmxnet3_rx_comp_ring_advance_next (vmxnet3_rxq_t * rxq)
{
  vmxnet3_rx_comp_ring *comp_ring = &rxq->rx_comp_ring;

  comp_ring->next++;
  if (PREDICT_FALSE (comp_ring->next == rxq->size))
    {
      comp_ring->next = 0;
      comp_ring->gen ^= VMXNET3_RXCF_GEN;
    }
}

static_always_inline uword
vmxnet3_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
			     vlib_frame_t * frame, vmxnet3_device_t * vd,
			     u16 qid)
{
  vnet_main_t *vnm = vnet_get_main ();
  uword n_trace = vlib_get_trace_count (vm, node);
  u32 n_rx_packets = 0, n_rx_bytes = 0;
  vmxnet3_rx_comp *rx_comp;
  u32 comp_idx;
  u32 desc_idx;
  vmxnet3_rxq_t *rxq;
  u32 thread_index = vm->thread_index;
  u32 buffer_indices[VLIB_FRAME_SIZE], *bi;
  u16 nexts[VLIB_FRAME_SIZE], *next;
  vmxnet3_rx_ring *ring;
  vmxnet3_rx_comp_ring *comp_ring;
  u16 rid;
  vlib_buffer_t *prev_b0 = 0, *hb = 0;
  u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
  u8 known_next = 0;

  rxq = vec_elt_at_index (vd->rxqs, qid);
  comp_ring = &rxq->rx_comp_ring;
  bi = buffer_indices;
  next = nexts;
  while (comp_ring->gen ==
	 (rxq->rx_comp[comp_ring->next].flags & VMXNET3_RXCF_GEN))
    {
      vlib_buffer_t *b0;
      u32 bi0;

      comp_idx = comp_ring->next;
      rx_comp = &rxq->rx_comp[comp_idx];

      rid = vmxnet3_find_rid (vd, rx_comp);
      ring = &rxq->rx_ring[rid];

      if (PREDICT_TRUE (ring->fill >= 1))
	ring->fill--;
      else
	{
	  vlib_error_count (vm, node->node_index,
			    VMXNET3_INPUT_ERROR_NO_BUFFER, 1);
	  break;
	}<commit_msg>vmxnet3: guard against array overflow<commit_after>/*
 *------------------------------------------------------------------
 * Copyright (c) 2018 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *------------------------------------------------------------------
 */

#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vlib/pci/pci.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/devices/devices.h>

#include <vmxnet3/vmxnet3.h>

#define foreach_vmxnet3_input_error \
  _(BUFFER_ALLOC, "buffer alloc error") \
  _(RX_PACKET, "Rx packet error") \
  _(NO_BUFFER, "Rx no buffer error")

typedef enum
{
#define _(f,s) VMXNET3_INPUT_ERROR_##f,
  foreach_vmxnet3_input_error
#undef _
    VMXNET3_INPUT_N_ERROR,
} vmxnet3_input_error_t;

static __clib_unused char *vmxnet3_input_error_strings[] = {
#define _(n,s) s,
  foreach_vmxnet3_input_error
#undef _
};

static_always_inline u16
vmxnet3_find_rid (vmxnet3_device_t * vd, vmxnet3_rx_comp * rx_comp)
{
  u32 rid;

  // rid is bits 16-25 (10 bits number)
  rid = rx_comp->index & (0xffffffff >> 6);
  rid >>= 16;
  if ((rid >= vd->num_rx_queues) && (rid < (vd->num_rx_queues << 1)))
    return 1;
  else
    return 0;
}

static_always_inline void
vmxnet3_rx_comp_ring_advance_next (vmxnet3_rxq_t * rxq)
{
  vmxnet3_rx_comp_ring *comp_ring = &rxq->rx_comp_ring;

  comp_ring->next++;
  if (PREDICT_FALSE (comp_ring->next == rxq->size))
    {
      comp_ring->next = 0;
      comp_ring->gen ^= VMXNET3_RXCF_GEN;
    }
}

static_always_inline uword
vmxnet3_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
			     vlib_frame_t * frame, vmxnet3_device_t * vd,
			     u16 qid)
{
  vnet_main_t *vnm = vnet_get_main ();
  uword n_trace = vlib_get_trace_count (vm, node);
  u32 n_rx_packets = 0, n_rx_bytes = 0;
  vmxnet3_rx_comp *rx_comp;
  u32 comp_idx;
  u32 desc_idx;
  vmxnet3_rxq_t *rxq;
  u32 thread_index = vm->thread_index;
  u32 buffer_indices[VLIB_FRAME_SIZE], *bi;
  u16 nexts[VLIB_FRAME_SIZE], *next;
  vmxnet3_rx_ring *ring;
  vmxnet3_rx_comp_ring *comp_ring;
  u16 rid;
  vlib_buffer_t *prev_b0 = 0, *hb = 0;
  u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
  u8 known_next = 0;

  rxq = vec_elt_at_index (vd->rxqs, qid);
  comp_ring = &rxq->rx_comp_ring;
  bi = buffer_indices;
  next = nexts;
  while (PREDICT_TRUE (n_rx_packets < VLIB_FRAME_SIZE) &&
	 (comp_ring->gen ==
	  (rxq->rx_comp[comp_ring->next].flags & VMXNET3_RXCF_GEN)))
    {
      vlib_buffer_t *b0;
      u32 bi0;

      comp_idx = comp_ring->next;
      rx_comp = &rxq->rx_comp[comp_idx];

      rid = vmxnet3_find_rid (vd, rx_comp);
      ring = &rxq->rx_ring[rid];

      if (PREDICT_TRUE (ring->fill >= 1))
	ring->fill--;
      else
	{
	  vlib_error_count (vm, node->node_index,
			    VMXNET3_INPUT_ERROR_NO_BUFFER, 1);
	  break;
	}
{'fraction_non_alphanumeric': 0.1488781079442086, 'fraction_numerical': 0.02501516070345664, 'mean_word_length': 3.242443729903537, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2105542', 'n_tokens_mistral': 2656, 'n_tokens_neox': 2537, 'n_words': 569}