blob: df7805c1ff29c3604942e912d86b14cef59f4a53 [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 Marion38c61912023-10-17 16:06:26 +000097 pool_put_index (dev->ports, port->index);
98 clib_mem_free (port);
99}
100
101void
102vnet_dev_port_update_tx_node_runtime (vlib_main_t *vm, vnet_dev_port_t *port)
103{
104 vnet_dev_port_validate (vm, port);
105
106 foreach_vnet_dev_port_tx_queue (q, port)
107 {
108 u32 ti;
109 clib_bitmap_foreach (ti, q->assigned_threads)
110 {
111 vlib_main_t *tvm = vlib_get_main_by_index (ti);
112 vlib_node_runtime_t *nr =
113 vlib_node_get_runtime (tvm, port->intf.tx_node_index);
114 vnet_dev_tx_node_runtime_t *tnr = vnet_dev_get_tx_node_runtime (nr);
115 tnr->hw_if_index = port->intf.hw_if_index;
116 tnr->tx_queue = q;
117 }
118 }
119}
120
121void
122vnet_dev_port_stop (vlib_main_t *vm, vnet_dev_port_t *port)
123{
124 vnet_dev_t *dev = port->dev;
125 vnet_dev_rt_op_t *ops = 0;
Damjan Marionb8dd9812023-11-03 13:47:05 +0000126 u16 n_threads = vlib_get_n_threads ();
Damjan Marion38c61912023-10-17 16:06:26 +0000127
128 log_debug (dev, "stopping port %u", port->port_id);
129
Damjan Marionb8dd9812023-11-03 13:47:05 +0000130 for (u16 i = 0; i < n_threads; i++)
131 {
132 vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
133 vec_add1 (ops, op);
134 }
Damjan Marion38c61912023-10-17 16:06:26 +0000135
136 vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
137 vec_free (ops);
138
139 port->port_ops.stop (vm, port);
140
141 foreach_vnet_dev_port_rx_queue (q, port)
142 {
143 q->started = 0;
144 log_debug (dev, "port %u rx queue %u stopped", port->port_id,
145 q->queue_id);
146 }
147
148 foreach_vnet_dev_port_tx_queue (q, port)
149 {
150 q->started = 0;
151 log_debug (dev, "port %u tx queue %u stopped", port->port_id,
152 q->queue_id);
153 }
154
155 log_debug (dev, "port %u stopped", port->port_id);
156 port->started = 0;
157}
158
159vnet_dev_rv_t
160vnet_dev_port_start_all_rx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
161{
162 vnet_dev_rv_t rv = VNET_DEV_OK;
163
164 vnet_dev_port_validate (vm, port);
165
166 foreach_vnet_dev_port_rx_queue (q, port)
167 {
168 rv = vnet_dev_rx_queue_start (vm, q);
169 if (rv != VNET_DEV_OK)
170 return rv;
171 }
172 return rv;
173}
174
175vnet_dev_rv_t
176vnet_dev_port_start_all_tx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
177{
178 vnet_dev_rv_t rv = VNET_DEV_OK;
179
180 vnet_dev_port_validate (vm, port);
181
182 foreach_vnet_dev_port_tx_queue (q, port)
183 {
184 rv = vnet_dev_tx_queue_start (vm, q);
185 if (rv != VNET_DEV_OK)
186 return rv;
187 }
188 return rv;
189}
190
191vnet_dev_rv_t
192vnet_dev_port_start (vlib_main_t *vm, vnet_dev_port_t *port)
193{
Damjan Marionb8dd9812023-11-03 13:47:05 +0000194 u16 n_threads = vlib_get_n_threads ();
Damjan Marion38c61912023-10-17 16:06:26 +0000195 vnet_dev_t *dev = port->dev;
196 vnet_dev_rt_op_t *ops = 0;
197 vnet_dev_rv_t rv;
198
199 vnet_dev_port_validate (vm, port);
200
201 log_debug (dev, "starting port %u", port->port_id);
202
203 vnet_dev_port_update_tx_node_runtime (vm, port);
204
205 if ((rv = port->port_ops.start (vm, port)) != VNET_DEV_OK)
206 {
207 vnet_dev_port_stop (vm, port);
208 return rv;
209 }
210
Damjan Marionb8dd9812023-11-03 13:47:05 +0000211 for (u16 i = 0; i < n_threads; i++)
212 {
213 vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
214 vec_add1 (ops, op);
215 }
Damjan Marion38c61912023-10-17 16:06:26 +0000216
217 vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
218 vec_free (ops);
219
220 foreach_vnet_dev_port_rx_queue (q, port)
221 if (q->enabled)
222 {
223 log_debug (dev, "port %u rx queue %u started", port->port_id,
224 q->queue_id);
225 q->started = 1;
226 }
227
228 foreach_vnet_dev_port_tx_queue (q, port)
229 if (q->enabled)
230 {
231 log_debug (dev, "port %u tx queue %u started", port->port_id,
232 q->queue_id);
233 q->started = 1;
234 }
235
236 port->started = 1;
237 log_debug (dev, "port %u started", port->port_id);
238
239 return VNET_DEV_OK;
240}
241
242vnet_dev_rv_t
243vnet_dev_port_add (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_port_id_t id,
244 vnet_dev_port_add_args_t *args)
245{
246 vnet_dev_port_t **pp, *port;
247 vnet_dev_rv_t rv = VNET_DEV_OK;
248
249 ASSERT (args->port.attr.type != VNET_DEV_PORT_TYPE_UNKNOWN);
Damjan Marione596ca12023-11-08 19:12:27 +0000250 ASSERT (args->port.attr.max_supported_rx_frame_size);
Damjan Marion38c61912023-10-17 16:06:26 +0000251
252 port =
253 vnet_dev_alloc_with_data (sizeof (vnet_dev_port_t), args->port.data_size);
254 pool_get (dev->ports, pp);
255 pp[0] = port;
256 clib_memcpy (vnet_dev_get_port_data (port), args->port.initial_data,
257 args->port.data_size);
258 port->port_id = id;
259 port->index = pp - dev->ports;
260 port->dev = dev;
261 port->attr = args->port.attr;
262 port->rx_queue_config = args->rx_queue.config;
263 port->tx_queue_config = args->tx_queue.config;
264 port->rx_queue_ops = args->rx_queue.ops;
265 port->tx_queue_ops = args->tx_queue.ops;
266 port->port_ops = args->port.ops;
267 port->rx_node = *args->rx_node;
268 port->tx_node = *args->tx_node;
269
Damjan Marion07a62cc2023-11-16 19:14:12 +0000270 if (args->port.args)
271 for (vnet_dev_arg_t *a = args->port.args; a->type != VNET_DEV_ARG_END; a++)
272 vec_add1 (port->args, *a);
Damjan Marion69768d92023-11-13 17:33:32 +0000273
Damjan Marion38c61912023-10-17 16:06:26 +0000274 /* defaults out of port attributes */
Damjan Marione596ca12023-11-08 19:12:27 +0000275 port->max_rx_frame_size = args->port.attr.max_supported_rx_frame_size;
Damjan Marion38c61912023-10-17 16:06:26 +0000276 port->primary_hw_addr = args->port.attr.hw_addr;
277
Damjan Marione596ca12023-11-08 19:12:27 +0000278 if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
279 {
280 if (port->max_rx_frame_size > 1514 &&
281 port->attr.caps.change_max_rx_frame_size)
282 port->max_rx_frame_size = 1514;
283 }
284
Damjan Marion38c61912023-10-17 16:06:26 +0000285 if (port->port_ops.alloc)
286 rv = port->port_ops.alloc (vm, port);
287
288 if (rv == VNET_DEV_OK)
289 port->initialized = 1;
290
291 return rv;
292}
293
294vnet_dev_rv_t
295vnet_dev_port_cfg_change_req_validate (vlib_main_t *vm, vnet_dev_port_t *port,
296 vnet_dev_port_cfg_change_req_t *req)
297{
298 vnet_dev_rv_t rv;
299 vnet_dev_hw_addr_t *addr;
300 int found;
301
302 if (req->validated)
303 return VNET_DEV_OK;
304
305 switch (req->type)
306 {
Damjan Marione596ca12023-11-08 19:12:27 +0000307 case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
Alok Mishraf7f26e52024-04-26 15:45:49 +0530308 if ((req->max_rx_frame_size > port->attr.max_supported_rx_frame_size) ||
309 (req->max_rx_frame_size < ETHERNET_MIN_PACKET_BYTES))
Damjan Marion38c61912023-10-17 16:06:26 +0000310 return VNET_DEV_ERR_INVALID_VALUE;
Damjan Marione596ca12023-11-08 19:12:27 +0000311 if (req->max_rx_frame_size == port->max_rx_frame_size)
Damjan Marion38c61912023-10-17 16:06:26 +0000312 return VNET_DEV_ERR_NO_CHANGE;
313 break;
314
315 case VNET_DEV_PORT_CFG_PROMISC_MODE:
316 if (req->promisc == port->promisc)
317 return VNET_DEV_ERR_NO_CHANGE;
318 break;
319
320 case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
321 if (clib_memcmp (&req->addr, &port->primary_hw_addr,
322 sizeof (vnet_dev_hw_addr_t)) == 0)
323 return VNET_DEV_ERR_NO_CHANGE;
324 break;
325
326 case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
327 pool_foreach (addr, port->secondary_hw_addr)
328 if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
329 return VNET_DEV_ERR_ALREADY_EXISTS;
330 break;
331
332 case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
333 found = 0;
334 pool_foreach (addr, port->secondary_hw_addr)
335 if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
336 found = 1;
337 if (!found)
338 return VNET_DEV_ERR_NO_SUCH_ENTRY;
339 break;
340
341 default:
342 break;
343 }
344
345 if (port->port_ops.config_change_validate)
346 {
347 rv = port->port_ops.config_change_validate (vm, port, req);
348 if (rv != VNET_DEV_OK)
349 return rv;
350 }
Damjan Marione596ca12023-11-08 19:12:27 +0000351 else
352 return VNET_DEV_ERR_NOT_SUPPORTED;
Damjan Marion38c61912023-10-17 16:06:26 +0000353
354 req->validated = 1;
355 return VNET_DEV_OK;
356}
357
358vnet_dev_rv_t
359vnet_dev_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
360 vnet_dev_port_cfg_change_req_t *req)
361{
362 vnet_dev_rv_t rv = VNET_DEV_OK;
363 vnet_dev_hw_addr_t *a;
Damjan Marionb8dd9812023-11-03 13:47:05 +0000364 vnet_dev_rx_queue_t *rxq = 0;
365 u8 enable = 0;
Damjan Marion38c61912023-10-17 16:06:26 +0000366
367 vnet_dev_port_validate (vm, port);
368
Damjan Marionb8dd9812023-11-03 13:47:05 +0000369 if (req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE ||
370 req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE)
371 {
372 if (req->all_queues == 0)
373 {
374 rxq = vnet_dev_port_get_rx_queue_by_id (port, req->queue_id);
375 if (rxq == 0)
376 return VNET_DEV_ERR_BUG;
377 }
378 }
379
380 if ((rv = vnet_dev_port_cfg_change_req_validate (vm, port, req)))
381 return rv;
Damjan Marion38c61912023-10-17 16:06:26 +0000382
383 if (port->port_ops.config_change)
384 rv = port->port_ops.config_change (vm, port, req);
Damjan Marione596ca12023-11-08 19:12:27 +0000385 else
386 return VNET_DEV_ERR_NOT_SUPPORTED;
Damjan Marion38c61912023-10-17 16:06:26 +0000387
388 if (rv != VNET_DEV_OK)
389 return rv;
390
391 switch (req->type)
392 {
Damjan Marione596ca12023-11-08 19:12:27 +0000393 case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
394 port->max_rx_frame_size = req->max_rx_frame_size;
Damjan Marion38c61912023-10-17 16:06:26 +0000395 break;
396
397 case VNET_DEV_PORT_CFG_PROMISC_MODE:
398 port->promisc = req->promisc;
399 break;
400
Damjan Marionb8dd9812023-11-03 13:47:05 +0000401 case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE:
402 enable = 1;
403 case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE:
404 if (req->all_queues)
405 {
406 clib_bitmap_t *bmp = 0;
407 vnet_dev_rt_op_t *ops = 0;
408 u32 i;
409
410 foreach_vnet_dev_port_rx_queue (q, port)
411 {
412 q->interrupt_mode = enable;
413 bmp = clib_bitmap_set (bmp, q->rx_thread_index, 1);
414 }
415
416 clib_bitmap_foreach (i, bmp)
417 {
418 vnet_dev_rt_op_t op = { .port = port, .thread_index = i };
419 vec_add1 (ops, op);
420 }
421
422 vnet_dev_rt_exec_ops (vm, port->dev, ops, vec_len (ops));
423 clib_bitmap_free (bmp);
424 vec_free (ops);
425 }
426 else
427 {
428 rxq->interrupt_mode = enable;
429 vnet_dev_rt_exec_ops (vm, port->dev,
430 &(vnet_dev_rt_op_t){
431 .port = port,
432 .thread_index = rxq->rx_thread_index,
433 },
434 1);
435 }
436 break;
437
Damjan Marion38c61912023-10-17 16:06:26 +0000438 case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
439 clib_memcpy (&port->primary_hw_addr, &req->addr,
440 sizeof (vnet_dev_hw_addr_t));
441 break;
442
443 case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
444 pool_get (port->secondary_hw_addr, a);
445 clib_memcpy (a, &req->addr, sizeof (vnet_dev_hw_addr_t));
446 break;
447
448 case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
449 pool_foreach (a, port->secondary_hw_addr)
450 if (clib_memcmp (a, &req->addr, sizeof (vnet_dev_hw_addr_t)) == 0)
451 {
452 pool_put (port->secondary_hw_addr, a);
453 break;
454 }
455 break;
456
457 default:
458 break;
459 }
460
461 return VNET_DEV_OK;
462}
463
464void
465vnet_dev_port_state_change (vlib_main_t *vm, vnet_dev_port_t *port,
466 vnet_dev_port_state_changes_t changes)
467{
468 vnet_main_t *vnm = vnet_get_main ();
469
470 vnet_dev_port_validate (vm, port);
471
472 if (changes.change.link_speed)
473 {
474 port->speed = changes.link_speed;
475 if (port->interface_created)
476 vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
477 changes.link_speed);
478 log_debug (port->dev, "port speed changed to %u", changes.link_speed);
479 }
480
481 if (changes.change.link_state)
482 {
483 port->link_up = changes.link_state;
484 if (port->interface_created)
485 vnet_hw_interface_set_flags (
486 vnm, port->intf.hw_if_index,
487 changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
488 log_debug (port->dev, "port link state changed to %s",
489 changes.link_state ? "up" : "down");
490 }
491}
492
493void
494vnet_dev_port_add_counters (vlib_main_t *vm, vnet_dev_port_t *port,
495 vnet_dev_counter_t *counters, u16 n_counters)
496{
497 vnet_dev_port_validate (vm, port);
498
499 port->counter_main =
500 vnet_dev_counters_alloc (vm, counters, n_counters, "%s port %u counters",
501 port->dev->device_id, port->port_id);
502}
503
504void
505vnet_dev_port_free_counters (vlib_main_t *vm, vnet_dev_port_t *port)
506{
507 vnet_dev_port_validate (vm, port);
508
509 if (port->counter_main)
510 vnet_dev_counters_free (vm, port->counter_main);
511}
512
513vnet_dev_rv_t
514vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
515{
516 vnet_main_t *vnm = vnet_get_main ();
517 u16 n_threads = vlib_get_n_threads ();
518 vnet_dev_main_t *dm = &vnet_dev_main;
519 vnet_dev_t *dev = port->dev;
520 vnet_dev_port_t **pp;
521 vnet_dev_rv_t rv;
522 u16 ti = 0;
523
524 if (port->intf.name[0] == 0)
525 {
526 u8 *s;
527 s = format (0, "%s%u/%u",
528 dm->drivers[port->dev->driver_index].registration->name,
529 port->dev->index, port->index);
530 u32 n = vec_len (s);
531
532 if (n >= sizeof (port->intf.name))
533 {
534 vec_free (s);
535 return VNET_DEV_ERR_BUG;
536 }
537 clib_memcpy (port->intf.name, s, n);
538 port->intf.name[n] = 0;
539 vec_free (s);
540 }
541
542 log_debug (
543 dev, "allocating %u rx queues with size %u and %u tx queues with size %u",
544 port->intf.num_rx_queues, port->intf.rxq_sz, port->intf.num_tx_queues,
545 port->intf.txq_sz);
546
547 for (int i = 0; i < port->intf.num_rx_queues; i++)
548 if ((rv = vnet_dev_rx_queue_alloc (vm, port, port->intf.rxq_sz)) !=
549 VNET_DEV_OK)
550 goto error;
551
552 for (u32 i = 0; i < port->intf.num_tx_queues; i++)
553 if ((rv = vnet_dev_tx_queue_alloc (vm, port, port->intf.txq_sz)) !=
554 VNET_DEV_OK)
555 goto error;
556
557 foreach_vnet_dev_port_tx_queue (q, port)
558 {
559 q->assigned_threads = clib_bitmap_set (q->assigned_threads, ti, 1);
560 log_debug (dev, "port %u tx queue %u assigned to thread %u",
561 port->port_id, q->queue_id, ti);
562 if (++ti >= n_threads)
563 break;
564 }
565
566 /* pool of port pointers helps us to assign unique dev_instance */
567 pool_get (dm->ports_by_dev_instance, pp);
568 port->intf.dev_instance = pp - dm->ports_by_dev_instance;
569 pp[0] = port;
570
571 if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
572 {
573 vnet_device_class_t *dev_class;
574 vnet_dev_driver_t *driver;
575 vnet_sw_interface_t *sw;
576 vnet_hw_interface_t *hw;
Damjan Mariond1eb1b72023-12-07 16:40:02 +0100577 vnet_hw_if_caps_t caps = 0;
Damjan Marion38c61912023-10-17 16:06:26 +0000578 u32 rx_node_index;
579
580 driver = pool_elt_at_index (dm->drivers, dev->driver_index);
581
582 /* hack to provide per-port tx node function */
583 dev_class = vnet_get_device_class (vnm, driver->dev_class_index);
584 dev_class->tx_fn_registrations = port->tx_node.registrations;
585 dev_class->format_tx_trace = port->tx_node.format_trace;
586 dev_class->tx_function_error_counters = port->tx_node.error_counters;
587 dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
588
589 /* create new interface including tx and output nodes */
590 port->intf.hw_if_index = vnet_eth_register_interface (
591 vnm, &(vnet_eth_interface_registration_t){
592 .address = port->primary_hw_addr.eth_mac,
Damjan Marione596ca12023-11-08 19:12:27 +0000593 .max_frame_size = port->max_rx_frame_size,
Damjan Marion38c61912023-10-17 16:06:26 +0000594 .dev_class_index = driver->dev_class_index,
595 .dev_instance = port->intf.dev_instance,
596 .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size,
597 .cb.flag_change = vnet_dev_port_eth_flag_change,
598 });
599
600 sw = vnet_get_hw_sw_interface (vnm, port->intf.hw_if_index);
601 hw = vnet_get_hw_interface (vnm, port->intf.hw_if_index);
602 port->intf.sw_if_index = sw->sw_if_index;
603 vnet_hw_interface_set_flags (
604 vnm, port->intf.hw_if_index,
605 port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
606 if (port->speed)
607 vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
608 port->speed);
609
610 port->intf.tx_node_index = hw->tx_node_index;
611
Damjan Mariond1eb1b72023-12-07 16:40:02 +0100612 caps |= port->attr.caps.interrupt_mode ? VNET_HW_IF_CAP_INT_MODE : 0;
613 caps |= port->attr.caps.mac_filter ? VNET_HW_IF_CAP_MAC_FILTER : 0;
614 caps |= port->attr.tx_offloads.tcp_gso ? VNET_HW_IF_CAP_TCP_GSO : 0;
615 caps |= port->attr.tx_offloads.ip4_cksum ? VNET_HW_IF_CAP_TX_CKSUM : 0;
616
617 if (caps)
618 vnet_hw_if_set_caps (vnm, port->intf.hw_if_index, caps);
619
Damjan Marion38c61912023-10-17 16:06:26 +0000620 /* create / reuse rx node */
621 if (vec_len (dm->free_rx_node_indices))
622 {
623 vlib_node_t *n;
624 rx_node_index = vec_pop (dm->free_rx_node_indices);
625 vlib_node_rename (vm, rx_node_index, "%s-rx", port->intf.name);
626 n = vlib_get_node (vm, rx_node_index);
627 n->function = vlib_node_get_preferred_node_fn_variant (
628 vm, port->rx_node.registrations);
629 n->format_trace = port->rx_node.format_trace;
630 vlib_register_errors (vm, rx_node_index,
631 port->rx_node.n_error_counters, 0,
632 port->rx_node.error_counters);
633 }
634 else
635 {
636 dev_class->format_tx_trace = port->tx_node.format_trace;
637 dev_class->tx_function_error_counters = port->tx_node.error_counters;
638 dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
639 vlib_node_registration_t rx_node_reg = {
640 .sibling_of = "port-rx-eth",
641 .type = VLIB_NODE_TYPE_INPUT,
642 .state = VLIB_NODE_STATE_DISABLED,
643 .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
644 .node_fn_registrations = port->rx_node.registrations,
645 .format_trace = port->rx_node.format_trace,
646 .error_counters = port->rx_node.error_counters,
647 .n_errors = port->rx_node.n_error_counters,
648 };
649 rx_node_index =
650 vlib_register_node (vm, &rx_node_reg, "%s-rx", port->intf.name);
651 }
652 port->rx_node_assigned = 1;
653 port->intf.rx_node_index = rx_node_index;
654 port->intf.rx_next_index =
655 vnet_dev_default_next_index_by_port_type[port->attr.type];
656
657 vlib_worker_thread_node_runtime_update ();
658 log_debug (dev,
659 "ethernet interface created, hw_if_index %u sw_if_index %u "
660 "rx_node_index %u tx_node_index %u",
661 port->intf.hw_if_index, port->intf.sw_if_index,
662 port->intf.rx_node_index, port->intf.tx_node_index);
663 }
664
665 port->interface_created = 1;
666 foreach_vnet_dev_port_rx_queue (q, port)
667 {
668 vnet_buffer (&q->buffer_template)->sw_if_index[VLIB_RX] =
669 port->intf.sw_if_index;
670 /* poison to catch node not calling runtime update function */
671 q->next_index = ~0;
Damjan Marionb8dd9812023-11-03 13:47:05 +0000672 q->interrupt_mode = port->intf.default_is_intr_mode;
Damjan Marion38c61912023-10-17 16:06:26 +0000673 vnet_dev_rx_queue_rt_request (
674 vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
675 }
676
677 vnet_dev_port_update_tx_node_runtime (vm, port);
678
679 if (port->port_ops.init)
680 rv = port->port_ops.init (vm, port);
681
682error:
683 if (rv != VNET_DEV_OK)
684 vnet_dev_port_if_remove (vm, port);
685 return rv;
686}
687
688vnet_dev_rv_t
689vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port)
690{
691 vnet_dev_main_t *dm = &vnet_dev_main;
692 vnet_main_t *vnm = vnet_get_main ();
693
694 vnet_dev_port_validate (vm, port);
695
696 if (port->started)
697 vnet_dev_port_stop (vm, port);
698
699 if (port->rx_node_assigned)
700 {
701 vlib_node_rename (vm, port->intf.rx_node_index, "deleted-%u",
702 port->intf.rx_node_index);
703 vec_add1 (dm->free_rx_node_indices, port->intf.rx_node_index);
704 port->rx_node_assigned = 0;
705 }
706
707 if (port->interface_created)
708 {
709 vlib_worker_thread_barrier_sync (vm);
710 vnet_delete_hw_interface (vnm, port->intf.hw_if_index);
711 vlib_worker_thread_barrier_release (vm);
712 pool_put_index (dm->ports_by_dev_instance, port->intf.dev_instance);
713 port->interface_created = 0;
714 }
715
716 port->intf = (typeof (port->intf)){};
717
718 if (port->port_ops.deinit)
719 port->port_ops.deinit (vm, port);
720
721 foreach_vnet_dev_port_tx_queue (q, port)
722 vnet_dev_tx_queue_free (vm, q);
723
724 foreach_vnet_dev_port_rx_queue (q, port)
725 vnet_dev_rx_queue_free (vm, q);
726
727 vnet_dev_port_free_counters (vm, port);
728
Damjan Marion69768d92023-11-13 17:33:32 +0000729 foreach_vnet_dev_port_args (v, port)
730 vnet_dev_arg_clear_value (v);
731
Damjan Marion38c61912023-10-17 16:06:26 +0000732 return VNET_DEV_OK;
733}
734void
735vnet_dev_port_clear_counters (vlib_main_t *vm, vnet_dev_port_t *port)
736{
Monendra Singh Kushwaha2ea1e2c2024-05-21 03:18:26 +0530737 if (port->port_ops.clear_counters)
738 port->port_ops.clear_counters (vm, port);
739 else if (port->counter_main)
Damjan Marion38c61912023-10-17 16:06:26 +0000740 vnet_dev_counters_clear (vm, port->counter_main);
741
742 foreach_vnet_dev_port_rx_queue (q, port)
Monendra Singh Kushwaha2ea1e2c2024-05-21 03:18:26 +0530743 {
744 if (port->rx_queue_ops.clear_counters)
745 port->rx_queue_ops.clear_counters (vm, q);
746 else if (q->counter_main)
747 vnet_dev_counters_clear (vm, q->counter_main);
748 }
Damjan Marion38c61912023-10-17 16:06:26 +0000749
750 foreach_vnet_dev_port_tx_queue (q, port)
Monendra Singh Kushwaha2ea1e2c2024-05-21 03:18:26 +0530751 {
752 if (port->tx_queue_ops.clear_counters)
753 port->tx_queue_ops.clear_counters (vm, q);
754 else if (q->counter_main)
755 vnet_dev_counters_clear (vm, q->counter_main);
756 }
Damjan Marion38c61912023-10-17 16:06:26 +0000757
758 log_notice (port->dev, "counters cleared on port %u", port->port_id);
759}