FD.io VPP  v17.04.2-2-ga8f93f8
Vector Packet Processing
node.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "ssvm_eth.h"
16 
18 
19 typedef struct
20 {
24 
25 /* packet trace format function */
26 static u8 *
27 format_ssvm_eth_input_trace (u8 * s, va_list * args)
28 {
29  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
30  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
31  ssvm_eth_input_trace_t *t = va_arg (*args, ssvm_eth_input_trace_t *);
32 
33  s = format (s, "SSVM_ETH_INPUT: sw_if_index %d, next index %d",
34  t->sw_if_index, t->next_index);
35  return s;
36 }
37 
39 
40 #define foreach_ssvm_eth_input_error \
41 _(NO_BUFFERS, "Rx packet drops (no buffers)")
42 
43 typedef enum
44 {
45 #define _(sym,str) SSVM_ETH_INPUT_ERROR_##sym,
47 #undef _
50 
51 static char *ssvm_eth_input_error_strings[] = {
52 #define _(sym,string) string,
54 #undef _
55 };
56 
57 typedef enum
58 {
66 
67 static inline uword
69  ssvm_private_t * intfc, vlib_node_runtime_t * node)
70 {
71  ssvm_shared_header_t *sh = intfc->sh;
72  vlib_main_t *vm = em->vlib_main;
74  ssvm_eth_queue_elt_t *elt, *elts;
75  u32 elt_index;
76  u32 my_pid = intfc->my_pid;
77  int rx_queue_index;
78  u32 n_to_alloc = VLIB_FRAME_SIZE * 2;
79  u32 n_allocated, n_present_in_cache;
82  u32 n_left_to_next, *to_next;
83  u32 next0;
84  u32 n_buffers;
85  u32 n_available;
86  u32 bi0, saved_bi0;
87  vlib_buffer_t *b0, *prev;
88  u32 saved_cache_size = 0;
89  ethernet_header_t *eh0;
90  u16 type0;
91  u32 n_rx_bytes = 0, l3_offset0;
92  u32 cpu_index = os_get_cpu_number ();
93  u32 trace_cnt __attribute__ ((unused)) = vlib_get_trace_count (vm, node);
94  volatile u32 *lock;
95  u32 *elt_indices;
96  uword n_trace = vlib_get_trace_count (vm, node);
97 
98  /* Either side down? buh-bye... */
101  return 0;
102 
103  if (intfc->i_am_master)
105  else
107 
108  /* Nothing to do? */
109  if (q->cursize == 0)
110  return 0;
111 
113 
114  vec_reset_length (intfc->rx_queue);
115 
116  lock = (u32 *) q;
117  while (__sync_lock_test_and_set (lock, 1))
118  ;
119  while (q->cursize > 0)
120  {
121  unix_shared_memory_queue_sub_raw (q, (u8 *) & elt_index);
122  ASSERT (elt_index < 2048);
123  vec_add1 (intfc->rx_queue, elt_index);
124  }
126  *lock = 0;
127 
128  n_present_in_cache = vec_len (em->buffer_cache);
129 
130  if (vec_len (em->buffer_cache) < vec_len (intfc->rx_queue) * 2)
131  {
133  n_to_alloc + vec_len (em->buffer_cache) - 1);
134  n_allocated =
135  vlib_buffer_alloc (vm, &em->buffer_cache[n_present_in_cache],
136  n_to_alloc);
137 
138  n_present_in_cache += n_allocated;
139  _vec_len (em->buffer_cache) = n_present_in_cache;
140  }
141 
142  elts = (ssvm_eth_queue_elt_t *) (sh->opaque[CHUNK_POOL_INDEX]);
143 
144  n_buffers = vec_len (intfc->rx_queue);
145  rx_queue_index = 0;
146 
147  while (n_buffers > 0)
148  {
149  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
150 
151  while (n_buffers > 0 && n_left_to_next > 0)
152  {
153  elt = elts + intfc->rx_queue[rx_queue_index];
154 
155  saved_cache_size = n_present_in_cache;
156  if (PREDICT_FALSE (saved_cache_size == 0))
157  {
158  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
159  goto out;
160  }
161  saved_bi0 = bi0 = em->buffer_cache[--n_present_in_cache];
162  b0 = vlib_get_buffer (vm, bi0);
163  prev = 0;
164 
165  while (1)
166  {
168 
169  b0->current_data = elt->current_data_hint;
173 
174  clib_memcpy (b0->data + b0->current_data, elt->data,
175  b0->current_length);
176 
177  if (PREDICT_FALSE (prev != 0))
178  prev->next_buffer = bi0;
179 
181  {
182  prev = b0;
183  if (PREDICT_FALSE (n_present_in_cache == 0))
184  {
185  vlib_put_next_frame (vm, node, next_index,
186  n_left_to_next);
187  goto out;
188  }
189  bi0 = em->buffer_cache[--n_present_in_cache];
190  b0 = vlib_get_buffer (vm, bi0);
191  }
192  else
193  break;
194  }
195 
196  saved_cache_size = n_present_in_cache;
197 
198  to_next[0] = saved_bi0;
199  to_next++;
200  n_left_to_next--;
201 
202  b0 = vlib_get_buffer (vm, saved_bi0);
203  eh0 = vlib_buffer_get_current (b0);
204 
205  type0 = clib_net_to_host_u16 (eh0->type);
206 
208 
209  if (type0 == ETHERNET_TYPE_IP4)
211  else if (type0 == ETHERNET_TYPE_IP6)
213  else if (type0 == ETHERNET_TYPE_MPLS_UNICAST)
215 
216  l3_offset0 = ((next0 == SSVM_ETH_INPUT_NEXT_IP4_INPUT ||
219  sizeof (ethernet_header_t) : 0);
220 
221  n_rx_bytes += b0->current_length
223 
224  b0->current_data += l3_offset0;
225  b0->current_length -= l3_offset0;
227 
228  vnet_buffer (b0)->sw_if_index[VLIB_RX] = intfc->vlib_hw_if_index;
229  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
230 
231  /*
232  * Turn this on if you run into
233  * "bad monkey" contexts, and you want to know exactly
234  * which nodes they've visited... See main.c...
235  */
237 
238  if (PREDICT_FALSE (n_trace > 0))
239  {
241 
242  vlib_trace_buffer (vm, node, next0, b0, /* follow_chain */ 1);
243  vlib_set_trace_count (vm, node, --n_trace);
244 
245  tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
246 
247  tr->next_index = next0;
248  tr->sw_if_index = intfc->vlib_hw_if_index;
249  }
250 
251  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
252  to_next, n_left_to_next,
253  bi0, next0);
254  n_buffers--;
255  rx_queue_index++;
256  }
257 
258  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
259  }
260 
261 out:
262  if (em->buffer_cache)
263  _vec_len (em->buffer_cache) = saved_cache_size;
264  else
265  ASSERT (saved_cache_size == 0);
266 
267  ssvm_lock (sh, my_pid, 2);
268 
269  ASSERT (vec_len (intfc->rx_queue) > 0);
270 
271  n_available = (u32) pointer_to_uword (sh->opaque[CHUNK_POOL_NFREE]);
272  elt_indices = (u32 *) (sh->opaque[CHUNK_POOL_FREELIST_INDEX]);
273 
274  clib_memcpy (&elt_indices[n_available], intfc->rx_queue,
275  vec_len (intfc->rx_queue) * sizeof (u32));
276 
277  n_available += vec_len (intfc->rx_queue);
278  sh->opaque[CHUNK_POOL_NFREE] = uword_to_pointer (n_available, void *);
279 
280  ssvm_unlock (sh);
281 
282  vlib_error_count (vm, node->node_index, SSVM_ETH_INPUT_ERROR_NO_BUFFERS,
283  n_buffers);
284 
286  (vnet_get_main ()->interface_main.combined_sw_if_counters
287  + VNET_INTERFACE_COUNTER_RX, cpu_index,
288  intfc->vlib_hw_if_index, rx_queue_index, n_rx_bytes);
289 
290  vnet_device_increment_rx_packets (cpu_index, rx_queue_index);
291 
292  return rx_queue_index;
293 }
294 
295 static uword
297  vlib_node_runtime_t * node, vlib_frame_t * frame)
298 {
300  ssvm_private_t *intfc;
301  uword n_rx_packets = 0;
302 
303  vec_foreach (intfc, em->intfcs)
304  {
305  n_rx_packets += ssvm_eth_device_input (em, intfc, node);
306  }
307 
308  return n_rx_packets;
309 }
310 
311 /* *INDENT-OFF* */
313  .function = ssvm_eth_input_node_fn,
314  .name = "ssvm_eth_input",
315  .vector_size = sizeof (u32),
316  .format_trace = format_ssvm_eth_input_trace,
317  .type = VLIB_NODE_TYPE_INPUT,
318  .state = VLIB_NODE_STATE_DISABLED,
319 
321  .error_strings = ssvm_eth_input_error_strings,
322 
323  .n_next_nodes = SSVM_ETH_INPUT_N_NEXT,
324 
325  /* edit / add dispositions here */
326  .next_nodes = {
327  [SSVM_ETH_INPUT_NEXT_DROP] = "error-drop",
328  [SSVM_ETH_INPUT_NEXT_ETHERNET_INPUT] = "ethernet-input",
329  [SSVM_ETH_INPUT_NEXT_IP4_INPUT] = "ip4-input",
330  [SSVM_ETH_INPUT_NEXT_IP6_INPUT] = "ip6-input",
331  [SSVM_ETH_INPUT_NEXT_MPLS_INPUT] = "mpls-input",
332  },
333 };
334 
336 /* *INDENT-ON* */
337 
338 
339 /*
340  * fd.io coding-style-patch-verification: ON
341  *
342  * Local Variables:
343  * eval: (c-set-style "gnu")
344  * End:
345  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
static u8 * format_ssvm_eth_input_trace(u8 *s, va_list *args)
Definition: node.c:27
#define CLIB_UNUSED(x)
Definition: clib.h:79
u32 vlib_hw_if_index
Definition: ssvm.h:79
static u32 vlib_get_trace_count(vlib_main_t *vm, vlib_node_runtime_t *rt)
Definition: trace_funcs.h:143
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
ssvm_eth_input_next_t
Definition: node.c:57
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:459
u32 * buffer_cache
Definition: ssvm_eth.h:66
void * opaque[SSVM_N_OPAQUE]
Definition: ssvm.h:65
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
#define SSVM_BUFFER_NEXT_PRESENT
Definition: ssvm_eth.h:47
struct _vlib_node_registration vlib_node_registration_t
ssvm_eth_input_error_t
Definition: node.c:43
ssvm_shared_header_t * sh
Definition: ssvm.h:76
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static void vlib_trace_buffer(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, vlib_buffer_t *b, int follow_chain)
Definition: trace_funcs.h:104
static void vnet_device_increment_rx_packets(u32 cpu_index, u64 count)
Definition: devices.h:98
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:67
#define VLIB_BUFFER_TOTAL_LENGTH_VALID
Definition: buffer.h:89
vlib_node_registration_t ssvm_eth_input_node
(constructor) VLIB_REGISTER_NODE (ssvm_eth_input_node)
Definition: node.c:17
static uword pointer_to_uword(const void *p)
Definition: types.h:131
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:71
static void ssvm_unlock(ssvm_shared_header_t *h)
Definition: ssvm.h:105
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
vlib_main_t * vlib_main
Definition: ssvm_eth.h:80
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:390
#define PREDICT_FALSE(x)
Definition: clib.h:97
ssvm_private_t * intfcs
Definition: ssvm_eth.h:64
int unix_shared_memory_queue_sub_raw(unix_shared_memory_queue_t *q, u8 *elem)
#define VLIB_FRAME_SIZE
Definition: node.h:328
u32 node_index
Node index.
Definition: node.h:436
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:216
u32 * rx_queue
Definition: ssvm.h:84
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:350
#define uword_to_pointer(u, type)
Definition: types.h:136
vlib_main_t * vm
Definition: buffer.c:276
static char * ssvm_eth_input_error_strings[]
Definition: node.c:51
#define clib_memcpy(a, b, c)
Definition: string.h:69
#define ARRAY_LEN(x)
Definition: clib.h:59
u32 my_pid
Definition: ssvm.h:78
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 cpu_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:211
vhost_vring_state_t state
Definition: vhost-user.h:83
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:109
#define foreach_ssvm_eth_input_error
Definition: node.c:40
u8 data[SSVM_BUFFER_SIZE]
Definition: ssvm_eth.h:56
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:103
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
ssvm_eth_main_t ssvm_eth_main
Definition: ssvm_eth.c:17
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
Definition: buffer.h:484
u16 total_length_not_including_first_buffer
Definition: ssvm_eth.h:52
static void vlib_buffer_init_for_free_list(vlib_buffer_t *dst, vlib_buffer_free_list_t *fl)
Definition: buffer_funcs.h:777
#define vnet_buffer(b)
Definition: buffer.h:294
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 data[0]
Packet data.
Definition: buffer.h:152
#define vec_foreach(var, vec)
Vector iterator.
static uword ssvm_eth_device_input(ssvm_eth_main_t *em, ssvm_private_t *intfc, vlib_node_runtime_t *node)
Definition: node.c:68
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:101
static vlib_buffer_free_list_t * vlib_buffer_get_free_list(vlib_main_t *vm, u32 free_list_index)
Definition: buffer_funcs.h:385
static uword ssvm_eth_input_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node.c:296
static void vlib_set_trace_count(vlib_main_t *vm, vlib_node_runtime_t *rt, u32 count)
Definition: trace_funcs.h:159
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:74
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:245
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
int i_am_master
Definition: ssvm.h:82
VLIB_NODE_FUNCTION_MULTIARCH(ethernet_input_not_l2_node, ethernet_input_not_l2)
Definition: node.c:1170
static void ssvm_lock(ssvm_shared_header_t *h, u32 my_pid, u32 tag)
Definition: ssvm.h:88
Definition: defs.h:46
struct _unix_shared_memory_queue unix_shared_memory_queue_t