FD.io VPP  v20.01-48-g3e0dafb74
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
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),
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"),
69  .last_in_arc = "ethernet-input",
71 };
72 
73 VNET_FEATURE_INIT (l2_patch, static) = {
74  .arc_name = "device-input",
75  .node_name = "l2-patch",
76  .runs_before = VNET_FEATURES ("ethernet-input"),
77 };
78 
79 VNET_FEATURE_INIT (worker_handoff, static) = {
80  .arc_name = "device-input",
81  .node_name = "worker-handoff",
82  .runs_before = VNET_FEATURES ("ethernet-input"),
83 };
84 
85 VNET_FEATURE_INIT (span_input, static) = {
86  .arc_name = "device-input",
87  .node_name = "span-input",
88  .runs_before = VNET_FEATURES ("ethernet-input"),
89 };
90 
91 VNET_FEATURE_INIT (p2p_ethernet_node, static) = {
92  .arc_name = "device-input",
93  .node_name = "p2p-ethernet-input",
94  .runs_before = VNET_FEATURES ("ethernet-input"),
95 };
96 
97 VNET_FEATURE_INIT (ethernet_input, static) = {
98  .arc_name = "device-input",
99  .node_name = "ethernet-input",
100  .runs_before = 0, /* not before any other features */
101 };
102 /* *INDENT-ON* */
103 
104 static int
105 vnet_device_queue_sort (void *a1, void *a2)
106 {
107  vnet_device_and_queue_t *dq1 = a1;
108  vnet_device_and_queue_t *dq2 = a2;
109 
110  if (dq1->dev_instance > dq2->dev_instance)
111  return 1;
112  else if (dq1->dev_instance < dq2->dev_instance)
113  return -1;
114  else if (dq1->queue_id > dq2->queue_id)
115  return 1;
116  else if (dq1->queue_id < dq2->queue_id)
117  return -1;
118  else
119  return 0;
120 }
121 
122 static void
124 {
127 
129 
131  {
132  hw = vnet_get_hw_interface (vnm, dq->hw_if_index);
135  }
136 }
137 
138 void
140  u16 queue_id, uword thread_index)
141 {
143  vlib_main_t *vm, *vm0;
146  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
147 
148  ASSERT (hw->input_node_index > 0);
149 
150  if (vdm->first_worker_thread_index == 0)
151  thread_index = 0;
152 
153  if (thread_index != 0 &&
154  (thread_index < vdm->first_worker_thread_index ||
155  thread_index > vdm->last_worker_thread_index))
156  {
157  thread_index = vdm->next_worker_thread_index++;
160  }
161 
162  vm = vlib_mains[thread_index];
163  vm0 = vlib_get_main ();
164 
166 
168 
169  vec_add2 (rt->devices_and_queues, dq, 1);
170  dq->hw_if_index = hw_if_index;
171  dq->dev_instance = hw->dev_instance;
172  dq->queue_id = queue_id;
174  rt->enabled_node_state = VLIB_NODE_STATE_POLLING;
175 
176  vnet_device_queue_update (vnm, rt);
178  vec_validate (hw->rx_mode_by_queue, queue_id);
179  hw->input_node_thread_index_by_queue[queue_id] = thread_index;
181 
183 
185 }
186 
187 int
189  u16 queue_id)
190 {
191  vlib_main_t *vm, *vm0;
192  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
195  uword old_thread_index;
197 
199  return VNET_API_ERROR_INVALID_INTERFACE;
200 
201  if (vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1)
202  return VNET_API_ERROR_INVALID_INTERFACE;
203 
204  old_thread_index = hw->input_node_thread_index_by_queue[queue_id];
205 
206  vm = vlib_mains[old_thread_index];
207 
209 
211  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
212  {
213  mode = dq->mode;
214  goto delete;
215  }
216 
217  return VNET_API_ERROR_INVALID_INTERFACE;
218 
219 delete:
220 
221  vm0 = vlib_get_main ();
224  vnet_device_queue_update (vnm, rt);
227 
228  if (vec_len (rt->devices_and_queues) == 0)
229  vlib_node_set_state (vm, hw->input_node_index, VLIB_NODE_STATE_DISABLED);
230  else if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
231  {
232  /*
233  * if the deleted interface is polling, we may need to set the node state
234  * to interrupt if there is no more polling interface for this device's
235  * corresponding thread. This is because mixed interfaces
236  * (polling and interrupt), assigned to the same thread, set the
237  * thread to polling prior to the deletion.
238  */
240  {
242  return 0;
243  }
244  rt->enabled_node_state = VLIB_NODE_STATE_INTERRUPT;
246  }
247 
248  return 0;
249 }
250 
251 
252 int
255 {
256  vlib_main_t *vm;
257  uword thread_index;
259  vlib_node_state_t enabled_node_state;
261  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
263  int is_polling = 0;
264 
266  mode = hw->default_rx_mode;
267 
268  if (hw->input_node_thread_index_by_queue == 0 || hw->rx_mode_by_queue == 0)
269  return VNET_API_ERROR_INVALID_INTERFACE;
270 
271  if (hw->rx_mode_by_queue[queue_id] == mode)
272  return 0;
273 
274  if (mode != VNET_HW_INTERFACE_RX_MODE_POLLING &&
276  return VNET_API_ERROR_UNSUPPORTED;
277 
278  if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) ||
279  (vec_len (hw->rx_mode_by_queue) < queue_id + 1))
280  return VNET_API_ERROR_INVALID_QUEUE;
281 
282  hw->rx_mode_by_queue[queue_id] = mode;
283  thread_index = hw->input_node_thread_index_by_queue[queue_id];
284  vm = vlib_mains[thread_index];
285 
287 
289  {
290  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
291  dq->mode = mode;
293  is_polling = 1;
294  }
295 
296  if (is_polling)
297  enabled_node_state = VLIB_NODE_STATE_POLLING;
298  else
299  enabled_node_state = VLIB_NODE_STATE_INTERRUPT;
300 
301  if (rt->enabled_node_state != enabled_node_state)
302  {
303  rt->enabled_node_state = enabled_node_state;
304  if (vlib_node_get_state (vm, hw->input_node_index) !=
305  VLIB_NODE_STATE_DISABLED)
306  vlib_node_set_state (vm, hw->input_node_index, enabled_node_state);
307  }
308 
309  return 0;
310 }
311 
312 int
314  u16 queue_id, vnet_hw_interface_rx_mode * mode)
315 {
316  vlib_main_t *vm;
317  uword thread_index;
319  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
321 
323  return VNET_API_ERROR_INVALID_INTERFACE;
324 
325  if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) ||
326  (vec_len (hw->rx_mode_by_queue) < queue_id + 1))
327  return VNET_API_ERROR_INVALID_QUEUE;
328 
329  thread_index = hw->input_node_thread_index_by_queue[queue_id];
330  vm = vlib_mains[thread_index];
331 
333 
335  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
336  {
337  *mode = dq->mode;
338  return 0;
339  }
340 
341  return VNET_API_ERROR_INVALID_INTERFACE;
342 }
343 
344 
345 
346 static clib_error_t *
348 {
352  uword *p;
353 
356 
357  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
358  tr = p ? (vlib_thread_registration_t *) p[0] : 0;
359  if (tr && tr->count > 0)
360  {
363  vdm->last_worker_thread_index = tr->first_index + tr->count - 1;
364  }
365  return 0;
366 }
367 
369 
370 /*
371  * fd.io coding-style-patch-verification: ON
372  *
373  * Local Variables:
374  * eval: (c-set-style "gnu")
375  * End:
376  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:440
static clib_error_t * vnet_device_init(vlib_main_t *vm)
Definition: devices.c:347
vnet_device_and_queue_t * devices_and_queues
Definition: devices.h:69
uword first_worker_thread_index
Definition: devices.h:53
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
u32 * input_node_thread_index_by_queue
Definition: interface.h:588
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:451
uword * dq_runtime_index_by_queue
Definition: interface.h:595
vlib_main_t ** vlib_mains
Definition: buffer.c:332
uword last_worker_thread_index
Definition: devices.h:54
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:204
vlib_node_state_t enabled_node_state
Definition: devices.h:70
vnet_hw_interface_rx_mode
Definition: interface.h:53
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static uword device_input_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: devices.c:25
vnet_hw_interface_flags_t flags
Definition: interface.h:523
unsigned int u32
Definition: types.h:88
vl_api_gre_tunnel_mode_t mode
Definition: gre.api:55
static vlib_node_state_t vlib_node_get_state(vlib_main_t *vm, u32 node_index)
Get node dispatch state.
Definition: node_funcs.h:188
vl_api_fib_path_type_t type
Definition: fib_types.api:123
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
static void vnet_device_queue_update(vnet_main_t *vnm, vnet_device_input_runtime_t *rt)
Definition: devices.c:123
unsigned short u16
Definition: types.h:57
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:313
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:806
#define VNET_DEVICE_INPUT_NEXT_NODES
Definition: devices.h:33
vlib_main_t * vm
Definition: in2out_ed.c:1810
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
vnet_hw_interface_rx_mode mode
Definition: devices.h:63
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1810
#define ASSERT(truth)
void vnet_hw_interface_assign_rx_thread(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id, uword thread_index)
Definition: devices.c:139
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:148
uword * thread_registrations_by_name
Definition: threads.h:294
#define VNET_FEATURES(...)
Definition: feature.h:442
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u8 device_input_feature_arc_index
Feature arc index for device-input.
Definition: feature.h:112
VNET_FEATURE_INIT(l2_patch, static)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:983
VNET_FEATURE_ARC_INIT(device_input, static)
#define hash_get_mem(h, key)
Definition: hash.h:269
int vnet_hw_interface_unassign_rx_thread(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id)
Definition: devices.c:188
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1496
vlib_node_state_t
Definition: node.h:250
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
vl_api_dhcp_client_state_t state
Definition: dhcp.api:201
#define vec_foreach(var, vec)
Vector iterator.
vnet_hw_interface_rx_mode default_rx_mode
Definition: interface.h:592
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1811
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:253
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
vnet_feature_main_t feature_main
Definition: feature.c:19
static int vnet_device_queue_sort(void *a1, void *a2)
Definition: devices.c:105
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