1 /* SPDX-License-Identifier: Apache-2.0
2 * Copyright (c) 2023 Cisco Systems, Inc.
6 #include <vnet/ethernet/ethernet.h>
7 #include <vnet/dev/dev.h>
8 #include <vnet/dev/counters.h>
9 #include <vnet/dev/log.h>
11 VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
13 .subclass_name = "port",
17 dummy_input_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
24 VLIB_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,
32 #define _(n, s) [VNET_DEV_ETH_RX_PORT_NEXT_##n] = s,
33 foreach_vnet_dev_port_rx_next
38 u16 vnet_dev_default_next_index_by_port_type[] = {
39 [VNET_DEV_PORT_TYPE_ETHERNET] = VNET_DEV_ETH_RX_PORT_NEXT_ETH_INPUT,
42 VNET_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,
49 VNET_FEATURE_INIT (l2_patch, static) = {
50 .arc_name = "port-rx-eth",
51 .node_name = "l2-patch",
52 .runs_before = VNET_FEATURES ("ethernet-input"),
55 VNET_FEATURE_INIT (worker_handoff, static) = {
56 .arc_name = "port-rx-eth",
57 .node_name = "worker-handoff",
58 .runs_before = VNET_FEATURES ("ethernet-input"),
61 VNET_FEATURE_INIT (span_input, static) = {
62 .arc_name = "port-rx-eth",
63 .node_name = "span-input",
64 .runs_before = VNET_FEATURES ("ethernet-input"),
67 VNET_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"),
73 VNET_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 */
80 vnet_dev_port_free (vlib_main_t *vm, vnet_dev_port_t *port)
82 vnet_dev_t *dev = port->dev;
84 vnet_dev_port_validate (vm, port);
86 ASSERT (port->started == 0);
88 log_debug (dev, "port %u", port->port_id);
90 if (port->port_ops.free)
91 port->port_ops.free (vm, port);
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);
101 vnet_dev_port_update_tx_node_runtime (vlib_main_t *vm, vnet_dev_port_t *port)
103 vnet_dev_port_validate (vm, port);
105 foreach_vnet_dev_port_tx_queue (q, port)
108 clib_bitmap_foreach (ti, q->assigned_threads)
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;
121 vnet_dev_port_stop (vlib_main_t *vm, vnet_dev_port_t *port)
123 vnet_dev_t *dev = port->dev;
124 vnet_dev_rt_op_t *ops = 0;
125 u16 n_threads = vlib_get_n_threads ();
127 log_debug (dev, "stopping port %u", port->port_id);
129 for (u16 i = 0; i < n_threads; i++)
131 vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
135 vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
138 port->port_ops.stop (vm, port);
140 foreach_vnet_dev_port_rx_queue (q, port)
143 log_debug (dev, "port %u rx queue %u stopped", port->port_id,
147 foreach_vnet_dev_port_tx_queue (q, port)
150 log_debug (dev, "port %u tx queue %u stopped", port->port_id,
154 log_debug (dev, "port %u stopped", port->port_id);
159 vnet_dev_port_start_all_rx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
161 vnet_dev_rv_t rv = VNET_DEV_OK;
163 vnet_dev_port_validate (vm, port);
165 foreach_vnet_dev_port_rx_queue (q, port)
167 rv = vnet_dev_rx_queue_start (vm, q);
168 if (rv != VNET_DEV_OK)
175 vnet_dev_port_start_all_tx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
177 vnet_dev_rv_t rv = VNET_DEV_OK;
179 vnet_dev_port_validate (vm, port);
181 foreach_vnet_dev_port_tx_queue (q, port)
183 rv = vnet_dev_tx_queue_start (vm, q);
184 if (rv != VNET_DEV_OK)
191 vnet_dev_port_start (vlib_main_t *vm, vnet_dev_port_t *port)
193 u16 n_threads = vlib_get_n_threads ();
194 vnet_dev_t *dev = port->dev;
195 vnet_dev_rt_op_t *ops = 0;
198 vnet_dev_port_validate (vm, port);
200 log_debug (dev, "starting port %u", port->port_id);
202 vnet_dev_port_update_tx_node_runtime (vm, port);
204 if ((rv = port->port_ops.start (vm, port)) != VNET_DEV_OK)
206 vnet_dev_port_stop (vm, port);
210 for (u16 i = 0; i < n_threads; i++)
212 vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
216 vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
219 foreach_vnet_dev_port_rx_queue (q, port)
222 log_debug (dev, "port %u rx queue %u started", port->port_id,
227 foreach_vnet_dev_port_tx_queue (q, port)
230 log_debug (dev, "port %u tx queue %u started", port->port_id,
236 log_debug (dev, "port %u started", port->port_id);
242 vnet_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)
245 vnet_dev_port_t **pp, *port;
246 vnet_dev_rv_t rv = VNET_DEV_OK;
248 ASSERT (args->port.attr.type != VNET_DEV_PORT_TYPE_UNKNOWN);
249 ASSERT (args->port.attr.max_supported_rx_frame_size);
252 vnet_dev_alloc_with_data (sizeof (vnet_dev_port_t), args->port.data_size);
253 pool_get (dev->ports, pp);
255 clib_memcpy (vnet_dev_get_port_data (port), args->port.initial_data,
256 args->port.data_size);
258 port->index = pp - dev->ports;
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;
269 /* defaults out of port attributes */
270 port->max_rx_frame_size = args->port.attr.max_supported_rx_frame_size;
271 port->primary_hw_addr = args->port.attr.hw_addr;
273 if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
275 if (port->max_rx_frame_size > 1514 &&
276 port->attr.caps.change_max_rx_frame_size)
277 port->max_rx_frame_size = 1514;
280 if (port->port_ops.alloc)
281 rv = port->port_ops.alloc (vm, port);
283 if (rv == VNET_DEV_OK)
284 port->initialized = 1;
290 vnet_dev_port_cfg_change_req_validate (vlib_main_t *vm, vnet_dev_port_t *port,
291 vnet_dev_port_cfg_change_req_t *req)
294 vnet_dev_hw_addr_t *addr;
302 case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
303 if (req->max_rx_frame_size > port->attr.max_supported_rx_frame_size)
304 return VNET_DEV_ERR_INVALID_VALUE;
305 if (req->max_rx_frame_size == port->max_rx_frame_size)
306 return VNET_DEV_ERR_NO_CHANGE;
309 case VNET_DEV_PORT_CFG_PROMISC_MODE:
310 if (req->promisc == port->promisc)
311 return VNET_DEV_ERR_NO_CHANGE;
314 case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
315 if (clib_memcmp (&req->addr, &port->primary_hw_addr,
316 sizeof (vnet_dev_hw_addr_t)) == 0)
317 return VNET_DEV_ERR_NO_CHANGE;
320 case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
321 pool_foreach (addr, port->secondary_hw_addr)
322 if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
323 return VNET_DEV_ERR_ALREADY_EXISTS;
326 case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
328 pool_foreach (addr, port->secondary_hw_addr)
329 if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
332 return VNET_DEV_ERR_NO_SUCH_ENTRY;
339 if (port->port_ops.config_change_validate)
341 rv = port->port_ops.config_change_validate (vm, port, req);
342 if (rv != VNET_DEV_OK)
346 return VNET_DEV_ERR_NOT_SUPPORTED;
353 vnet_dev_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
354 vnet_dev_port_cfg_change_req_t *req)
356 vnet_dev_rv_t rv = VNET_DEV_OK;
357 vnet_dev_hw_addr_t *a;
358 vnet_dev_rx_queue_t *rxq = 0;
361 vnet_dev_port_validate (vm, port);
363 if (req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE ||
364 req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE)
366 if (req->all_queues == 0)
368 rxq = vnet_dev_port_get_rx_queue_by_id (port, req->queue_id);
370 return VNET_DEV_ERR_BUG;
374 if ((rv = vnet_dev_port_cfg_change_req_validate (vm, port, req)))
377 if (port->port_ops.config_change)
378 rv = port->port_ops.config_change (vm, port, req);
380 return VNET_DEV_ERR_NOT_SUPPORTED;
382 if (rv != VNET_DEV_OK)
387 case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
388 port->max_rx_frame_size = req->max_rx_frame_size;
391 case VNET_DEV_PORT_CFG_PROMISC_MODE:
392 port->promisc = req->promisc;
395 case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE:
397 case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE:
400 clib_bitmap_t *bmp = 0;
401 vnet_dev_rt_op_t *ops = 0;
404 foreach_vnet_dev_port_rx_queue (q, port)
406 q->interrupt_mode = enable;
407 bmp = clib_bitmap_set (bmp, q->rx_thread_index, 1);
410 clib_bitmap_foreach (i, bmp)
412 vnet_dev_rt_op_t op = { .port = port, .thread_index = i };
416 vnet_dev_rt_exec_ops (vm, port->dev, ops, vec_len (ops));
417 clib_bitmap_free (bmp);
422 rxq->interrupt_mode = enable;
423 vnet_dev_rt_exec_ops (vm, port->dev,
426 .thread_index = rxq->rx_thread_index,
432 case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
433 clib_memcpy (&port->primary_hw_addr, &req->addr,
434 sizeof (vnet_dev_hw_addr_t));
437 case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
438 pool_get (port->secondary_hw_addr, a);
439 clib_memcpy (a, &req->addr, sizeof (vnet_dev_hw_addr_t));
442 case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
443 pool_foreach (a, port->secondary_hw_addr)
444 if (clib_memcmp (a, &req->addr, sizeof (vnet_dev_hw_addr_t)) == 0)
446 pool_put (port->secondary_hw_addr, a);
459 vnet_dev_port_state_change (vlib_main_t *vm, vnet_dev_port_t *port,
460 vnet_dev_port_state_changes_t changes)
462 vnet_main_t *vnm = vnet_get_main ();
464 vnet_dev_port_validate (vm, port);
466 if (changes.change.link_speed)
468 port->speed = changes.link_speed;
469 if (port->interface_created)
470 vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
472 log_debug (port->dev, "port speed changed to %u", changes.link_speed);
475 if (changes.change.link_state)
477 port->link_up = changes.link_state;
478 if (port->interface_created)
479 vnet_hw_interface_set_flags (
480 vnm, port->intf.hw_if_index,
481 changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
482 log_debug (port->dev, "port link state changed to %s",
483 changes.link_state ? "up" : "down");
488 vnet_dev_port_add_counters (vlib_main_t *vm, vnet_dev_port_t *port,
489 vnet_dev_counter_t *counters, u16 n_counters)
491 vnet_dev_port_validate (vm, port);
494 vnet_dev_counters_alloc (vm, counters, n_counters, "%s port %u counters",
495 port->dev->device_id, port->port_id);
499 vnet_dev_port_free_counters (vlib_main_t *vm, vnet_dev_port_t *port)
501 vnet_dev_port_validate (vm, port);
503 if (port->counter_main)
504 vnet_dev_counters_free (vm, port->counter_main);
508 vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
510 vnet_main_t *vnm = vnet_get_main ();
511 u16 n_threads = vlib_get_n_threads ();
512 vnet_dev_main_t *dm = &vnet_dev_main;
513 vnet_dev_t *dev = port->dev;
514 vnet_dev_port_t **pp;
518 if (port->intf.name[0] == 0)
521 s = format (0, "%s%u/%u",
522 dm->drivers[port->dev->driver_index].registration->name,
523 port->dev->index, port->index);
526 if (n >= sizeof (port->intf.name))
529 return VNET_DEV_ERR_BUG;
531 clib_memcpy (port->intf.name, s, n);
532 port->intf.name[n] = 0;
537 dev, "allocating %u rx queues with size %u and %u tx queues with size %u",
538 port->intf.num_rx_queues, port->intf.rxq_sz, port->intf.num_tx_queues,
541 for (int i = 0; i < port->intf.num_rx_queues; i++)
542 if ((rv = vnet_dev_rx_queue_alloc (vm, port, port->intf.rxq_sz)) !=
546 for (u32 i = 0; i < port->intf.num_tx_queues; i++)
547 if ((rv = vnet_dev_tx_queue_alloc (vm, port, port->intf.txq_sz)) !=
551 foreach_vnet_dev_port_tx_queue (q, port)
553 q->assigned_threads = clib_bitmap_set (q->assigned_threads, ti, 1);
554 log_debug (dev, "port %u tx queue %u assigned to thread %u",
555 port->port_id, q->queue_id, ti);
556 if (++ti >= n_threads)
560 /* pool of port pointers helps us to assign unique dev_instance */
561 pool_get (dm->ports_by_dev_instance, pp);
562 port->intf.dev_instance = pp - dm->ports_by_dev_instance;
565 if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
567 vnet_device_class_t *dev_class;
568 vnet_dev_driver_t *driver;
569 vnet_sw_interface_t *sw;
570 vnet_hw_interface_t *hw;
573 driver = pool_elt_at_index (dm->drivers, dev->driver_index);
575 /* hack to provide per-port tx node function */
576 dev_class = vnet_get_device_class (vnm, driver->dev_class_index);
577 dev_class->tx_fn_registrations = port->tx_node.registrations;
578 dev_class->format_tx_trace = port->tx_node.format_trace;
579 dev_class->tx_function_error_counters = port->tx_node.error_counters;
580 dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
582 /* create new interface including tx and output nodes */
583 port->intf.hw_if_index = vnet_eth_register_interface (
584 vnm, &(vnet_eth_interface_registration_t){
585 .address = port->primary_hw_addr.eth_mac,
586 .max_frame_size = port->max_rx_frame_size,
587 .dev_class_index = driver->dev_class_index,
588 .dev_instance = port->intf.dev_instance,
589 .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size,
590 .cb.flag_change = vnet_dev_port_eth_flag_change,
593 sw = vnet_get_hw_sw_interface (vnm, port->intf.hw_if_index);
594 hw = vnet_get_hw_interface (vnm, port->intf.hw_if_index);
595 port->intf.sw_if_index = sw->sw_if_index;
596 vnet_hw_interface_set_flags (
597 vnm, port->intf.hw_if_index,
598 port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
600 vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
603 port->intf.tx_node_index = hw->tx_node_index;
605 /* create / reuse rx node */
606 if (vec_len (dm->free_rx_node_indices))
609 rx_node_index = vec_pop (dm->free_rx_node_indices);
610 vlib_node_rename (vm, rx_node_index, "%s-rx", port->intf.name);
611 n = vlib_get_node (vm, rx_node_index);
612 n->function = vlib_node_get_preferred_node_fn_variant (
613 vm, port->rx_node.registrations);
614 n->format_trace = port->rx_node.format_trace;
615 vlib_register_errors (vm, rx_node_index,
616 port->rx_node.n_error_counters, 0,
617 port->rx_node.error_counters);
621 dev_class->format_tx_trace = port->tx_node.format_trace;
622 dev_class->tx_function_error_counters = port->tx_node.error_counters;
623 dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
624 vlib_node_registration_t rx_node_reg = {
625 .sibling_of = "port-rx-eth",
626 .type = VLIB_NODE_TYPE_INPUT,
627 .state = VLIB_NODE_STATE_DISABLED,
628 .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
629 .node_fn_registrations = port->rx_node.registrations,
630 .format_trace = port->rx_node.format_trace,
631 .error_counters = port->rx_node.error_counters,
632 .n_errors = port->rx_node.n_error_counters,
635 vlib_register_node (vm, &rx_node_reg, "%s-rx", port->intf.name);
637 port->rx_node_assigned = 1;
638 port->intf.rx_node_index = rx_node_index;
639 port->intf.rx_next_index =
640 vnet_dev_default_next_index_by_port_type[port->attr.type];
642 vlib_worker_thread_node_runtime_update ();
644 "ethernet interface created, hw_if_index %u sw_if_index %u "
645 "rx_node_index %u tx_node_index %u",
646 port->intf.hw_if_index, port->intf.sw_if_index,
647 port->intf.rx_node_index, port->intf.tx_node_index);
650 port->interface_created = 1;
651 foreach_vnet_dev_port_rx_queue (q, port)
653 vnet_buffer (&q->buffer_template)->sw_if_index[VLIB_RX] =
654 port->intf.sw_if_index;
655 /* poison to catch node not calling runtime update function */
657 q->interrupt_mode = port->intf.default_is_intr_mode;
658 vnet_dev_rx_queue_rt_request (
659 vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
662 vnet_dev_port_update_tx_node_runtime (vm, port);
664 if (port->port_ops.init)
665 rv = port->port_ops.init (vm, port);
668 if (rv != VNET_DEV_OK)
669 vnet_dev_port_if_remove (vm, port);
674 vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port)
676 vnet_dev_main_t *dm = &vnet_dev_main;
677 vnet_main_t *vnm = vnet_get_main ();
679 vnet_dev_port_validate (vm, port);
682 vnet_dev_port_stop (vm, port);
684 if (port->rx_node_assigned)
686 vlib_node_rename (vm, port->intf.rx_node_index, "deleted-%u",
687 port->intf.rx_node_index);
688 vec_add1 (dm->free_rx_node_indices, port->intf.rx_node_index);
689 port->rx_node_assigned = 0;
692 if (port->interface_created)
694 vlib_worker_thread_barrier_sync (vm);
695 vnet_delete_hw_interface (vnm, port->intf.hw_if_index);
696 vlib_worker_thread_barrier_release (vm);
697 pool_put_index (dm->ports_by_dev_instance, port->intf.dev_instance);
698 port->interface_created = 0;
701 port->intf = (typeof (port->intf)){};
703 if (port->port_ops.deinit)
704 port->port_ops.deinit (vm, port);
706 foreach_vnet_dev_port_tx_queue (q, port)
707 vnet_dev_tx_queue_free (vm, q);
709 foreach_vnet_dev_port_rx_queue (q, port)
710 vnet_dev_rx_queue_free (vm, q);
712 vnet_dev_port_free_counters (vm, port);
717 vnet_dev_port_clear_counters (vlib_main_t *vm, vnet_dev_port_t *port)
719 if (port->counter_main)
720 vnet_dev_counters_clear (vm, port->counter_main);
722 foreach_vnet_dev_port_rx_queue (q, port)
724 vnet_dev_counters_clear (vm, q->counter_main);
726 foreach_vnet_dev_port_tx_queue (q, port)
728 vnet_dev_counters_clear (vm, q->counter_main);
730 log_notice (port->dev, "counters cleared on port %u", port->port_id);