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