FD.io VPP  v17.10-9-gd594711
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 VNET_FEATURE_ARC_INIT (device_input, static) =
56 {
57  .arc_name = "device-input",
58  .start_nodes = VNET_FEATURES ("device-input"),
60 };
61 
62 VNET_FEATURE_INIT (l2_patch, static) = {
63  .arc_name = "device-input",
64  .node_name = "l2-patch",
65  .runs_before = VNET_FEATURES ("ethernet-input"),
66 };
67 
68 VNET_FEATURE_INIT (worker_handoff, static) = {
69  .arc_name = "device-input",
70  .node_name = "worker-handoff",
71  .runs_before = VNET_FEATURES ("ethernet-input"),
72 };
73 
74 VNET_FEATURE_INIT (span_input, static) = {
75  .arc_name = "device-input",
76  .node_name = "span-input",
77  .runs_before = VNET_FEATURES ("ethernet-input"),
78 };
79 
80 VNET_FEATURE_INIT (p2p_ethernet_node, static) = {
81  .arc_name = "device-input",
82  .node_name = "p2p-ethernet-input",
83  .runs_before = VNET_FEATURES ("ethernet-input"),
84 };
85 
87  .arc_name = "device-input",
88  .node_name = "ethernet-input",
89  .runs_before = 0, /* not before any other features */
90 };
91 /* *INDENT-ON* */
92 
93 static int
94 vnet_device_queue_sort (void *a1, void *a2)
95 {
96  vnet_device_and_queue_t *dq1 = a1;
97  vnet_device_and_queue_t *dq2 = a2;
98 
99  if (dq1->dev_instance > dq2->dev_instance)
100  return 1;
101  else if (dq1->dev_instance < dq2->dev_instance)
102  return -1;
103  else if (dq1->queue_id > dq2->queue_id)
104  return 1;
105  else if (dq1->queue_id < dq2->queue_id)
106  return -1;
107  else
108  return 0;
109 }
110 
111 static void
113 {
116 
118 
120  {
121  hw = vnet_get_hw_interface (vnm, dq->hw_if_index);
124  }
125 }
126 
127 void
129  u16 queue_id, uword thread_index)
130 {
132  vlib_main_t *vm, *vm0;
135  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
136 
137  ASSERT (hw->input_node_index > 0);
138 
139  if (vdm->first_worker_thread_index == 0)
140  thread_index = 0;
141 
142  if (thread_index != 0 &&
143  (thread_index < vdm->first_worker_thread_index ||
144  thread_index > vdm->last_worker_thread_index))
145  {
146  thread_index = vdm->next_worker_thread_index++;
149  }
150 
151  vm = vlib_mains[thread_index];
152  vm0 = vlib_get_main ();
153 
155 
157 
158  vec_add2 (rt->devices_and_queues, dq, 1);
159  dq->hw_if_index = hw_if_index;
160  dq->dev_instance = hw->dev_instance;
161  dq->queue_id = queue_id;
163  rt->enabled_node_state = VLIB_NODE_STATE_POLLING;
164 
165  vnet_device_queue_update (vnm, rt);
167  vec_validate (hw->rx_mode_by_queue, queue_id);
168  hw->input_node_thread_index_by_queue[queue_id] = thread_index;
170 
172 
174 }
175 
176 int
178  u16 queue_id)
179 {
180  vlib_main_t *vm, *vm0;
181  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
184  uword old_thread_index;
186 
188  return VNET_API_ERROR_INVALID_INTERFACE;
189 
190  if (vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1)
191  return VNET_API_ERROR_INVALID_INTERFACE;
192 
193  old_thread_index = hw->input_node_thread_index_by_queue[queue_id];
194 
195  vm = vlib_mains[old_thread_index];
196 
198 
200  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
201  {
202  mode = dq->mode;
203  goto delete;
204  }
205 
206  return VNET_API_ERROR_INVALID_INTERFACE;
207 
208 delete:
209 
210  vm0 = vlib_get_main ();
213  vnet_device_queue_update (vnm, rt);
216 
217  if (vec_len (rt->devices_and_queues) == 0)
218  vlib_node_set_state (vm, hw->input_node_index, VLIB_NODE_STATE_DISABLED);
219  else if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
220  {
221  /*
222  * if the deleted interface is polling, we may need to set the node state
223  * to interrupt if there is no more polling interface for this device's
224  * corresponding thread. This is because mixed interfaces
225  * (polling and interrupt), assigned to the same thread, set the
226  * thread to polling prior to the deletion.
227  */
229  {
231  return 0;
232  }
233  rt->enabled_node_state = VLIB_NODE_STATE_INTERRUPT;
235  }
236 
237  return 0;
238 }
239 
240 
241 int
243  u16 queue_id, vnet_hw_interface_rx_mode mode)
244 {
245  vlib_main_t *vm;
246  uword thread_index;
248  vlib_node_state_t enabled_node_state;
250  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
252  int is_polling = 0;
253 
255  mode = hw->default_rx_mode;
256 
257  if (hw->input_node_thread_index_by_queue == 0 || hw->rx_mode_by_queue == 0)
258  return VNET_API_ERROR_INVALID_INTERFACE;
259 
260  if (hw->rx_mode_by_queue[queue_id] == mode)
261  return 0;
262 
263  if (mode != VNET_HW_INTERFACE_RX_MODE_POLLING &&
265  return VNET_API_ERROR_UNSUPPORTED;
266 
267  if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) ||
268  (vec_len (hw->rx_mode_by_queue) < queue_id + 1))
269  return VNET_API_ERROR_INVALID_QUEUE;
270 
271  hw->rx_mode_by_queue[queue_id] = mode;
272  thread_index = hw->input_node_thread_index_by_queue[queue_id];
273  vm = vlib_mains[thread_index];
274 
276 
278  {
279  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
280  dq->mode = mode;
282  is_polling = 1;
283  }
284 
285  if (is_polling)
286  enabled_node_state = VLIB_NODE_STATE_POLLING;
287  else
288  enabled_node_state = VLIB_NODE_STATE_INTERRUPT;
289 
290  if (rt->enabled_node_state != enabled_node_state)
291  {
292  rt->enabled_node_state = enabled_node_state;
293  if (vlib_node_get_state (vm, hw->input_node_index) !=
294  VLIB_NODE_STATE_DISABLED)
295  vlib_node_set_state (vm, hw->input_node_index, enabled_node_state);
296  }
297 
298  return 0;
299 }
300 
301 int
303  u16 queue_id, vnet_hw_interface_rx_mode * mode)
304 {
305  vlib_main_t *vm;
306  uword thread_index;
308  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
310 
312  return VNET_API_ERROR_INVALID_INTERFACE;
313 
314  if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) ||
315  (vec_len (hw->rx_mode_by_queue) < queue_id + 1))
316  return VNET_API_ERROR_INVALID_QUEUE;
317 
318  thread_index = hw->input_node_thread_index_by_queue[queue_id];
319  vm = vlib_mains[thread_index];
320 
322 
324  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
325  {
326  *mode = dq->mode;
327  return 0;
328  }
329 
330  return VNET_API_ERROR_INVALID_INTERFACE;
331 }
332 
333 
334 
335 static clib_error_t *
337 {
341  uword *p;
342 
345 
346  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
347  tr = p ? (vlib_thread_registration_t *) p[0] : 0;
348  if (tr && tr->count > 0)
349  {
352  vdm->last_worker_thread_index = tr->first_index + tr->count - 1;
353  }
354  return 0;
355 }
356 
358 
359 /*
360  * fd.io coding-style-patch-verification: ON
361  *
362  * Local Variables:
363  * eval: (c-set-style "gnu")
364  * End:
365  */
#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:336
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:488
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:495
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:112
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:302
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
#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:128
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:771
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:177
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1488
#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:492
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:242
#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:94
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