blob: fccedebdcf40d59a97e2967041cdf358bc8fa1c0 [file] [log] [blame]
Damjan Marion38c61912023-10-17 16:06:26 +00001/* SPDX-License-Identifier: Apache-2.0
2 * Copyright (c) 2023 Cisco Systems, Inc.
3 */
4
5#include <vnet/vnet.h>
6#include <vnet/ethernet/ethernet.h>
7#include <vnet/dev/dev.h>
8#include <vnet/dev/counters.h>
9#include <vnet/dev/log.h>
10
11VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
12 .class_name = "dev",
13 .subclass_name = "port",
14};
15
16static uword
17dummy_input_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
18 vlib_frame_t *frame)
19{
20 ASSERT (0);
21 return 0;
22}
23
24VLIB_REGISTER_NODE (port_rx_eth_node) = {
25 .function = dummy_input_fn,
26 .name = "port-rx-eth",
27 .runtime_data_bytes = sizeof (vnet_dev_rx_node_runtime_t),
28 .type = VLIB_NODE_TYPE_INPUT,
29 .state = VLIB_NODE_STATE_DISABLED,
30 .n_next_nodes = VNET_DEV_ETH_RX_PORT_N_NEXTS,
31 .next_nodes = {
32#define _(n, s) [VNET_DEV_ETH_RX_PORT_NEXT_##n] = s,
33 foreach_vnet_dev_port_rx_next
34#undef _
35 },
36};
37
38u16 vnet_dev_default_next_index_by_port_type[] = {
39 [VNET_DEV_PORT_TYPE_ETHERNET] = VNET_DEV_ETH_RX_PORT_NEXT_ETH_INPUT,
40};
41
42VNET_FEATURE_ARC_INIT (eth_port_rx, static) = {
43 .arc_name = "port-rx-eth",
44 .start_nodes = VNET_FEATURES ("port-rx-eth"),
45 .last_in_arc = "ethernet-input",
46 .arc_index_ptr = &vnet_dev_main.eth_port_rx_feature_arc_index,
47};
48
49VNET_FEATURE_INIT (l2_patch, static) = {
50 .arc_name = "port-rx-eth",
51 .node_name = "l2-patch",
52 .runs_before = VNET_FEATURES ("ethernet-input"),
53};
54
55VNET_FEATURE_INIT (worker_handoff, static) = {
56 .arc_name = "port-rx-eth",
57 .node_name = "worker-handoff",
58 .runs_before = VNET_FEATURES ("ethernet-input"),
59};
60
61VNET_FEATURE_INIT (span_input, static) = {
62 .arc_name = "port-rx-eth",
63 .node_name = "span-input",
64 .runs_before = VNET_FEATURES ("ethernet-input"),
65};
66
67VNET_FEATURE_INIT (p2p_ethernet_node, static) = {
68 .arc_name = "port-rx-eth",
69 .node_name = "p2p-ethernet-input",
70 .runs_before = VNET_FEATURES ("ethernet-input"),
71};
72
73VNET_FEATURE_INIT (ethernet_input, static) = {
74 .arc_name = "port-rx-eth",
75 .node_name = "ethernet-input",
76 .runs_before = 0, /* not before any other features */
77};
78
79void
80vnet_dev_port_free (vlib_main_t *vm, vnet_dev_port_t *port)
81{
82 vnet_dev_t *dev = port->dev;
83
84 vnet_dev_port_validate (vm, port);
85
86 ASSERT (port->started == 0);
87
88 log_debug (dev, "port %u", port->port_id);
89
90 if (port->port_ops.free)
91 port->port_ops.free (vm, port);
92
93 pool_free (port->secondary_hw_addr);
94 pool_free (port->rx_queues);
95 pool_free (port->tx_queues);
Damjan Marion69768d92023-11-13 17:33:32 +000096 vnet_dev_arg_free (&port->args);
Damjan Marion61e287b2024-10-08 20:50:56 +020097 vnet_dev_arg_free (&port->sec_if_args);
Damjan Marion38c61912023-10-17 16:06:26 +000098 pool_put_index (dev->ports, port->index);
99 clib_mem_free (port);
100}
101
102void
103vnet_dev_port_update_tx_node_runtime (vlib_main_t *vm, vnet_dev_port_t *port)
104{
105 vnet_dev_port_validate (vm, port);
106
107 foreach_vnet_dev_port_tx_queue (q, port)
108 {
109 u32 ti;
110 clib_bitmap_foreach (ti, q->assigned_threads)
111 {
112 vlib_main_t *tvm = vlib_get_main_by_index (ti);
Damjan Marion61e287b2024-10-08 20:50:56 +0200113 vlib_node_runtime_t *nr;
114 vnet_dev_tx_node_runtime_t *tnr;
115 vnet_dev_port_interfaces_t *ifs = port->interfaces;
116
117 nr =
118 vlib_node_get_runtime (tvm, ifs->primary_interface.tx_node_index);
119 tnr = vnet_dev_get_tx_node_runtime (nr);
120 tnr->hw_if_index = ifs->primary_interface.hw_if_index;
Damjan Marion38c61912023-10-17 16:06:26 +0000121 tnr->tx_queue = q;
Damjan Marion61e287b2024-10-08 20:50:56 +0200122
123 pool_foreach_pointer (sif, port->interfaces->secondary_interfaces)
124 {
125 nr = vlib_node_get_runtime (tvm, sif->tx_node_index);
126 tnr = vnet_dev_get_tx_node_runtime (nr);
127 tnr->hw_if_index = sif->hw_if_index;
128 tnr->tx_queue = q;
129 }
Damjan Marion38c61912023-10-17 16:06:26 +0000130 }
131 }
132}
133
134void
135vnet_dev_port_stop (vlib_main_t *vm, vnet_dev_port_t *port)
136{
137 vnet_dev_t *dev = port->dev;
138 vnet_dev_rt_op_t *ops = 0;
Damjan Marionb8dd9812023-11-03 13:47:05 +0000139 u16 n_threads = vlib_get_n_threads ();
Damjan Marion38c61912023-10-17 16:06:26 +0000140
141 log_debug (dev, "stopping port %u", port->port_id);
142
Damjan Marionb8dd9812023-11-03 13:47:05 +0000143 for (u16 i = 0; i < n_threads; i++)
144 {
145 vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
146 vec_add1 (ops, op);
147 }
Damjan Marion38c61912023-10-17 16:06:26 +0000148
149 vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
150 vec_free (ops);
151
152 port->port_ops.stop (vm, port);
153
154 foreach_vnet_dev_port_rx_queue (q, port)
155 {
156 q->started = 0;
157 log_debug (dev, "port %u rx queue %u stopped", port->port_id,
158 q->queue_id);
159 }
160
161 foreach_vnet_dev_port_tx_queue (q, port)
162 {
163 q->started = 0;
164 log_debug (dev, "port %u tx queue %u stopped", port->port_id,
165 q->queue_id);
166 }
167
168 log_debug (dev, "port %u stopped", port->port_id);
169 port->started = 0;
170}
171
172vnet_dev_rv_t
173vnet_dev_port_start_all_rx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
174{
175 vnet_dev_rv_t rv = VNET_DEV_OK;
176
177 vnet_dev_port_validate (vm, port);
178
179 foreach_vnet_dev_port_rx_queue (q, port)
180 {
181 rv = vnet_dev_rx_queue_start (vm, q);
182 if (rv != VNET_DEV_OK)
183 return rv;
184 }
185 return rv;
186}
187
188vnet_dev_rv_t
189vnet_dev_port_start_all_tx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
190{
191 vnet_dev_rv_t rv = VNET_DEV_OK;
192
193 vnet_dev_port_validate (vm, port);
194
195 foreach_vnet_dev_port_tx_queue (q, port)
196 {
197 rv = vnet_dev_tx_queue_start (vm, q);
198 if (rv != VNET_DEV_OK)
199 return rv;
200 }
201 return rv;
202}
203
204vnet_dev_rv_t
205vnet_dev_port_start (vlib_main_t *vm, vnet_dev_port_t *port)
206{
Damjan Marionb8dd9812023-11-03 13:47:05 +0000207 u16 n_threads = vlib_get_n_threads ();
Damjan Marion38c61912023-10-17 16:06:26 +0000208 vnet_dev_t *dev = port->dev;
209 vnet_dev_rt_op_t *ops = 0;
210 vnet_dev_rv_t rv;
211
212 vnet_dev_port_validate (vm, port);
213
214 log_debug (dev, "starting port %u", port->port_id);
215
216 vnet_dev_port_update_tx_node_runtime (vm, port);
217
218 if ((rv = port->port_ops.start (vm, port)) != VNET_DEV_OK)
219 {
220 vnet_dev_port_stop (vm, port);
221 return rv;
222 }
223
Damjan Marionb8dd9812023-11-03 13:47:05 +0000224 for (u16 i = 0; i < n_threads; i++)
225 {
226 vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
227 vec_add1 (ops, op);
228 }
Damjan Marion38c61912023-10-17 16:06:26 +0000229
230 vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
231 vec_free (ops);
232
233 foreach_vnet_dev_port_rx_queue (q, port)
234 if (q->enabled)
235 {
236 log_debug (dev, "port %u rx queue %u started", port->port_id,
237 q->queue_id);
238 q->started = 1;
239 }
240
241 foreach_vnet_dev_port_tx_queue (q, port)
242 if (q->enabled)
243 {
244 log_debug (dev, "port %u tx queue %u started", port->port_id,
245 q->queue_id);
246 q->started = 1;
247 }
248
249 port->started = 1;
250 log_debug (dev, "port %u started", port->port_id);
251
252 return VNET_DEV_OK;
253}
254
255vnet_dev_rv_t
256vnet_dev_port_add (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_port_id_t id,
257 vnet_dev_port_add_args_t *args)
258{
259 vnet_dev_port_t **pp, *port;
260 vnet_dev_rv_t rv = VNET_DEV_OK;
261
262 ASSERT (args->port.attr.type != VNET_DEV_PORT_TYPE_UNKNOWN);
Damjan Marione596ca12023-11-08 19:12:27 +0000263 ASSERT (args->port.attr.max_supported_rx_frame_size);
Damjan Marion38c61912023-10-17 16:06:26 +0000264
265 port =
266 vnet_dev_alloc_with_data (sizeof (vnet_dev_port_t), args->port.data_size);
267 pool_get (dev->ports, pp);
268 pp[0] = port;
269 clib_memcpy (vnet_dev_get_port_data (port), args->port.initial_data,
270 args->port.data_size);
271 port->port_id = id;
272 port->index = pp - dev->ports;
273 port->dev = dev;
274 port->attr = args->port.attr;
275 port->rx_queue_config = args->rx_queue.config;
276 port->tx_queue_config = args->tx_queue.config;
277 port->rx_queue_ops = args->rx_queue.ops;
278 port->tx_queue_ops = args->tx_queue.ops;
279 port->port_ops = args->port.ops;
280 port->rx_node = *args->rx_node;
281 port->tx_node = *args->tx_node;
282
Damjan Marion07a62cc2023-11-16 19:14:12 +0000283 if (args->port.args)
284 for (vnet_dev_arg_t *a = args->port.args; a->type != VNET_DEV_ARG_END; a++)
285 vec_add1 (port->args, *a);
Damjan Marion69768d92023-11-13 17:33:32 +0000286
Damjan Marion61e287b2024-10-08 20:50:56 +0200287 if (args->port.sec_if_args)
288 for (vnet_dev_arg_t *a = args->port.sec_if_args;
289 a->type != VNET_DEV_ARG_END; a++)
290 vec_add1 (port->sec_if_args, *a);
291
Damjan Marion38c61912023-10-17 16:06:26 +0000292 /* defaults out of port attributes */
Damjan Marione596ca12023-11-08 19:12:27 +0000293 port->max_rx_frame_size = args->port.attr.max_supported_rx_frame_size;
Damjan Marion38c61912023-10-17 16:06:26 +0000294 port->primary_hw_addr = args->port.attr.hw_addr;
295
Damjan Marione596ca12023-11-08 19:12:27 +0000296 if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
297 {
298 if (port->max_rx_frame_size > 1514 &&
299 port->attr.caps.change_max_rx_frame_size)
300 port->max_rx_frame_size = 1514;
301 }
302
Damjan Marion38c61912023-10-17 16:06:26 +0000303 if (port->port_ops.alloc)
304 rv = port->port_ops.alloc (vm, port);
305
306 if (rv == VNET_DEV_OK)
307 port->initialized = 1;
308
309 return rv;
310}
311
312vnet_dev_rv_t
313vnet_dev_port_cfg_change_req_validate (vlib_main_t *vm, vnet_dev_port_t *port,
314 vnet_dev_port_cfg_change_req_t *req)
315{
316 vnet_dev_rv_t rv;
317 vnet_dev_hw_addr_t *addr;
318 int found;
319
320 if (req->validated)
321 return VNET_DEV_OK;
322
323 switch (req->type)
324 {
Damjan Marione596ca12023-11-08 19:12:27 +0000325 case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
Alok Mishraf7f26e52024-04-26 15:45:49 +0530326 if ((req->max_rx_frame_size > port->attr.max_supported_rx_frame_size) ||
327 (req->max_rx_frame_size < ETHERNET_MIN_PACKET_BYTES))
Damjan Marion38c61912023-10-17 16:06:26 +0000328 return VNET_DEV_ERR_INVALID_VALUE;
Damjan Marione596ca12023-11-08 19:12:27 +0000329 if (req->max_rx_frame_size == port->max_rx_frame_size)
Damjan Marion38c61912023-10-17 16:06:26 +0000330 return VNET_DEV_ERR_NO_CHANGE;
331 break;
332
333 case VNET_DEV_PORT_CFG_PROMISC_MODE:
334 if (req->promisc == port->promisc)
335 return VNET_DEV_ERR_NO_CHANGE;
336 break;
337
338 case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
339 if (clib_memcmp (&req->addr, &port->primary_hw_addr,
340 sizeof (vnet_dev_hw_addr_t)) == 0)
341 return VNET_DEV_ERR_NO_CHANGE;
342 break;
343
344 case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
345 pool_foreach (addr, port->secondary_hw_addr)
346 if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
347 return VNET_DEV_ERR_ALREADY_EXISTS;
348 break;
349
350 case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
351 found = 0;
352 pool_foreach (addr, port->secondary_hw_addr)
353 if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
354 found = 1;
355 if (!found)
356 return VNET_DEV_ERR_NO_SUCH_ENTRY;
357 break;
358
359 default:
360 break;
361 }
362
363 if (port->port_ops.config_change_validate)
364 {
365 rv = port->port_ops.config_change_validate (vm, port, req);
366 if (rv != VNET_DEV_OK)
367 return rv;
368 }
Damjan Marione596ca12023-11-08 19:12:27 +0000369 else
370 return VNET_DEV_ERR_NOT_SUPPORTED;
Damjan Marion38c61912023-10-17 16:06:26 +0000371
372 req->validated = 1;
373 return VNET_DEV_OK;
374}
375
376vnet_dev_rv_t
377vnet_dev_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
378 vnet_dev_port_cfg_change_req_t *req)
379{
380 vnet_dev_rv_t rv = VNET_DEV_OK;
381 vnet_dev_hw_addr_t *a;
Damjan Marionb8dd9812023-11-03 13:47:05 +0000382 vnet_dev_rx_queue_t *rxq = 0;
383 u8 enable = 0;
Damjan Marion38c61912023-10-17 16:06:26 +0000384
385 vnet_dev_port_validate (vm, port);
386
Damjan Marionb8dd9812023-11-03 13:47:05 +0000387 if (req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE ||
388 req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE)
389 {
390 if (req->all_queues == 0)
391 {
Damjan Marioncda500b2024-10-08 23:14:49 +0200392 rxq = vnet_dev_get_port_rx_queue_by_id (port, req->queue_id);
Damjan Marionb8dd9812023-11-03 13:47:05 +0000393 if (rxq == 0)
394 return VNET_DEV_ERR_BUG;
395 }
396 }
397
398 if ((rv = vnet_dev_port_cfg_change_req_validate (vm, port, req)))
399 return rv;
Damjan Marion38c61912023-10-17 16:06:26 +0000400
401 if (port->port_ops.config_change)
402 rv = port->port_ops.config_change (vm, port, req);
Damjan Marione596ca12023-11-08 19:12:27 +0000403 else
404 return VNET_DEV_ERR_NOT_SUPPORTED;
Damjan Marion38c61912023-10-17 16:06:26 +0000405
406 if (rv != VNET_DEV_OK)
407 return rv;
408
409 switch (req->type)
410 {
Damjan Marione596ca12023-11-08 19:12:27 +0000411 case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
412 port->max_rx_frame_size = req->max_rx_frame_size;
Damjan Marion38c61912023-10-17 16:06:26 +0000413 break;
414
415 case VNET_DEV_PORT_CFG_PROMISC_MODE:
416 port->promisc = req->promisc;
417 break;
418
Damjan Marionb8dd9812023-11-03 13:47:05 +0000419 case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE:
420 enable = 1;
421 case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE:
422 if (req->all_queues)
423 {
424 clib_bitmap_t *bmp = 0;
425 vnet_dev_rt_op_t *ops = 0;
426 u32 i;
427
428 foreach_vnet_dev_port_rx_queue (q, port)
429 {
430 q->interrupt_mode = enable;
431 bmp = clib_bitmap_set (bmp, q->rx_thread_index, 1);
432 }
433
434 clib_bitmap_foreach (i, bmp)
435 {
436 vnet_dev_rt_op_t op = { .port = port, .thread_index = i };
437 vec_add1 (ops, op);
438 }
439
440 vnet_dev_rt_exec_ops (vm, port->dev, ops, vec_len (ops));
441 clib_bitmap_free (bmp);
442 vec_free (ops);
443 }
444 else
445 {
446 rxq->interrupt_mode = enable;
447 vnet_dev_rt_exec_ops (vm, port->dev,
448 &(vnet_dev_rt_op_t){
449 .port = port,
450 .thread_index = rxq->rx_thread_index,
451 },
452 1);
453 }
454 break;
455
Damjan Marion38c61912023-10-17 16:06:26 +0000456 case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
457 clib_memcpy (&port->primary_hw_addr, &req->addr,
458 sizeof (vnet_dev_hw_addr_t));
459 break;
460
461 case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
462 pool_get (port->secondary_hw_addr, a);
463 clib_memcpy (a, &req->addr, sizeof (vnet_dev_hw_addr_t));
464 break;
465
466 case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
467 pool_foreach (a, port->secondary_hw_addr)
468 if (clib_memcmp (a, &req->addr, sizeof (vnet_dev_hw_addr_t)) == 0)
469 {
470 pool_put (port->secondary_hw_addr, a);
471 break;
472 }
473 break;
474
475 default:
476 break;
477 }
478
479 return VNET_DEV_OK;
480}
481
482void
483vnet_dev_port_state_change (vlib_main_t *vm, vnet_dev_port_t *port,
484 vnet_dev_port_state_changes_t changes)
485{
486 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion61e287b2024-10-08 20:50:56 +0200487 vnet_dev_port_interfaces_t *ifs = port->interfaces;
Damjan Marion38c61912023-10-17 16:06:26 +0000488
489 vnet_dev_port_validate (vm, port);
490
491 if (changes.change.link_speed)
492 {
493 port->speed = changes.link_speed;
Damjan Marion61e287b2024-10-08 20:50:56 +0200494 if (port->interfaces)
495 vnet_hw_interface_set_link_speed (
496 vnm, ifs->primary_interface.hw_if_index, changes.link_speed);
Damjan Marion38c61912023-10-17 16:06:26 +0000497 log_debug (port->dev, "port speed changed to %u", changes.link_speed);
498 }
499
500 if (changes.change.link_state)
501 {
502 port->link_up = changes.link_state;
Damjan Marion61e287b2024-10-08 20:50:56 +0200503 if (ifs)
504 {
505 vnet_hw_interface_set_flags (
506 vnm, ifs->primary_interface.hw_if_index,
507 changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
508 pool_foreach_pointer (sif, ifs->secondary_interfaces)
509 {
510 vnet_hw_interface_set_flags (
511 vnm, sif->hw_if_index,
512 changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
513 }
514 }
Damjan Marion38c61912023-10-17 16:06:26 +0000515 log_debug (port->dev, "port link state changed to %s",
516 changes.link_state ? "up" : "down");
517 }
518}
519
520void
521vnet_dev_port_add_counters (vlib_main_t *vm, vnet_dev_port_t *port,
522 vnet_dev_counter_t *counters, u16 n_counters)
523{
524 vnet_dev_port_validate (vm, port);
525
526 port->counter_main =
527 vnet_dev_counters_alloc (vm, counters, n_counters, "%s port %u counters",
528 port->dev->device_id, port->port_id);
529}
530
531void
532vnet_dev_port_free_counters (vlib_main_t *vm, vnet_dev_port_t *port)
533{
534 vnet_dev_port_validate (vm, port);
535
536 if (port->counter_main)
537 vnet_dev_counters_free (vm, port->counter_main);
538}
539
Damjan Marion61e287b2024-10-08 20:50:56 +0200540static void
541vnet_dev_port_init_if_rt_data (vlib_main_t *vm, vnet_dev_port_t *port,
542 vnet_dev_rx_queue_if_rt_data_t *rtd,
543 u32 sw_if_index)
544{
545 vnet_dev_t *dev = port->dev;
546 u8 buffer_pool_index =
547 vlib_buffer_pool_get_default_for_numa (vm, dev->numa_node);
548 vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
549
550 rtd->buffer_template = bp->buffer_template;
551 vnet_buffer (&rtd->buffer_template)->sw_if_index[VLIB_RX] = sw_if_index;
552 vnet_buffer (&rtd->buffer_template)->sw_if_index[VLIB_TX] = ~0;
553 rtd->next_index = ~0;
554 rtd->sw_if_index = sw_if_index;
555}
556
Damjan Marion38c61912023-10-17 16:06:26 +0000557vnet_dev_rv_t
Damjan Marion61e287b2024-10-08 20:50:56 +0200558vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr)
Damjan Marion38c61912023-10-17 16:06:26 +0000559{
560 vnet_main_t *vnm = vnet_get_main ();
561 u16 n_threads = vlib_get_n_threads ();
562 vnet_dev_main_t *dm = &vnet_dev_main;
563 vnet_dev_t *dev = port->dev;
Damjan Marion61e287b2024-10-08 20:50:56 +0200564 vnet_dev_port_if_create_args_t *a = ptr;
565 vnet_dev_port_interfaces_t *ifs = port->interfaces;
Damjan Marion8cbf5652024-10-23 20:56:27 +0200566 vnet_dev_instance_t *di;
Damjan Marion38c61912023-10-17 16:06:26 +0000567 vnet_dev_rv_t rv;
568 u16 ti = 0;
569
Damjan Marion61e287b2024-10-08 20:50:56 +0200570 if (ifs)
571 return VNET_DEV_ERR_ALREADY_EXISTS;
572
573 port->interfaces = ifs =
574 clib_mem_alloc (sizeof (vnet_dev_port_interfaces_t));
575
576 *(ifs) = (vnet_dev_port_interfaces_t){
577 .num_rx_queues = a->num_rx_queues,
578 .num_tx_queues = a->num_tx_queues,
579 .rxq_sz = a->rxq_sz,
580 .txq_sz = a->txq_sz,
581 .default_is_intr_mode = a->default_is_intr_mode,
582 };
583
584 if (a->name[0] == 0)
Damjan Marion38c61912023-10-17 16:06:26 +0000585 {
586 u8 *s;
587 s = format (0, "%s%u/%u",
588 dm->drivers[port->dev->driver_index].registration->name,
589 port->dev->index, port->index);
590 u32 n = vec_len (s);
591
Damjan Marion61e287b2024-10-08 20:50:56 +0200592 if (n >= sizeof (a->name))
Damjan Marion38c61912023-10-17 16:06:26 +0000593 {
594 vec_free (s);
595 return VNET_DEV_ERR_BUG;
596 }
Damjan Marion61e287b2024-10-08 20:50:56 +0200597 clib_memcpy (ifs->primary_interface.name, s, n);
598 ifs->primary_interface.name[n] = 0;
Damjan Marion38c61912023-10-17 16:06:26 +0000599 vec_free (s);
600 }
Damjan Marion61e287b2024-10-08 20:50:56 +0200601 else
602 clib_memcpy (ifs->primary_interface.name, a->name,
603 sizeof (ifs->primary_interface.name));
Damjan Marion38c61912023-10-17 16:06:26 +0000604
605 log_debug (
606 dev, "allocating %u rx queues with size %u and %u tx queues with size %u",
Damjan Marion61e287b2024-10-08 20:50:56 +0200607 a->num_rx_queues, a->rxq_sz, a->num_tx_queues, a->txq_sz);
Damjan Marion38c61912023-10-17 16:06:26 +0000608
Damjan Marion61e287b2024-10-08 20:50:56 +0200609 for (int i = 0; i < ifs->num_rx_queues; i++)
610 if ((rv = vnet_dev_rx_queue_alloc (vm, port, ifs->rxq_sz)) != VNET_DEV_OK)
Damjan Marion38c61912023-10-17 16:06:26 +0000611 goto error;
612
Damjan Marion61e287b2024-10-08 20:50:56 +0200613 for (u32 i = 0; i < ifs->num_tx_queues; i++)
614 if ((rv = vnet_dev_tx_queue_alloc (vm, port, ifs->txq_sz)) != VNET_DEV_OK)
Damjan Marion38c61912023-10-17 16:06:26 +0000615 goto error;
616
617 foreach_vnet_dev_port_tx_queue (q, port)
618 {
Mohammed Hawari82569142024-11-06 17:13:02 +0100619 /* if consistent_qp is enabled, we start by assigning queues to workers
620 * and we end with main */
Damjan Marion61e287b2024-10-08 20:50:56 +0200621 u16 real_ti = (ti + a->consistent_qp) % n_threads;
Mohammed Hawari82569142024-11-06 17:13:02 +0100622 q->assigned_threads = clib_bitmap_set (q->assigned_threads, real_ti, 1);
Damjan Marion38c61912023-10-17 16:06:26 +0000623 log_debug (dev, "port %u tx queue %u assigned to thread %u",
Mohammed Hawari82569142024-11-06 17:13:02 +0100624 port->port_id, q->queue_id, real_ti);
Damjan Marion38c61912023-10-17 16:06:26 +0000625 if (++ti >= n_threads)
626 break;
627 }
628
Damjan Marion8cbf5652024-10-23 20:56:27 +0200629 pool_get (dm->dev_instances, di);
Damjan Marion61e287b2024-10-08 20:50:56 +0200630 ifs->primary_interface.dev_instance = di - dm->dev_instances;
Damjan Marion8cbf5652024-10-23 20:56:27 +0200631 di->port = port;
Damjan Marion61e287b2024-10-08 20:50:56 +0200632 di->is_primary_if = 1;
Damjan Marion38c61912023-10-17 16:06:26 +0000633
634 if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
635 {
636 vnet_device_class_t *dev_class;
637 vnet_dev_driver_t *driver;
638 vnet_sw_interface_t *sw;
639 vnet_hw_interface_t *hw;
Damjan Mariond1eb1b72023-12-07 16:40:02 +0100640 vnet_hw_if_caps_t caps = 0;
Damjan Marion61e287b2024-10-08 20:50:56 +0200641 u32 rx_node_index, hw_if_index, sw_if_index;
Damjan Marion38c61912023-10-17 16:06:26 +0000642
643 driver = pool_elt_at_index (dm->drivers, dev->driver_index);
644
645 /* hack to provide per-port tx node function */
646 dev_class = vnet_get_device_class (vnm, driver->dev_class_index);
647 dev_class->tx_fn_registrations = port->tx_node.registrations;
648 dev_class->format_tx_trace = port->tx_node.format_trace;
649 dev_class->tx_function_error_counters = port->tx_node.error_counters;
650 dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
651
652 /* create new interface including tx and output nodes */
Damjan Marion61e287b2024-10-08 20:50:56 +0200653 hw_if_index = vnet_eth_register_interface (
Damjan Marion38c61912023-10-17 16:06:26 +0000654 vnm, &(vnet_eth_interface_registration_t){
655 .address = port->primary_hw_addr.eth_mac,
Damjan Marione596ca12023-11-08 19:12:27 +0000656 .max_frame_size = port->max_rx_frame_size,
Damjan Marion38c61912023-10-17 16:06:26 +0000657 .dev_class_index = driver->dev_class_index,
Damjan Marion61e287b2024-10-08 20:50:56 +0200658 .dev_instance = ifs->primary_interface.dev_instance,
Damjan Marion38c61912023-10-17 16:06:26 +0000659 .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size,
660 .cb.flag_change = vnet_dev_port_eth_flag_change,
661 });
Damjan Marion61e287b2024-10-08 20:50:56 +0200662 ifs->primary_interface.hw_if_index = hw_if_index;
Damjan Marion38c61912023-10-17 16:06:26 +0000663
Damjan Marion61e287b2024-10-08 20:50:56 +0200664 sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
665 hw = vnet_get_hw_interface (vnm, hw_if_index);
666 sw_if_index = ifs->primary_interface.sw_if_index = sw->sw_if_index;
Damjan Marion38c61912023-10-17 16:06:26 +0000667 vnet_hw_interface_set_flags (
Damjan Marion61e287b2024-10-08 20:50:56 +0200668 vnm, ifs->primary_interface.hw_if_index,
Damjan Marion38c61912023-10-17 16:06:26 +0000669 port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
670 if (port->speed)
Damjan Marion61e287b2024-10-08 20:50:56 +0200671 vnet_hw_interface_set_link_speed (
672 vnm, ifs->primary_interface.hw_if_index, port->speed);
Damjan Marion38c61912023-10-17 16:06:26 +0000673
Damjan Marion61e287b2024-10-08 20:50:56 +0200674 ifs->primary_interface.tx_node_index = hw->tx_node_index;
Damjan Marion38c61912023-10-17 16:06:26 +0000675
Damjan Mariond1eb1b72023-12-07 16:40:02 +0100676 caps |= port->attr.caps.interrupt_mode ? VNET_HW_IF_CAP_INT_MODE : 0;
677 caps |= port->attr.caps.mac_filter ? VNET_HW_IF_CAP_MAC_FILTER : 0;
678 caps |= port->attr.tx_offloads.tcp_gso ? VNET_HW_IF_CAP_TCP_GSO : 0;
679 caps |= port->attr.tx_offloads.ip4_cksum ? VNET_HW_IF_CAP_TX_CKSUM : 0;
680
681 if (caps)
Damjan Marion61e287b2024-10-08 20:50:56 +0200682 vnet_hw_if_set_caps (vnm, hw_if_index, caps);
Damjan Mariond1eb1b72023-12-07 16:40:02 +0100683
Damjan Marion38c61912023-10-17 16:06:26 +0000684 /* create / reuse rx node */
685 if (vec_len (dm->free_rx_node_indices))
686 {
687 vlib_node_t *n;
688 rx_node_index = vec_pop (dm->free_rx_node_indices);
Damjan Marion61e287b2024-10-08 20:50:56 +0200689 vlib_node_rename (vm, rx_node_index, "%s-rx",
690 port->interfaces->primary_interface.name);
Damjan Marion38c61912023-10-17 16:06:26 +0000691 n = vlib_get_node (vm, rx_node_index);
692 n->function = vlib_node_get_preferred_node_fn_variant (
693 vm, port->rx_node.registrations);
694 n->format_trace = port->rx_node.format_trace;
695 vlib_register_errors (vm, rx_node_index,
696 port->rx_node.n_error_counters, 0,
697 port->rx_node.error_counters);
698 }
699 else
700 {
701 dev_class->format_tx_trace = port->tx_node.format_trace;
702 dev_class->tx_function_error_counters = port->tx_node.error_counters;
703 dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
704 vlib_node_registration_t rx_node_reg = {
705 .sibling_of = "port-rx-eth",
706 .type = VLIB_NODE_TYPE_INPUT,
707 .state = VLIB_NODE_STATE_DISABLED,
708 .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
709 .node_fn_registrations = port->rx_node.registrations,
710 .format_trace = port->rx_node.format_trace,
711 .error_counters = port->rx_node.error_counters,
712 .n_errors = port->rx_node.n_error_counters,
713 };
Damjan Marion61e287b2024-10-08 20:50:56 +0200714 rx_node_index = vlib_register_node (vm, &rx_node_reg, "%s-rx",
715 ifs->primary_interface.name);
Damjan Marion38c61912023-10-17 16:06:26 +0000716 }
717 port->rx_node_assigned = 1;
Damjan Marion61e287b2024-10-08 20:50:56 +0200718 ifs->rx_node_index = rx_node_index;
719 ifs->primary_interface.rx_next_index =
Damjan Marion38c61912023-10-17 16:06:26 +0000720 vnet_dev_default_next_index_by_port_type[port->attr.type];
721
722 vlib_worker_thread_node_runtime_update ();
723 log_debug (dev,
724 "ethernet interface created, hw_if_index %u sw_if_index %u "
725 "rx_node_index %u tx_node_index %u",
Damjan Marion61e287b2024-10-08 20:50:56 +0200726 hw_if_index, sw_if_index, rx_node_index,
727 ifs->primary_interface.tx_node_index);
Damjan Marion38c61912023-10-17 16:06:26 +0000728 }
729
Damjan Marion38c61912023-10-17 16:06:26 +0000730 foreach_vnet_dev_port_rx_queue (q, port)
731 {
Damjan Marion61e287b2024-10-08 20:50:56 +0200732 vnet_dev_port_init_if_rt_data (vm, port, &q->if_rt_data,
733 ifs->primary_interface.sw_if_index);
Damjan Marion38c61912023-10-17 16:06:26 +0000734 /* poison to catch node not calling runtime update function */
Damjan Marion61e287b2024-10-08 20:50:56 +0200735 q->interrupt_mode = ifs->default_is_intr_mode;
Damjan Marion38c61912023-10-17 16:06:26 +0000736 vnet_dev_rx_queue_rt_request (
737 vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
738 }
739
740 vnet_dev_port_update_tx_node_runtime (vm, port);
741
742 if (port->port_ops.init)
743 rv = port->port_ops.init (vm, port);
744
745error:
746 if (rv != VNET_DEV_OK)
747 vnet_dev_port_if_remove (vm, port);
Damjan Marion61e287b2024-10-08 20:50:56 +0200748 else
749 a->sw_if_index = ifs->primary_interface.sw_if_index;
Damjan Marion38c61912023-10-17 16:06:26 +0000750 return rv;
751}
752
753vnet_dev_rv_t
754vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port)
755{
756 vnet_dev_main_t *dm = &vnet_dev_main;
757 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion61e287b2024-10-08 20:50:56 +0200758 vnet_dev_port_interfaces_t *ifs = port->interfaces;
Damjan Marion38c61912023-10-17 16:06:26 +0000759
760 vnet_dev_port_validate (vm, port);
761
762 if (port->started)
763 vnet_dev_port_stop (vm, port);
764
765 if (port->rx_node_assigned)
766 {
Damjan Marion61e287b2024-10-08 20:50:56 +0200767 vlib_node_rename (vm, ifs->rx_node_index, "deleted-%u",
768 ifs->rx_node_index);
769 vec_add1 (dm->free_rx_node_indices, ifs->rx_node_index);
Damjan Marion38c61912023-10-17 16:06:26 +0000770 port->rx_node_assigned = 0;
771 }
772
Damjan Marion61e287b2024-10-08 20:50:56 +0200773 if (ifs)
Damjan Marion38c61912023-10-17 16:06:26 +0000774 {
775 vlib_worker_thread_barrier_sync (vm);
Damjan Marion61e287b2024-10-08 20:50:56 +0200776 vnet_delete_hw_interface (vnm, ifs->primary_interface.hw_if_index);
Damjan Marion38c61912023-10-17 16:06:26 +0000777 vlib_worker_thread_barrier_release (vm);
Damjan Marion61e287b2024-10-08 20:50:56 +0200778 pool_put_index (dm->dev_instances, ifs->primary_interface.dev_instance);
779 clib_mem_free (port->interfaces);
780 port->interfaces = 0;
Damjan Marion38c61912023-10-17 16:06:26 +0000781 }
782
Damjan Marion38c61912023-10-17 16:06:26 +0000783 if (port->port_ops.deinit)
784 port->port_ops.deinit (vm, port);
785
786 foreach_vnet_dev_port_tx_queue (q, port)
787 vnet_dev_tx_queue_free (vm, q);
788
789 foreach_vnet_dev_port_rx_queue (q, port)
790 vnet_dev_rx_queue_free (vm, q);
791
792 vnet_dev_port_free_counters (vm, port);
793
Damjan Marion69768d92023-11-13 17:33:32 +0000794 foreach_vnet_dev_port_args (v, port)
795 vnet_dev_arg_clear_value (v);
796
Damjan Marion38c61912023-10-17 16:06:26 +0000797 return VNET_DEV_OK;
798}
Damjan Marion61e287b2024-10-08 20:50:56 +0200799
800vnet_dev_rv_t
801vnet_dev_port_del_sec_if_internal (vlib_main_t *vm, vnet_dev_port_t *port,
802 vnet_dev_port_interface_t *sif)
803{
804 vnet_dev_rv_t rv = VNET_DEV_OK;
805
806 if (sif && port->port_ops.add_sec_if)
807 rv = port->port_ops.add_sec_if (vm, port, sif);
808
809 if (rv != VNET_DEV_OK)
810 return rv;
811
812 foreach_vnet_dev_port_rx_queue (q, port)
813 {
814 vec_foreach_pointer (p, q->sec_if_rt_data)
815 if (p)
816 clib_mem_free (p);
817 vec_free (q->sec_if_rt_data);
818 }
819
820 if (sif->interface_created)
821 ethernet_delete_interface (vnet_get_main (), sif->hw_if_index);
822
823 pool_put_index (port->interfaces->secondary_interfaces, sif->index);
824 vnet_dev_arg_free (&sif->args);
825 clib_mem_free (sif);
826 return rv;
827}
828
829vnet_dev_rv_t
830vnet_dev_port_add_sec_if (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr)
831{
832 vnet_dev_main_t *dm = &vnet_dev_main;
833 vnet_dev_port_sec_if_create_args_t *a = ptr;
834 vnet_main_t *vnm = vnet_get_main ();
835 vnet_dev_t *dev = port->dev;
836 vnet_dev_port_interface_t *sif = 0;
837 vnet_dev_port_interface_t **sip;
838 vnet_dev_rv_t rv = VNET_DEV_OK;
839
840 sif = clib_mem_alloc (sizeof (vnet_dev_port_interface_t));
841 pool_get (port->interfaces->secondary_interfaces, sip);
842 *sip = sif;
843
844 *sif = (vnet_dev_port_interface_t){
845 .index = sip - port->interfaces->secondary_interfaces,
846 .args = vec_dup (port->sec_if_args),
847 };
848
849 clib_memcpy (sif->name, a->name, sizeof (sif->name));
850
851 if (sif->args)
852 {
853 rv = vnet_dev_arg_parse (vm, dev, sif->args, a->args);
854 if (rv != VNET_DEV_OK)
855 return rv;
856 }
857
858 if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
859 {
860 vnet_device_class_t *dev_class;
861 vnet_dev_driver_t *driver;
862 vnet_sw_interface_t *sw;
863 vnet_hw_interface_t *hw;
864 vnet_dev_instance_t *di;
865 vnet_hw_if_caps_t caps = 0;
866
867 pool_get (dm->dev_instances, di);
868 sif->dev_instance = di - dm->dev_instances;
869 di->port = port;
870 di->sec_if_index = sip - port->interfaces->secondary_interfaces;
871
872 driver = pool_elt_at_index (dm->drivers, dev->driver_index);
873
874 /* hack to provide per-port tx node function */
875 dev_class = vnet_get_device_class (vnm, driver->dev_class_index);
876 dev_class->tx_fn_registrations = port->tx_node.registrations;
877 dev_class->format_tx_trace = port->tx_node.format_trace;
878 dev_class->tx_function_error_counters = port->tx_node.error_counters;
879 dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
880
881 /* create new interface including tx and output nodes */
882 sif->hw_if_index = vnet_eth_register_interface (
883 vnm, &(vnet_eth_interface_registration_t){
884 .address = port->primary_hw_addr.eth_mac,
885 .max_frame_size = port->max_rx_frame_size,
886 .dev_class_index = driver->dev_class_index,
887 .dev_instance = sif->dev_instance,
888 .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size,
889 .cb.flag_change = vnet_dev_port_eth_flag_change,
890 });
891
892 sw = vnet_get_hw_sw_interface (vnm, sif->hw_if_index);
893 hw = vnet_get_hw_interface (vnm, sif->hw_if_index);
894 sif->sw_if_index = sw->sw_if_index;
895 sif->next_index =
896 vnet_dev_default_next_index_by_port_type[port->attr.type];
897 sif->interface_created = 1;
898 vnet_dev_port_update_tx_node_runtime (vm, port);
899 vnet_hw_interface_set_flags (
900 vnm, sif->hw_if_index,
901 port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
902 if (port->speed)
903 vnet_hw_interface_set_link_speed (vnm, sif->hw_if_index, port->speed);
904
905 sif->tx_node_index = hw->tx_node_index;
906
907 caps |= port->attr.caps.interrupt_mode ? VNET_HW_IF_CAP_INT_MODE : 0;
908 caps |= port->attr.caps.mac_filter ? VNET_HW_IF_CAP_MAC_FILTER : 0;
909 caps |= port->attr.tx_offloads.tcp_gso ? VNET_HW_IF_CAP_TCP_GSO : 0;
910 caps |= port->attr.tx_offloads.ip4_cksum ? VNET_HW_IF_CAP_TX_CKSUM : 0;
911
912 if (caps)
913 vnet_hw_if_set_caps (vnm, sif->hw_if_index, caps);
914 }
915 else
916 return VNET_DEV_ERR_NOT_SUPPORTED;
917
918 foreach_vnet_dev_port_rx_queue (q, port)
919 {
920 vnet_dev_rx_queue_if_rt_data_t *rtd;
921 vec_validate (q->sec_if_rt_data, sif->index);
922
923 rtd = clib_mem_alloc_aligned (sizeof (vnet_dev_rx_queue_if_rt_data_t),
924 CLIB_CACHE_LINE_BYTES);
925
926 q->sec_if_rt_data[sif->index] = rtd;
927
928 vnet_dev_port_init_if_rt_data (vm, port, rtd, sif->sw_if_index);
929 vnet_dev_rx_queue_rt_request (
930 vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
931 }
932
933 if (sif && port->port_ops.add_sec_if)
934 rv = port->port_ops.add_sec_if (vm, port, sif);
935
936 if (rv != VNET_DEV_OK)
937 vnet_dev_port_del_sec_if_internal (vm, port, sif);
938
939 return rv;
940}
941
942vnet_dev_rv_t
943vnet_dev_port_del_sec_if (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr)
944{
945 vnet_dev_port_del_sec_if_args_t *a = ptr;
946 vnet_sw_interface_t *si;
947 vnet_hw_interface_t *hi;
948 vnet_dev_instance_t *di;
949 vnet_main_t *vnm = vnet_get_main ();
950
951 log_debug (port->dev, "%u", a->sw_if_index);
952
953 si = vnet_get_sw_interface_or_null (vnm, a->sw_if_index);
954 if (!si)
955 return VNET_DEV_ERR_UNKNOWN_INTERFACE;
956
957 hi = vnet_get_hw_interface (vnm, si->hw_if_index);
958 di = vnet_dev_get_dev_instance (hi->dev_instance);
959
960 return vnet_dev_port_del_sec_if_internal (
961 vm, port, vnet_dev_port_get_sec_if_by_index (port, di->sec_if_index));
962}
963
Damjan Marion38c61912023-10-17 16:06:26 +0000964void
965vnet_dev_port_clear_counters (vlib_main_t *vm, vnet_dev_port_t *port)
966{
Monendra Singh Kushwaha2ea1e2c2024-05-21 03:18:26 +0530967 if (port->port_ops.clear_counters)
968 port->port_ops.clear_counters (vm, port);
969 else if (port->counter_main)
Damjan Marion38c61912023-10-17 16:06:26 +0000970 vnet_dev_counters_clear (vm, port->counter_main);
971
972 foreach_vnet_dev_port_rx_queue (q, port)
Monendra Singh Kushwaha2ea1e2c2024-05-21 03:18:26 +0530973 {
974 if (port->rx_queue_ops.clear_counters)
975 port->rx_queue_ops.clear_counters (vm, q);
976 else if (q->counter_main)
977 vnet_dev_counters_clear (vm, q->counter_main);
978 }
Damjan Marion38c61912023-10-17 16:06:26 +0000979
980 foreach_vnet_dev_port_tx_queue (q, port)
Monendra Singh Kushwaha2ea1e2c2024-05-21 03:18:26 +0530981 {
982 if (port->tx_queue_ops.clear_counters)
983 port->tx_queue_ops.clear_counters (vm, q);
984 else if (q->counter_main)
985 vnet_dev_counters_clear (vm, q->counter_main);
986 }
Damjan Marion38c61912023-10-17 16:06:26 +0000987
988 log_notice (port->dev, "counters cleared on port %u", port->port_id);
989}