FD.io VPP  v17.07.01-10-g3be13f0
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 
81  .arc_name = "device-input",
82  .node_name = "ethernet-input",
83  .runs_before = 0, /* not before any other features */
84 };
85 /* *INDENT-ON* */
86 
87 static int
88 vnet_device_queue_sort (void *a1, void *a2)
89 {
90  vnet_device_and_queue_t *dq1 = a1;
91  vnet_device_and_queue_t *dq2 = a2;
92 
93  if (dq1->dev_instance > dq2->dev_instance)
94  return 1;
95  else if (dq1->dev_instance < dq2->dev_instance)
96  return -1;
97  else if (dq1->queue_id > dq2->queue_id)
98  return 1;
99  else if (dq1->queue_id < dq2->queue_id)
100  return -1;
101  else
102  return 0;
103 }
104 
105 static void
107 {
110 
112 
114  {
115  hw = vnet_get_hw_interface (vnm, dq->hw_if_index);
118  }
119 }
120 
121 void
123  u16 queue_id, uword thread_index)
124 {
126  vlib_main_t *vm, *vm0;
129  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
130 
131  ASSERT (hw->input_node_index > 0);
132 
133  if (vdm->first_worker_thread_index == 0)
134  thread_index = 0;
135 
136  if (thread_index != 0 &&
137  (thread_index < vdm->first_worker_thread_index ||
138  thread_index > vdm->last_worker_thread_index))
139  {
140  thread_index = vdm->next_worker_thread_index++;
143  }
144 
145  vm = vlib_mains[thread_index];
146  vm0 = vlib_get_main ();
147 
149 
151 
152  vec_add2 (rt->devices_and_queues, dq, 1);
153  dq->hw_if_index = hw_if_index;
154  dq->dev_instance = hw->dev_instance;
155  dq->queue_id = queue_id;
157  rt->enabled_node_state = VLIB_NODE_STATE_POLLING;
158 
159  vnet_device_queue_update (vnm, rt);
161  vec_validate (hw->rx_mode_by_queue, queue_id);
162  hw->input_node_thread_index_by_queue[queue_id] = thread_index;
164 
166 
168 }
169 
170 int
172  u16 queue_id)
173 {
174  vlib_main_t *vm, *vm0;
175  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
178  uword old_thread_index;
180 
182  return VNET_API_ERROR_INVALID_INTERFACE;
183 
184  if (vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1)
185  return VNET_API_ERROR_INVALID_INTERFACE;
186 
187  old_thread_index = hw->input_node_thread_index_by_queue[queue_id];
188 
189  vm = vlib_mains[old_thread_index];
190 
192 
194  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
195  {
196  mode = dq->mode;
197  goto delete;
198  }
199 
200  return VNET_API_ERROR_INVALID_INTERFACE;
201 
202 delete:
203 
204  vm0 = vlib_get_main ();
207  vnet_device_queue_update (vnm, rt);
210 
211  if (vec_len (rt->devices_and_queues) == 0)
212  vlib_node_set_state (vm, hw->input_node_index, VLIB_NODE_STATE_DISABLED);
213  else if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
214  {
215  /*
216  * if the deleted interface is polling, we may need to set the node state
217  * to interrupt if there is no more polling interface for this device's
218  * corresponding thread. This is because mixed interfaces
219  * (polling and interrupt), assigned to the same thread, set the
220  * thread to polling prior to the deletion.
221  */
223  {
225  return 0;
226  }
227  rt->enabled_node_state = VLIB_NODE_STATE_INTERRUPT;
229  }
230 
231  return 0;
232 }
233 
234 
235 int
237  u16 queue_id, vnet_hw_interface_rx_mode mode)
238 {
239  vlib_main_t *vm;
240  uword thread_index;
242  vlib_node_state_t enabled_node_state;
244  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
246  int is_polling = 0;
247 
249  mode = hw->default_rx_mode;
250 
251  if (hw->input_node_thread_index_by_queue == 0 || hw->rx_mode_by_queue == 0)
252  return VNET_API_ERROR_INVALID_INTERFACE;
253 
254  if (hw->rx_mode_by_queue[queue_id] == mode)
255  return 0;
256 
257  if (mode != VNET_HW_INTERFACE_RX_MODE_POLLING &&
259  return VNET_API_ERROR_UNSUPPORTED;
260 
261  hw->rx_mode_by_queue[queue_id] = mode;
262  thread_index = hw->input_node_thread_index_by_queue[queue_id];
263  vm = vlib_mains[thread_index];
264 
266 
268  {
269  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
270  dq->mode = mode;
272  is_polling = 1;
273  }
274 
275  if (is_polling)
276  enabled_node_state = VLIB_NODE_STATE_POLLING;
277  else
278  enabled_node_state = VLIB_NODE_STATE_INTERRUPT;
279 
280  if (rt->enabled_node_state != enabled_node_state)
281  {
282  rt->enabled_node_state = enabled_node_state;
283  if (vlib_node_get_state (vm, hw->input_node_index) !=
284  VLIB_NODE_STATE_DISABLED)
285  vlib_node_set_state (vm, hw->input_node_index, enabled_node_state);
286  }
287 
288  return 0;
289 }
290 
291 int
293  u16 queue_id, vnet_hw_interface_rx_mode * mode)
294 {
295  vlib_main_t *vm;
296  uword thread_index;
298  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
300 
302  return VNET_API_ERROR_INVALID_INTERFACE;
303 
304  thread_index = hw->input_node_thread_index_by_queue[queue_id];
305  vm = vlib_mains[thread_index];
306 
308 
310  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
311  {
312  *mode = dq->mode;
313  return 0;
314  }
315 
316  return VNET_API_ERROR_INVALID_INTERFACE;
317 }
318 
319 
320 
321 static clib_error_t *
323 {
327  uword *p;
328 
331 
332  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
333  tr = p ? (vlib_thread_registration_t *) p[0] : 0;
334  if (tr && tr->count > 0)
335  {
338  vdm->last_worker_thread_index = tr->first_index + tr->count - 1;
339  }
340  return 0;
341 }
342 
344 
345 /*
346  * fd.io coding-style-patch-verification: ON
347  *
348  * Local Variables:
349  * eval: (c-set-style "gnu")
350  * End:
351  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
static clib_error_t * vnet_device_init(vlib_main_t *vm)
Definition: devices.c:322
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:561
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:447
uword * dq_runtime_index_by_queue
Definition: interface.h:495
vlib_node_state_t
Definition: node.h:208
uword last_worker_thread_index
Definition: devices.h:54
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:186
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:106
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:292
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:109
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:805
#define VNET_DEVICE_INPUT_NEXT_NODES
Definition: devices.h:33
#define VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE
Definition: interface.h:423
vnet_hw_interface_rx_mode mode
Definition: devices.h:63
void vlib_worker_thread_barrier_sync(vlib_main_t *vm)
Definition: threads.c:1166
#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:122
vhost_vring_state_t state
Definition: vhost-user.h:81
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:146
uword * thread_registrations_by_name
Definition: threads.h:261
#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:960
vlib_main_t ** vlib_mains
static uword ethernet_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: node.c:753
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:171
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1198
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:144
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:236
#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:88
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