FD.io VPP  v18.01-8-g0eacf49
Vector Packet Processing
devices.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 
16 #include <vnet/vnet.h>
17 #include <vnet/devices/devices.h>
18 #include <vnet/feature/feature.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ethernet/ethernet.h>
21 
23 
24 static uword
26  vlib_frame_t * frame)
27 {
28  return 0;
29 }
30 
31 /* *INDENT-OFF* */
33  .function = device_input_fn,
34  .name = "device-input",
35  .runtime_data_bytes = sizeof (vnet_device_input_runtime_t),
36  .type = VLIB_NODE_TYPE_INPUT,
37  .state = VLIB_NODE_STATE_DISABLED,
38  .n_next_nodes = VNET_DEVICE_INPUT_N_NEXT_NODES,
39  .next_nodes = VNET_DEVICE_INPUT_NEXT_NODES,
40 };
41 
42 /* Table defines how much we need to advance current data pointer
43  in the buffer if we shortcut to l3 nodes */
44 
45 const u32 __attribute__((aligned (CLIB_CACHE_LINE_BYTES)))
48 {
53 };
54 
55 const u32 __attribute__((aligned (CLIB_CACHE_LINE_BYTES)))
58 {
59  [VNET_DEVICE_INPUT_NEXT_IP4_INPUT] = VNET_BUFFER_F_L3_HDR_OFFSET_VALID,
60  [VNET_DEVICE_INPUT_NEXT_IP4_NCS_INPUT] = VNET_BUFFER_F_L3_HDR_OFFSET_VALID,
61  [VNET_DEVICE_INPUT_NEXT_IP6_INPUT] = VNET_BUFFER_F_L3_HDR_OFFSET_VALID,
62  [VNET_DEVICE_INPUT_NEXT_MPLS_INPUT] = VNET_BUFFER_F_L3_HDR_OFFSET_VALID,
63 };
64 
65 VNET_FEATURE_ARC_INIT (device_input, static) =
66 {
67  .arc_name = "device-input",
68  .start_nodes = VNET_FEATURES ("device-input"),
70 };
71 
72 VNET_FEATURE_INIT (l2_patch, static) = {
73  .arc_name = "device-input",
74  .node_name = "l2-patch",
75  .runs_before = VNET_FEATURES ("ethernet-input"),
76 };
77 
78 VNET_FEATURE_INIT (worker_handoff, static) = {
79  .arc_name = "device-input",
80  .node_name = "worker-handoff",
81  .runs_before = VNET_FEATURES ("ethernet-input"),
82 };
83 
84 VNET_FEATURE_INIT (span_input, static) = {
85  .arc_name = "device-input",
86  .node_name = "span-input",
87  .runs_before = VNET_FEATURES ("ethernet-input"),
88 };
89 
90 VNET_FEATURE_INIT (p2p_ethernet_node, static) = {
91  .arc_name = "device-input",
92  .node_name = "p2p-ethernet-input",
93  .runs_before = VNET_FEATURES ("ethernet-input"),
94 };
95 
97  .arc_name = "device-input",
98  .node_name = "ethernet-input",
99  .runs_before = 0, /* not before any other features */
100 };
101 /* *INDENT-ON* */
102 
103 static int
104 vnet_device_queue_sort (void *a1, void *a2)
105 {
106  vnet_device_and_queue_t *dq1 = a1;
107  vnet_device_and_queue_t *dq2 = a2;
108 
109  if (dq1->dev_instance > dq2->dev_instance)
110  return 1;
111  else if (dq1->dev_instance < dq2->dev_instance)
112  return -1;
113  else if (dq1->queue_id > dq2->queue_id)
114  return 1;
115  else if (dq1->queue_id < dq2->queue_id)
116  return -1;
117  else
118  return 0;
119 }
120 
121 static void
123 {
126 
128 
130  {
131  hw = vnet_get_hw_interface (vnm, dq->hw_if_index);
134  }
135 }
136 
137 void
139  u16 queue_id, uword thread_index)
140 {
142  vlib_main_t *vm, *vm0;
145  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
146 
147  ASSERT (hw->input_node_index > 0);
148 
149  if (vdm->first_worker_thread_index == 0)
150  thread_index = 0;
151 
152  if (thread_index != 0 &&
153  (thread_index < vdm->first_worker_thread_index ||
154  thread_index > vdm->last_worker_thread_index))
155  {
156  thread_index = vdm->next_worker_thread_index++;
159  }
160 
161  vm = vlib_mains[thread_index];
162  vm0 = vlib_get_main ();
163 
165 
167 
168  vec_add2 (rt->devices_and_queues, dq, 1);
169  dq->hw_if_index = hw_if_index;
170  dq->dev_instance = hw->dev_instance;
171  dq->queue_id = queue_id;
173  rt->enabled_node_state = VLIB_NODE_STATE_POLLING;
174 
175  vnet_device_queue_update (vnm, rt);
177  vec_validate (hw->rx_mode_by_queue, queue_id);
178  hw->input_node_thread_index_by_queue[queue_id] = thread_index;
180 
182 
184 }
185 
186 int
188  u16 queue_id)
189 {
190  vlib_main_t *vm, *vm0;
191  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
194  uword old_thread_index;
196 
198  return VNET_API_ERROR_INVALID_INTERFACE;
199 
200  if (vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1)
201  return VNET_API_ERROR_INVALID_INTERFACE;
202 
203  old_thread_index = hw->input_node_thread_index_by_queue[queue_id];
204 
205  vm = vlib_mains[old_thread_index];
206 
208 
210  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
211  {
212  mode = dq->mode;
213  goto delete;
214  }
215 
216  return VNET_API_ERROR_INVALID_INTERFACE;
217 
218 delete:
219 
220  vm0 = vlib_get_main ();
223  vnet_device_queue_update (vnm, rt);
226 
227  if (vec_len (rt->devices_and_queues) == 0)
228  vlib_node_set_state (vm, hw->input_node_index, VLIB_NODE_STATE_DISABLED);
229  else if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
230  {
231  /*
232  * if the deleted interface is polling, we may need to set the node state
233  * to interrupt if there is no more polling interface for this device's
234  * corresponding thread. This is because mixed interfaces
235  * (polling and interrupt), assigned to the same thread, set the
236  * thread to polling prior to the deletion.
237  */
239  {
241  return 0;
242  }
243  rt->enabled_node_state = VLIB_NODE_STATE_INTERRUPT;
245  }
246 
247  return 0;
248 }
249 
250 
251 int
253  u16 queue_id, vnet_hw_interface_rx_mode mode)
254 {
255  vlib_main_t *vm;
256  uword thread_index;
258  vlib_node_state_t enabled_node_state;
260  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
262  int is_polling = 0;
263 
265  mode = hw->default_rx_mode;
266 
267  if (hw->input_node_thread_index_by_queue == 0 || hw->rx_mode_by_queue == 0)
268  return VNET_API_ERROR_INVALID_INTERFACE;
269 
270  if (hw->rx_mode_by_queue[queue_id] == mode)
271  return 0;
272 
273  if (mode != VNET_HW_INTERFACE_RX_MODE_POLLING &&
275  return VNET_API_ERROR_UNSUPPORTED;
276 
277  if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) ||
278  (vec_len (hw->rx_mode_by_queue) < queue_id + 1))
279  return VNET_API_ERROR_INVALID_QUEUE;
280 
281  hw->rx_mode_by_queue[queue_id] = mode;
282  thread_index = hw->input_node_thread_index_by_queue[queue_id];
283  vm = vlib_mains[thread_index];
284 
286 
288  {
289  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
290  dq->mode = mode;
292  is_polling = 1;
293  }
294 
295  if (is_polling)
296  enabled_node_state = VLIB_NODE_STATE_POLLING;
297  else
298  enabled_node_state = VLIB_NODE_STATE_INTERRUPT;
299 
300  if (rt->enabled_node_state != enabled_node_state)
301  {
302  rt->enabled_node_state = enabled_node_state;
303  if (vlib_node_get_state (vm, hw->input_node_index) !=
304  VLIB_NODE_STATE_DISABLED)
305  vlib_node_set_state (vm, hw->input_node_index, enabled_node_state);
306  }
307 
308  return 0;
309 }
310 
311 int
313  u16 queue_id, vnet_hw_interface_rx_mode * mode)
314 {
315  vlib_main_t *vm;
316  uword thread_index;
318  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
320 
322  return VNET_API_ERROR_INVALID_INTERFACE;
323 
324  if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) ||
325  (vec_len (hw->rx_mode_by_queue) < queue_id + 1))
326  return VNET_API_ERROR_INVALID_QUEUE;
327 
328  thread_index = hw->input_node_thread_index_by_queue[queue_id];
329  vm = vlib_mains[thread_index];
330 
332 
334  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
335  {
336  *mode = dq->mode;
337  return 0;
338  }
339 
340  return VNET_API_ERROR_INVALID_INTERFACE;
341 }
342 
343 
344 
345 static clib_error_t *
347 {
351  uword *p;
352 
355 
356  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
357  tr = p ? (vlib_thread_registration_t *) p[0] : 0;
358  if (tr && tr->count > 0)
359  {
362  vdm->last_worker_thread_index = tr->first_index + tr->count - 1;
363  }
364  return 0;
365 }
366 
368 
369 /*
370  * fd.io coding-style-patch-verification: ON
371  *
372  * Local Variables:
373  * eval: (c-set-style "gnu")
374  * End:
375  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
static clib_error_t * vnet_device_init(vlib_main_t *vm)
Definition: devices.c:346
vnet_device_and_queue_t * devices_and_queues
Definition: devices.h:69
uword first_worker_thread_index
Definition: devices.h:53
u32 * input_node_thread_index_by_queue
Definition: interface.h:492
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
vnet_device_per_worker_data_t * workers
Definition: devices.h:52
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:557
uword next_worker_thread_index
Definition: devices.h:55
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:443
uword * dq_runtime_index_by_queue
Definition: interface.h:499
vlib_main_t ** vlib_mains
Definition: buffer.c:292
vlib_node_state_t
Definition: node.h:207
uword last_worker_thread_index
Definition: devices.h:54
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:212
vlib_node_state_t enabled_node_state
Definition: devices.h:70
vnet_hw_interface_rx_mode
Definition: interface.h:51
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static uword device_input_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: devices.c:25
static vlib_node_state_t vlib_node_get_state(vlib_main_t *vm, u32 node_index)
Get node dispatch state.
Definition: node_funcs.h:187
const u32 device_input_next_node_advance[((VNET_DEVICE_INPUT_N_NEXT_NODES/CLIB_CACHE_LINE_BYTES)+1)*CLIB_CACHE_LINE_BYTES]
Definition: devices.c:47
static void vnet_device_queue_update(vnet_main_t *vnm, vnet_device_input_runtime_t *rt)
Definition: devices.c:122
int vnet_hw_interface_get_rx_mode(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id, vnet_hw_interface_rx_mode *mode)
Definition: devices.c:312
static void * vlib_node_get_runtime_data(vlib_main_t *vm, u32 node_index)
Get node runtime private data by node index.
Definition: node_funcs.h:110
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:801
#define VNET_DEVICE_INPUT_NEXT_NODES
Definition: devices.h:33
#define VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE
Definition: interface.h:420
vnet_hw_interface_rx_mode mode
Definition: devices.h:63
vlib_main_t * vm
Definition: buffer.c:283
const u32 device_input_next_node_flags[((VNET_DEVICE_INPUT_N_NEXT_NODES/CLIB_CACHE_LINE_BYTES)+1)*CLIB_CACHE_LINE_BYTES]
Definition: devices.c:57
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
void vnet_hw_interface_assign_rx_thread(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id, uword thread_index)
Definition: devices.c:138
vhost_vring_state_t state
Definition: vhost-user.h:82
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
Definition: node_funcs.h:147
uword * thread_registrations_by_name
Definition: threads.h:297
#define VNET_FEATURES(...)
Definition: feature.h:368
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u64 uword
Definition: types.h:112
u8 device_input_feature_arc_index
Feature arc index for device-input.
Definition: feature.h:93
unsigned short u16
Definition: types.h:57
VNET_FEATURE_INIT(l2_patch, static)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:956
static uword ethernet_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: node.c:793
VNET_FEATURE_ARC_INIT(device_input, static)
#define hash_get_mem(h, key)
Definition: hash.h:268
int vnet_hw_interface_unassign_rx_thread(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id)
Definition: devices.c:187
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1491
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
#define vec_foreach(var, vec)
Vector iterator.
vnet_hw_interface_rx_mode default_rx_mode
Definition: interface.h:496
int vnet_hw_interface_set_rx_mode(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id, vnet_hw_interface_rx_mode mode)
Definition: devices.c:252
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
vnet_feature_main_t feature_main
Definition: feature.c:19
static int vnet_device_queue_sort(void *a1, void *a2)
Definition: devices.c:104
vnet_device_main_t vnet_device_main
Definition: devices.c:22
vlib_node_registration_t device_input_node
(constructor) VLIB_REGISTER_NODE (device_input_node)
Definition: devices.c:32