diff options
author | Damjan Marion <damarion@cisco.com> | 2024-10-08 20:50:56 +0200 |
---|---|---|
committer | Damjan Marion <damjan.marion@gmail.com> | 2024-11-07 16:49:49 +0100 |
commit | 61e287b9f895fa7cd9809ec74e44efee780a5aad (patch) | |
tree | 2a1f6e6f038062940d9b04dce480ed07394c9407 /src/vnet/dev/port.c | |
parent | de020ab4788d75e70f0cfea4c21f09a4716be161 (diff) |
dev: secondary interfaces support
Type: feature
Change-Id: I6cc4340431b8273022955fca1600061a722e3ace
Signed-off-by: Damjan Marion <damarion@cisco.com>
Diffstat (limited to 'src/vnet/dev/port.c')
-rw-r--r-- | src/vnet/dev/port.c | 345 |
1 files changed, 286 insertions, 59 deletions
diff --git a/src/vnet/dev/port.c b/src/vnet/dev/port.c index 5bd4edf05c1..fccedebdcf4 100644 --- a/src/vnet/dev/port.c +++ b/src/vnet/dev/port.c @@ -94,6 +94,7 @@ vnet_dev_port_free (vlib_main_t *vm, vnet_dev_port_t *port) pool_free (port->rx_queues); pool_free (port->tx_queues); vnet_dev_arg_free (&port->args); + vnet_dev_arg_free (&port->sec_if_args); pool_put_index (dev->ports, port->index); clib_mem_free (port); } @@ -109,11 +110,23 @@ vnet_dev_port_update_tx_node_runtime (vlib_main_t *vm, vnet_dev_port_t *port) clib_bitmap_foreach (ti, q->assigned_threads) { vlib_main_t *tvm = vlib_get_main_by_index (ti); - vlib_node_runtime_t *nr = - vlib_node_get_runtime (tvm, port->intf.tx_node_index); - vnet_dev_tx_node_runtime_t *tnr = vnet_dev_get_tx_node_runtime (nr); - tnr->hw_if_index = port->intf.hw_if_index; + vlib_node_runtime_t *nr; + vnet_dev_tx_node_runtime_t *tnr; + vnet_dev_port_interfaces_t *ifs = port->interfaces; + + nr = + vlib_node_get_runtime (tvm, ifs->primary_interface.tx_node_index); + tnr = vnet_dev_get_tx_node_runtime (nr); + tnr->hw_if_index = ifs->primary_interface.hw_if_index; tnr->tx_queue = q; + + pool_foreach_pointer (sif, port->interfaces->secondary_interfaces) + { + nr = vlib_node_get_runtime (tvm, sif->tx_node_index); + tnr = vnet_dev_get_tx_node_runtime (nr); + tnr->hw_if_index = sif->hw_if_index; + tnr->tx_queue = q; + } } } } @@ -271,6 +284,11 @@ vnet_dev_port_add (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_port_id_t id, for (vnet_dev_arg_t *a = args->port.args; a->type != VNET_DEV_ARG_END; a++) vec_add1 (port->args, *a); + if (args->port.sec_if_args) + for (vnet_dev_arg_t *a = args->port.sec_if_args; + a->type != VNET_DEV_ARG_END; a++) + vec_add1 (port->sec_if_args, *a); + /* defaults out of port attributes */ port->max_rx_frame_size = args->port.attr.max_supported_rx_frame_size; port->primary_hw_addr = args->port.attr.hw_addr; @@ -466,25 +484,34 @@ vnet_dev_port_state_change (vlib_main_t *vm, vnet_dev_port_t *port, vnet_dev_port_state_changes_t changes) { vnet_main_t *vnm = vnet_get_main (); + vnet_dev_port_interfaces_t *ifs = port->interfaces; vnet_dev_port_validate (vm, port); if (changes.change.link_speed) { port->speed = changes.link_speed; - if (port->interface_created) - vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index, - changes.link_speed); + if (port->interfaces) + vnet_hw_interface_set_link_speed ( + vnm, ifs->primary_interface.hw_if_index, changes.link_speed); log_debug (port->dev, "port speed changed to %u", changes.link_speed); } if (changes.change.link_state) { port->link_up = changes.link_state; - if (port->interface_created) - vnet_hw_interface_set_flags ( - vnm, port->intf.hw_if_index, - changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); + if (ifs) + { + vnet_hw_interface_set_flags ( + vnm, ifs->primary_interface.hw_if_index, + changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); + pool_foreach_pointer (sif, ifs->secondary_interfaces) + { + vnet_hw_interface_set_flags ( + vnm, sif->hw_if_index, + changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); + } + } log_debug (port->dev, "port link state changed to %s", changes.link_state ? "up" : "down"); } @@ -510,19 +537,51 @@ vnet_dev_port_free_counters (vlib_main_t *vm, vnet_dev_port_t *port) vnet_dev_counters_free (vm, port->counter_main); } +static void +vnet_dev_port_init_if_rt_data (vlib_main_t *vm, vnet_dev_port_t *port, + vnet_dev_rx_queue_if_rt_data_t *rtd, + u32 sw_if_index) +{ + vnet_dev_t *dev = port->dev; + u8 buffer_pool_index = + vlib_buffer_pool_get_default_for_numa (vm, dev->numa_node); + vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index); + + rtd->buffer_template = bp->buffer_template; + vnet_buffer (&rtd->buffer_template)->sw_if_index[VLIB_RX] = sw_if_index; + vnet_buffer (&rtd->buffer_template)->sw_if_index[VLIB_TX] = ~0; + rtd->next_index = ~0; + rtd->sw_if_index = sw_if_index; +} + vnet_dev_rv_t -vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) +vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr) { vnet_main_t *vnm = vnet_get_main (); u16 n_threads = vlib_get_n_threads (); vnet_dev_main_t *dm = &vnet_dev_main; vnet_dev_t *dev = port->dev; + vnet_dev_port_if_create_args_t *a = ptr; + vnet_dev_port_interfaces_t *ifs = port->interfaces; vnet_dev_instance_t *di; vnet_dev_rv_t rv; u16 ti = 0; - u8 is_consistent_qp = port->intf.consistent_qp; - if (port->intf.name[0] == 0) + if (ifs) + return VNET_DEV_ERR_ALREADY_EXISTS; + + port->interfaces = ifs = + clib_mem_alloc (sizeof (vnet_dev_port_interfaces_t)); + + *(ifs) = (vnet_dev_port_interfaces_t){ + .num_rx_queues = a->num_rx_queues, + .num_tx_queues = a->num_tx_queues, + .rxq_sz = a->rxq_sz, + .txq_sz = a->txq_sz, + .default_is_intr_mode = a->default_is_intr_mode, + }; + + if (a->name[0] == 0) { u8 *s; s = format (0, "%s%u/%u", @@ -530,36 +589,36 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) port->dev->index, port->index); u32 n = vec_len (s); - if (n >= sizeof (port->intf.name)) + if (n >= sizeof (a->name)) { vec_free (s); return VNET_DEV_ERR_BUG; } - clib_memcpy (port->intf.name, s, n); - port->intf.name[n] = 0; + clib_memcpy (ifs->primary_interface.name, s, n); + ifs->primary_interface.name[n] = 0; vec_free (s); } + else + clib_memcpy (ifs->primary_interface.name, a->name, + sizeof (ifs->primary_interface.name)); log_debug ( dev, "allocating %u rx queues with size %u and %u tx queues with size %u", - port->intf.num_rx_queues, port->intf.rxq_sz, port->intf.num_tx_queues, - port->intf.txq_sz); + a->num_rx_queues, a->rxq_sz, a->num_tx_queues, a->txq_sz); - for (int i = 0; i < port->intf.num_rx_queues; i++) - if ((rv = vnet_dev_rx_queue_alloc (vm, port, port->intf.rxq_sz)) != - VNET_DEV_OK) + for (int i = 0; i < ifs->num_rx_queues; i++) + if ((rv = vnet_dev_rx_queue_alloc (vm, port, ifs->rxq_sz)) != VNET_DEV_OK) goto error; - for (u32 i = 0; i < port->intf.num_tx_queues; i++) - if ((rv = vnet_dev_tx_queue_alloc (vm, port, port->intf.txq_sz)) != - VNET_DEV_OK) + for (u32 i = 0; i < ifs->num_tx_queues; i++) + if ((rv = vnet_dev_tx_queue_alloc (vm, port, ifs->txq_sz)) != VNET_DEV_OK) goto error; foreach_vnet_dev_port_tx_queue (q, port) { /* if consistent_qp is enabled, we start by assigning queues to workers * and we end with main */ - u16 real_ti = (ti + is_consistent_qp) % n_threads; + u16 real_ti = (ti + a->consistent_qp) % n_threads; q->assigned_threads = clib_bitmap_set (q->assigned_threads, real_ti, 1); log_debug (dev, "port %u tx queue %u assigned to thread %u", port->port_id, q->queue_id, real_ti); @@ -568,8 +627,9 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) } pool_get (dm->dev_instances, di); - port->intf.dev_instance = di - dm->dev_instances; + ifs->primary_interface.dev_instance = di - dm->dev_instances; di->port = port; + di->is_primary_if = 1; if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET) { @@ -578,7 +638,7 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) vnet_sw_interface_t *sw; vnet_hw_interface_t *hw; vnet_hw_if_caps_t caps = 0; - u32 rx_node_index; + u32 rx_node_index, hw_if_index, sw_if_index; driver = pool_elt_at_index (dm->drivers, dev->driver_index); @@ -590,27 +650,28 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) dev_class->tx_function_n_errors = port->tx_node.n_error_counters; /* create new interface including tx and output nodes */ - port->intf.hw_if_index = vnet_eth_register_interface ( + hw_if_index = vnet_eth_register_interface ( vnm, &(vnet_eth_interface_registration_t){ .address = port->primary_hw_addr.eth_mac, .max_frame_size = port->max_rx_frame_size, .dev_class_index = driver->dev_class_index, - .dev_instance = port->intf.dev_instance, + .dev_instance = ifs->primary_interface.dev_instance, .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size, .cb.flag_change = vnet_dev_port_eth_flag_change, }); + ifs->primary_interface.hw_if_index = hw_if_index; - sw = vnet_get_hw_sw_interface (vnm, port->intf.hw_if_index); - hw = vnet_get_hw_interface (vnm, port->intf.hw_if_index); - port->intf.sw_if_index = sw->sw_if_index; + sw = vnet_get_hw_sw_interface (vnm, hw_if_index); + hw = vnet_get_hw_interface (vnm, hw_if_index); + sw_if_index = ifs->primary_interface.sw_if_index = sw->sw_if_index; vnet_hw_interface_set_flags ( - vnm, port->intf.hw_if_index, + vnm, ifs->primary_interface.hw_if_index, port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); if (port->speed) - vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index, - port->speed); + vnet_hw_interface_set_link_speed ( + vnm, ifs->primary_interface.hw_if_index, port->speed); - port->intf.tx_node_index = hw->tx_node_index; + ifs->primary_interface.tx_node_index = hw->tx_node_index; caps |= port->attr.caps.interrupt_mode ? VNET_HW_IF_CAP_INT_MODE : 0; caps |= port->attr.caps.mac_filter ? VNET_HW_IF_CAP_MAC_FILTER : 0; @@ -618,14 +679,15 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) caps |= port->attr.tx_offloads.ip4_cksum ? VNET_HW_IF_CAP_TX_CKSUM : 0; if (caps) - vnet_hw_if_set_caps (vnm, port->intf.hw_if_index, caps); + vnet_hw_if_set_caps (vnm, hw_if_index, caps); /* create / reuse rx node */ if (vec_len (dm->free_rx_node_indices)) { vlib_node_t *n; rx_node_index = vec_pop (dm->free_rx_node_indices); - vlib_node_rename (vm, rx_node_index, "%s-rx", port->intf.name); + vlib_node_rename (vm, rx_node_index, "%s-rx", + port->interfaces->primary_interface.name); n = vlib_get_node (vm, rx_node_index); n->function = vlib_node_get_preferred_node_fn_variant ( vm, port->rx_node.registrations); @@ -649,30 +711,28 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) .error_counters = port->rx_node.error_counters, .n_errors = port->rx_node.n_error_counters, }; - rx_node_index = - vlib_register_node (vm, &rx_node_reg, "%s-rx", port->intf.name); + rx_node_index = vlib_register_node (vm, &rx_node_reg, "%s-rx", + ifs->primary_interface.name); } port->rx_node_assigned = 1; - port->intf.rx_node_index = rx_node_index; - port->intf.rx_next_index = + ifs->rx_node_index = rx_node_index; + ifs->primary_interface.rx_next_index = vnet_dev_default_next_index_by_port_type[port->attr.type]; vlib_worker_thread_node_runtime_update (); log_debug (dev, "ethernet interface created, hw_if_index %u sw_if_index %u " "rx_node_index %u tx_node_index %u", - port->intf.hw_if_index, port->intf.sw_if_index, - port->intf.rx_node_index, port->intf.tx_node_index); + hw_if_index, sw_if_index, rx_node_index, + ifs->primary_interface.tx_node_index); } - port->interface_created = 1; foreach_vnet_dev_port_rx_queue (q, port) { - vnet_buffer (&q->buffer_template)->sw_if_index[VLIB_RX] = - port->intf.sw_if_index; + vnet_dev_port_init_if_rt_data (vm, port, &q->if_rt_data, + ifs->primary_interface.sw_if_index); /* poison to catch node not calling runtime update function */ - q->next_index = ~0; - q->interrupt_mode = port->intf.default_is_intr_mode; + q->interrupt_mode = ifs->default_is_intr_mode; vnet_dev_rx_queue_rt_request ( vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 }); } @@ -685,6 +745,8 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port) error: if (rv != VNET_DEV_OK) vnet_dev_port_if_remove (vm, port); + else + a->sw_if_index = ifs->primary_interface.sw_if_index; return rv; } @@ -693,6 +755,7 @@ vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port) { vnet_dev_main_t *dm = &vnet_dev_main; vnet_main_t *vnm = vnet_get_main (); + vnet_dev_port_interfaces_t *ifs = port->interfaces; vnet_dev_port_validate (vm, port); @@ -701,23 +764,22 @@ vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port) if (port->rx_node_assigned) { - vlib_node_rename (vm, port->intf.rx_node_index, "deleted-%u", - port->intf.rx_node_index); - vec_add1 (dm->free_rx_node_indices, port->intf.rx_node_index); + vlib_node_rename (vm, ifs->rx_node_index, "deleted-%u", + ifs->rx_node_index); + vec_add1 (dm->free_rx_node_indices, ifs->rx_node_index); port->rx_node_assigned = 0; } - if (port->interface_created) + if (ifs) { vlib_worker_thread_barrier_sync (vm); - vnet_delete_hw_interface (vnm, port->intf.hw_if_index); + vnet_delete_hw_interface (vnm, ifs->primary_interface.hw_if_index); vlib_worker_thread_barrier_release (vm); - pool_put_index (dm->dev_instances, port->intf.dev_instance); - port->interface_created = 0; + pool_put_index (dm->dev_instances, ifs->primary_interface.dev_instance); + clib_mem_free (port->interfaces); + port->interfaces = 0; } - port->intf = (typeof (port->intf)){}; - if (port->port_ops.deinit) port->port_ops.deinit (vm, port); @@ -734,6 +796,171 @@ vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port) return VNET_DEV_OK; } + +vnet_dev_rv_t +vnet_dev_port_del_sec_if_internal (vlib_main_t *vm, vnet_dev_port_t *port, + vnet_dev_port_interface_t *sif) +{ + vnet_dev_rv_t rv = VNET_DEV_OK; + + if (sif && port->port_ops.add_sec_if) + rv = port->port_ops.add_sec_if (vm, port, sif); + + if (rv != VNET_DEV_OK) + return rv; + + foreach_vnet_dev_port_rx_queue (q, port) + { + vec_foreach_pointer (p, q->sec_if_rt_data) + if (p) + clib_mem_free (p); + vec_free (q->sec_if_rt_data); + } + + if (sif->interface_created) + ethernet_delete_interface (vnet_get_main (), sif->hw_if_index); + + pool_put_index (port->interfaces->secondary_interfaces, sif->index); + vnet_dev_arg_free (&sif->args); + clib_mem_free (sif); + return rv; +} + +vnet_dev_rv_t +vnet_dev_port_add_sec_if (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr) +{ + vnet_dev_main_t *dm = &vnet_dev_main; + vnet_dev_port_sec_if_create_args_t *a = ptr; + vnet_main_t *vnm = vnet_get_main (); + vnet_dev_t *dev = port->dev; + vnet_dev_port_interface_t *sif = 0; + vnet_dev_port_interface_t **sip; + vnet_dev_rv_t rv = VNET_DEV_OK; + + sif = clib_mem_alloc (sizeof (vnet_dev_port_interface_t)); + pool_get (port->interfaces->secondary_interfaces, sip); + *sip = sif; + + *sif = (vnet_dev_port_interface_t){ + .index = sip - port->interfaces->secondary_interfaces, + .args = vec_dup (port->sec_if_args), + }; + + clib_memcpy (sif->name, a->name, sizeof (sif->name)); + + if (sif->args) + { + rv = vnet_dev_arg_parse (vm, dev, sif->args, a->args); + if (rv != VNET_DEV_OK) + return rv; + } + + if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET) + { + vnet_device_class_t *dev_class; + vnet_dev_driver_t *driver; + vnet_sw_interface_t *sw; + vnet_hw_interface_t *hw; + vnet_dev_instance_t *di; + vnet_hw_if_caps_t caps = 0; + + pool_get (dm->dev_instances, di); + sif->dev_instance = di - dm->dev_instances; + di->port = port; + di->sec_if_index = sip - port->interfaces->secondary_interfaces; + + driver = pool_elt_at_index (dm->drivers, dev->driver_index); + + /* hack to provide per-port tx node function */ + dev_class = vnet_get_device_class (vnm, driver->dev_class_index); + dev_class->tx_fn_registrations = port->tx_node.registrations; + dev_class->format_tx_trace = port->tx_node.format_trace; + dev_class->tx_function_error_counters = port->tx_node.error_counters; + dev_class->tx_function_n_errors = port->tx_node.n_error_counters; + + /* create new interface including tx and output nodes */ + sif->hw_if_index = vnet_eth_register_interface ( + vnm, &(vnet_eth_interface_registration_t){ + .address = port->primary_hw_addr.eth_mac, + .max_frame_size = port->max_rx_frame_size, + .dev_class_index = driver->dev_class_index, + .dev_instance = sif->dev_instance, + .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size, + .cb.flag_change = vnet_dev_port_eth_flag_change, + }); + + sw = vnet_get_hw_sw_interface (vnm, sif->hw_if_index); + hw = vnet_get_hw_interface (vnm, sif->hw_if_index); + sif->sw_if_index = sw->sw_if_index; + sif->next_index = + vnet_dev_default_next_index_by_port_type[port->attr.type]; + sif->interface_created = 1; + vnet_dev_port_update_tx_node_runtime (vm, port); + vnet_hw_interface_set_flags ( + vnm, sif->hw_if_index, + port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0); + if (port->speed) + vnet_hw_interface_set_link_speed (vnm, sif->hw_if_index, port->speed); + + sif->tx_node_index = hw->tx_node_index; + + caps |= port->attr.caps.interrupt_mode ? VNET_HW_IF_CAP_INT_MODE : 0; + caps |= port->attr.caps.mac_filter ? VNET_HW_IF_CAP_MAC_FILTER : 0; + caps |= port->attr.tx_offloads.tcp_gso ? VNET_HW_IF_CAP_TCP_GSO : 0; + caps |= port->attr.tx_offloads.ip4_cksum ? VNET_HW_IF_CAP_TX_CKSUM : 0; + + if (caps) + vnet_hw_if_set_caps (vnm, sif->hw_if_index, caps); + } + else + return VNET_DEV_ERR_NOT_SUPPORTED; + + foreach_vnet_dev_port_rx_queue (q, port) + { + vnet_dev_rx_queue_if_rt_data_t *rtd; + vec_validate (q->sec_if_rt_data, sif->index); + + rtd = clib_mem_alloc_aligned (sizeof (vnet_dev_rx_queue_if_rt_data_t), + CLIB_CACHE_LINE_BYTES); + + q->sec_if_rt_data[sif->index] = rtd; + + vnet_dev_port_init_if_rt_data (vm, port, rtd, sif->sw_if_index); + vnet_dev_rx_queue_rt_request ( + vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 }); + } + + if (sif && port->port_ops.add_sec_if) + rv = port->port_ops.add_sec_if (vm, port, sif); + + if (rv != VNET_DEV_OK) + vnet_dev_port_del_sec_if_internal (vm, port, sif); + + return rv; +} + +vnet_dev_rv_t +vnet_dev_port_del_sec_if (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr) +{ + vnet_dev_port_del_sec_if_args_t *a = ptr; + vnet_sw_interface_t *si; + vnet_hw_interface_t *hi; + vnet_dev_instance_t *di; + vnet_main_t *vnm = vnet_get_main (); + + log_debug (port->dev, "%u", a->sw_if_index); + + si = vnet_get_sw_interface_or_null (vnm, a->sw_if_index); + if (!si) + return VNET_DEV_ERR_UNKNOWN_INTERFACE; + + hi = vnet_get_hw_interface (vnm, si->hw_if_index); + di = vnet_dev_get_dev_instance (hi->dev_instance); + + return vnet_dev_port_del_sec_if_internal ( + vm, port, vnet_dev_port_get_sec_if_by_index (port, di->sec_if_index)); +} + void vnet_dev_port_clear_counters (vlib_main_t *vm, vnet_dev_port_t *port) { |