FD.io VPP  v17.04-9-g99c0734
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 void
107  u16 queue_id, uword cpu_index)
108 {
109  vnet_main_t *vnm = vnet_get_main ();
111  vlib_main_t *vm;
114  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
115 
116  ASSERT (hw->input_node_index > 0);
117 
118  if (vdm->first_worker_cpu_index == 0)
119  cpu_index = 0;
120 
121  if (cpu_index != 0 &&
122  (cpu_index < vdm->first_worker_cpu_index ||
123  cpu_index > vdm->last_worker_cpu_index))
124  {
125  cpu_index = vdm->next_worker_cpu_index++;
128  }
129 
130  vm = vlib_mains[cpu_index];
132 
133  vec_add2 (rt->devices_and_queues, dq, 1);
134  dq->hw_if_index = hw_if_index;
135  dq->dev_instance = hw->dev_instance;
136  dq->queue_id = queue_id;
137 
140  hw->input_node_cpu_index_by_queue[queue_id] = cpu_index;
141 }
142 
143 static int
145  uword cpu_index)
146 {
147  vnet_main_t *vnm = vnet_get_main ();
148  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
151  uword old_cpu_index;
152 
153  if (hw->input_node_cpu_index_by_queue == 0)
154  return VNET_API_ERROR_INVALID_INTERFACE;
155 
156  if (vec_len (hw->input_node_cpu_index_by_queue) < queue_id + 1)
157  return VNET_API_ERROR_INVALID_INTERFACE;
158 
159  old_cpu_index = hw->input_node_cpu_index_by_queue[queue_id];
160 
161  if (old_cpu_index == cpu_index)
162  return 0;
163 
164  rt =
165  vlib_node_get_runtime_data (vlib_mains[old_cpu_index],
166  hw->input_node_index);
167 
169  if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id)
170  {
172  goto deleted;
173  }
174 
175  return VNET_API_ERROR_INVALID_INTERFACE;
176 
177 deleted:
179 
180  return 0;
181 }
182 
183 static clib_error_t *
185  vlib_cli_command_t * cmd)
186 {
187  u8 *s = 0;
188  vnet_main_t *vnm = vnet_get_main ();
191  vlib_node_t *pn = vlib_get_node_by_name (vm, (u8 *) "device-input");
192  uword si;
193  int index = 0;
194 
195  /* *INDENT-OFF* */
198  ({
199  rt = vlib_node_get_runtime_data (this_vlib_main, si);
200 
201  if (vec_len (rt->devices_and_queues))
202  s = format (s, " node %U:\n", format_vlib_node_name, vm, si);
203 
204  vec_foreach (dq, rt->devices_and_queues)
205  {
206  s = format (s, " %U queue %u\n",
207  format_vnet_sw_if_index_name, vnm, dq->hw_if_index,
208  dq->queue_id);
209  }
210  }));
211  if (vec_len (s) > 0)
212  {
213  vlib_cli_output(vm, "Thread %u (%v):\n%v", index,
214  vlib_worker_threads[index].name, s);
215  vec_reset_length (s);
216  }
217  index++;
218  }));
219  /* *INDENT-ON* */
220 
221  vec_free (s);
222  return 0;
223 }
224 
225 /* *INDENT-OFF* */
226 VLIB_CLI_COMMAND (memif_delete_command, static) = {
227  .path = "show interface placement",
228  .short_help = "show interface placement",
229  .function = show_device_placement_fn,
230 };
231 /* *INDENT-ON* */
232 
233 static clib_error_t *
235  vlib_cli_command_t * cmd)
236 {
237  clib_error_t *error = 0;
238  unformat_input_t _line_input, *line_input = &_line_input;
239  vnet_main_t *vnm = vnet_get_main ();
241  u32 hw_if_index = (u32) ~ 0;
242  u32 queue_id = (u32) 0;
243  u32 cpu_index = (u32) ~ 0;
244  int rv;
245 
246  if (!unformat_user (input, unformat_line_input, line_input))
247  return 0;
248 
249  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
250  {
251  if (unformat
252  (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
253  ;
254  else if (unformat (line_input, "queue %d", &queue_id))
255  ;
256  else if (unformat (line_input, "main", &cpu_index))
257  cpu_index = 0;
258  else if (unformat (line_input, "worker %d", &cpu_index))
259  cpu_index += vdm->first_worker_cpu_index;
260  else
261  {
262  error = clib_error_return (0, "parse error: '%U'",
263  format_unformat_error, line_input);
264  unformat_free (line_input);
265  return error;
266  }
267  }
268 
269  unformat_free (line_input);
270 
271  if (hw_if_index == (u32) ~ 0)
272  return clib_error_return (0, "please specify valid interface name");
273 
274  if (cpu_index > vdm->last_worker_cpu_index)
275  return clib_error_return (0,
276  "please specify valid worker thread or main");
277 
278  rv = vnet_device_input_unassign_thread (hw_if_index, queue_id, cpu_index);
279 
280  if (rv)
281  return clib_error_return (0, "not found");
282 
283  vnet_device_input_assign_thread (hw_if_index, queue_id, cpu_index);
284 
285  return 0;
286 }
287 
288 /*?
289  * This command is used to assign a given interface, and optionally a
290  * given queue, to a different thread. If the '<em>queue</em>' is not provided,
291  * it defaults to 0.
292  *
293  * @cliexpar
294  * Example of how to display the interface placement:
295  * @cliexstart{show interface placement}
296  * Thread 1 (vpp_wk_0):
297  * GigabitEthernet0/8/0 queue 0
298  * GigabitEthernet0/9/0 queue 0
299  * Thread 2 (vpp_wk_1):
300  * GigabitEthernet0/8/0 queue 1
301  * GigabitEthernet0/9/0 queue 1
302  * @cliexend
303  * Example of how to assign a interface and queue to a thread:
304  * @cliexcmd{set interface placement GigabitEthernet0/8/0 queue 1 thread 1}
305 ?*/
306 /* *INDENT-OFF* */
307 VLIB_CLI_COMMAND (cmd_set_dpdk_if_placement,static) = {
308  .path = "set interface placement",
309  .short_help = "set interface placement <interface> [queue <n>] [thread <n> | main]",
310  .function = set_device_placement,
311 };
312 /* *INDENT-ON* */
313 
314 static clib_error_t *
316 {
320  uword *p;
321 
324 
325  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
326  tr = p ? (vlib_thread_registration_t *) p[0] : 0;
327  if (tr && tr->count > 0)
328  {
331  vdm->last_worker_cpu_index = tr->first_index + tr->count - 1;
332  }
333  return 0;
334 }
335 
337 
338 /*
339  * fd.io coding-style-patch-verification: ON
340  *
341  * Local Variables:
342  * eval: (c-set-style "gnu")
343  * End:
344  */
uword * sibling_bitmap
Definition: node.h:294
unformat_function_t unformat_vnet_hw_interface
#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:315
vnet_device_and_queue_t * devices_and_queues
Definition: devices.h:67
uword first_worker_cpu_index
Definition: devices.h:53
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
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
static clib_error_t * show_device_placement_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: devices.c:184
#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 unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:982
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:447
vlib_main_t ** vlib_mains
Definition: buffer.c:285
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
#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
#define clib_error_return(e, args...)
Definition: error.h:111
unformat_function_t unformat_line_input
Definition: format.h:281
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
vlib_worker_thread_t * vlib_worker_threads
Definition: threads.c:35
#define clib_bitmap_foreach(i, ai, body)
Macro to iterate across set bits in a bitmap.
Definition: bitmap.h:361
uword last_worker_cpu_index
Definition: devices.h:54
struct _unformat_input_t unformat_input_t
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
static int vnet_device_input_unassign_thread(u32 hw_if_index, u16 queue_id, uword cpu_index)
Definition: devices.c:144
#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 foreach_vlib_main(body)
Definition: threads.h:225
static clib_error_t * set_device_placement(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: devices.c:234
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
vlib_main_t * vm
Definition: buffer.c:276
u32 * input_node_cpu_index_by_queue
Definition: interface.h:471
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
vhost_vring_state_t state
Definition: vhost-user.h:83
uword * thread_registrations_by_name
Definition: threads.h:276
#define VNET_FEATURES(...)
Definition: feature.h:368
uword next_worker_cpu_index
Definition: devices.h:55
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)
unsigned char u8
Definition: types.h:56
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:960
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
static uword ethernet_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: node.c:748
VNET_FEATURE_ARC_INIT(device_input, static)
#define hash_get_mem(h, key)
Definition: hash.h:268
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#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.
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
void vnet_device_input_assign_thread(u32 hw_if_index, u16 queue_id, uword cpu_index)
Definition: devices.c:106
vnet_feature_main_t feature_main
Definition: feature.c:19
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:577
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
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:971
vlib_node_registration_t device_input_node
(constructor) VLIB_REGISTER_NODE (device_input_node)
Definition: devices.c:32
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169