On 1/12/26 12:20 PM, Eelco Chaudron wrote:
> This patch moved the flow count APIs to the netdev-offload provider.
>
> Acked-by: Eli Britstein <elibr.nvidia.com>
> Signed-off-by: Eelco Chaudron <[email protected]>
> ---
> lib/dpif-netdev.c | 29 +++++-----------------------
> lib/dpif-offload-dpdk.c | 27 ++++++++++++++++++++++++++
> lib/dpif-offload-provider.h | 3 +++
> lib/dpif-offload-tc.c | 1 +
> lib/dpif-offload.c | 20 +++++++++++++++++++
> lib/dpif-offload.h | 1 +
> lib/dpif.c | 23 ----------------------
> lib/dpif.h | 2 --
> lib/netdev-offload-dpdk.c | 13 ++++++-------
> lib/netdev-offload-dpdk.h | 1 +
> lib/netdev-offload-provider.h | 5 -----
> lib/netdev-offload-tc.c | 18 ++++++------------
> lib/netdev-offload-tc.h | 1 +
> lib/netdev-offload.c | 36 -----------------------------------
> lib/netdev-offload.h | 3 ---
> ofproto/ofproto-dpif-upcall.c | 9 +++------
> 16 files changed, 74 insertions(+), 118 deletions(-)
>
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index 79b05bc0d..82df85823 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -4762,11 +4762,8 @@ dpif_netdev_offload_stats_get(struct dpif *dpif,
> [DP_NETDEV_HW_OFFLOADS_STATS_LAT_EMA_STDDEV] =
> { " Exponential Latency stddev (us)", 0 },
> };
> - struct dp_netdev *dp = get_dp_netdev(dpif);
> - struct dp_netdev_port *port;
> +
> unsigned int nb_thread;
> - uint64_t *port_nb_offloads;
> - uint64_t *nb_offloads;
> unsigned int tid;
> size_t i;
>
> @@ -4783,29 +4780,11 @@ dpif_netdev_offload_stats_get(struct dpif *dpif,
> stats->size = ARRAY_SIZE(hwol_stats) * (nb_thread + 1);
> stats->counters = xcalloc(stats->size, sizeof *stats->counters);
>
> - nb_offloads = xcalloc(nb_thread, sizeof *nb_offloads);
> - port_nb_offloads = xcalloc(nb_thread, sizeof *port_nb_offloads);
> -
> - ovs_rwlock_rdlock(&dp->port_rwlock);
> - HMAP_FOR_EACH (port, node, &dp->ports) {
> - memset(port_nb_offloads, 0, nb_thread * sizeof *port_nb_offloads);
> - /* Do not abort on read error from a port, just report 0. */
> - if (!netdev_flow_get_n_flows(port->netdev, port_nb_offloads)) {
> - for (i = 0; i < nb_thread; i++) {
> - nb_offloads[i] += port_nb_offloads[i];
> - }
> - }
> - }
> - ovs_rwlock_unlock(&dp->port_rwlock);
> -
> - free(port_nb_offloads);
> -
> for (tid = 0; tid < nb_thread; tid++) {
> uint64_t counts[ARRAY_SIZE(hwol_stats)];
> size_t idx = ((tid + 1) * ARRAY_SIZE(hwol_stats));
>
> memset(counts, 0, sizeof counts);
> - counts[DP_NETDEV_HW_OFFLOADS_STATS_INSERTED] = nb_offloads[tid];
> if (dp_offload_threads != NULL) {
> atomic_read_relaxed(&dp_offload_threads[tid].enqueued_item,
>
> &counts[DP_NETDEV_HW_OFFLOADS_STATS_ENQUEUED]);
> @@ -4830,14 +4809,16 @@ dpif_netdev_offload_stats_get(struct dpif *dpif,
> }
> }
>
> - free(nb_offloads);
> -
> /* Do an average of the average for the aggregate. */
> hwol_stats[DP_NETDEV_HW_OFFLOADS_STATS_LAT_CMA_MEAN].total /= nb_thread;
> hwol_stats[DP_NETDEV_HW_OFFLOADS_STATS_LAT_CMA_STDDEV].total /=
> nb_thread;
> hwol_stats[DP_NETDEV_HW_OFFLOADS_STATS_LAT_EMA_MEAN].total /= nb_thread;
> hwol_stats[DP_NETDEV_HW_OFFLOADS_STATS_LAT_EMA_STDDEV].total /=
> nb_thread;
>
> + /* Get the total offload count. */
> + hwol_stats[DP_NETDEV_HW_OFFLOADS_STATS_INSERTED].total =
> + dpif_offload_flow_get_n_offloaded(dpif);
> +
> for (i = 0; i < ARRAY_SIZE(hwol_stats); i++) {
> snprintf(stats->counters[i].name, sizeof(stats->counters[i].name),
> " Total %s", hwol_stats[i].name);
> diff --git a/lib/dpif-offload-dpdk.c b/lib/dpif-offload-dpdk.c
> index ed0b5bec9..2ded4111d 100644
> --- a/lib/dpif-offload-dpdk.c
> +++ b/lib/dpif-offload-dpdk.c
> @@ -255,6 +255,32 @@ dpif_offload_dpdk_can_offload(struct dpif_offload
> *offload OVS_UNUSED,
> return netdev_dpdk_flow_api_supported(netdev, true);
> }
>
> +static bool
> +dpif_offload_dpdk_get_n_offloaded_cb(
> + struct dpif_offload_port_mgr_port *port, void *aux)
> +{
> + uint64_t *total = aux;
> +
> + *total += netdev_offload_dpdk_flow_get_n_offloaded(port->netdev);
> + return false;
> +}
> +
> +static uint64_t
> +dpif_offload_dpdk_get_n_offloaded(const struct dpif_offload *offload_)
> +{
> + struct dpif_offload_dpdk *offload = dpif_offload_dpdk_cast(offload_);
> + uint64_t total = 0;
> +
> + if (!dpif_offload_is_offload_enabled()) {
> + return 0;
> + }
> +
> + dpif_offload_port_mgr_traverse_ports(
> + offload->port_mgr, dpif_offload_dpdk_get_n_offloaded_cb, &total);
> +
> + return total;
> +}
> +
> static int
> dpif_offload_dpdk_netdev_flow_flush(const struct dpif_offload *offload
> OVS_UNUSED, struct netdev *netdev)
> @@ -274,6 +300,7 @@ struct dpif_offload_class dpif_offload_dpdk_class = {
> .can_offload = dpif_offload_dpdk_can_offload,
> .port_add = dpif_offload_dpdk_port_add,
> .port_del = dpif_offload_dpdk_port_del,
> + .flow_get_n_offloaded = dpif_offload_dpdk_get_n_offloaded,
> .netdev_flow_flush = dpif_offload_dpdk_netdev_flow_flush,
> };
>
> diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
> index f49443758..5e403894e 100644
> --- a/lib/dpif-offload-provider.h
> +++ b/lib/dpif-offload-provider.h
> @@ -132,6 +132,9 @@ struct dpif_offload_class {
> * successful, otherwise returns a positive errno value. */
> int (*flow_flush)(const struct dpif_offload *);
>
> + /* Returns the number of flows offloaded by the offload provider. */
> + uint64_t (*flow_get_n_offloaded)(const struct dpif_offload *);
The name is a little strange for a class member. Should we maybe call
it just .get_n_flows() or .flow_count() ? Since we're asking the
offload provider and not the general dpif implementation it's expected
that all the flows in there are offloaded.
> +
> /* Adds or modifies the meter in 'dpif_offload' with the given 'meter_id'
> * and the configuration in 'config'.
> *
> diff --git a/lib/dpif-offload-tc.c b/lib/dpif-offload-tc.c
> index 70f4f3c97..9e8da207c 100644
> --- a/lib/dpif-offload-tc.c
> +++ b/lib/dpif-offload-tc.c
> @@ -294,6 +294,7 @@ struct dpif_offload_class dpif_offload_tc_class = {
> .port_add = dpif_offload_tc_port_add,
> .port_del = dpif_offload_tc_port_del,
> .flow_flush = dpif_offload_tc_flow_flush,
> + .flow_get_n_offloaded = dpif_offload_tc_flow_get_n_offloaded,
> .meter_set = dpif_offload_tc_meter_set,
> .meter_get = dpif_offload_tc_meter_get,
> .meter_del = dpif_offload_tc_meter_del,
> diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
> index 357a7fe62..1c5494d8e 100644
> --- a/lib/dpif-offload.c
> +++ b/lib/dpif-offload.c
> @@ -742,6 +742,26 @@ dpif_offload_flow_flush(struct dpif *dpif)
> }
> }
>
> +uint64_t
> +dpif_offload_flow_get_n_offloaded(const struct dpif *dpif)
> +{
> + struct dp_offload *dp_offload = dpif_offload_get_dp_offload(dpif);
> + const struct dpif_offload *offload;
> + uint64_t flow_count = 0;
> +
> + if (!dp_offload || !dpif_offload_is_offload_enabled()) {
> + return 0;
> + }
> +
> + LIST_FOR_EACH (offload, dpif_list_node, &dp_offload->offload_providers) {
> + if (offload->class->flow_get_n_offloaded) {
> + flow_count += offload->class->flow_get_n_offloaded(offload);
> + }
> + }
> +
> + return flow_count;
> +}
> +
> void
> dpif_offload_meter_set(const struct dpif *dpif, ofproto_meter_id meter_id,
> struct ofputil_meter_config *config)
> diff --git a/lib/dpif-offload.h b/lib/dpif-offload.h
> index 0485b7e98..fb7edf269 100644
> --- a/lib/dpif-offload.h
> +++ b/lib/dpif-offload.h
> @@ -51,6 +51,7 @@ void dpif_offload_dump_start(struct dpif_offload_dump *,
> const struct dpif *);
> bool dpif_offload_dump_next(struct dpif_offload_dump *,
> struct dpif_offload **);
> int dpif_offload_dump_done(struct dpif_offload_dump *);
> +uint64_t dpif_offload_flow_get_n_offloaded(const struct dpif *);
> void dpif_offload_meter_set(const struct dpif *dpif, ofproto_meter_id
> meter_id,
> struct ofputil_meter_config *);
> void dpif_offload_meter_get(const struct dpif *dpif, ofproto_meter_id
> meter_id,
> diff --git a/lib/dpif.c b/lib/dpif.c
> index 12dbc9cd1..61cc68c8e 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -2089,29 +2089,6 @@ dpif_bond_stats_get(struct dpif *dpif, uint32_t
> bond_id,
> : EOPNOTSUPP;
> }
>
> -int
> -dpif_get_n_offloaded_flows(struct dpif *dpif, uint64_t *n_flows)
> -{
> - const char *dpif_type_str = dpif_normalize_type(dpif_type(dpif));
> - struct dpif_port_dump port_dump;
> - struct dpif_port dpif_port;
> - int ret, n_devs = 0;
> - uint64_t nflows;
> -
> - *n_flows = 0;
> - DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
> - ret = netdev_ports_get_n_flows(dpif_type_str, dpif_port.port_no,
> - &nflows);
> - if (!ret) {
> - *n_flows += nflows;
> - } else if (ret == EOPNOTSUPP) {
> - continue;
> - }
> - n_devs++;
> - }
> - return n_devs ? 0 : EOPNOTSUPP;
> -}
> -
> int
> dpif_cache_get_supported_levels(struct dpif *dpif, uint32_t *levels)
> {
> diff --git a/lib/dpif.h b/lib/dpif.h
> index 0b685d8df..7fd3c939c 100644
> --- a/lib/dpif.h
> +++ b/lib/dpif.h
> @@ -441,8 +441,6 @@ int dpif_get_dp_stats(const struct dpif *, struct
> dpif_dp_stats *);
>
> int dpif_set_features(struct dpif *, uint32_t new_features);
>
> -int dpif_get_n_offloaded_flows(struct dpif *dpif, uint64_t *n_flows);
> -
>
> /* Port operations. */
>
> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
> index 072103596..d1781d8e4 100644
> --- a/lib/netdev-offload-dpdk.c
> +++ b/lib/netdev-offload-dpdk.c
> @@ -2776,24 +2776,24 @@ close_vport_netdev:
> return ret;
> }
>
> -static int
> -netdev_offload_dpdk_get_n_flows(struct netdev *netdev,
> - uint64_t *n_flows)
> +uint64_t
> +netdev_offload_dpdk_flow_get_n_offloaded(struct netdev *netdev)
> {
> struct netdev_offload_dpdk_data *data;
> + uint64_t total = 0;
> unsigned int tid;
>
> data = (struct netdev_offload_dpdk_data *)
> ovsrcu_get(void *, &netdev->hw_info.offload_data);
> if (!data) {
> - return -1;
> + return 0;
> }
>
> for (tid = 0; tid < netdev_offload_thread_nb(); tid++) {
> - n_flows[tid] = data->rte_flow_counters[tid];
> + total += data->rte_flow_counters[tid];
> }
>
> - return 0;
> + return total;
> }
>
> const struct netdev_flow_api netdev_offload_dpdk = {
> @@ -2804,5 +2804,4 @@ const struct netdev_flow_api netdev_offload_dpdk = {
> .uninit_flow_api = netdev_offload_dpdk_uninit_flow_api,
> .flow_get = netdev_offload_dpdk_flow_get,
> .hw_miss_packet_recover = netdev_offload_dpdk_hw_miss_packet_recover,
> - .flow_get_n_flows = netdev_offload_dpdk_get_n_flows,
> };
> diff --git a/lib/netdev-offload-dpdk.h b/lib/netdev-offload-dpdk.h
> index feded432f..d5061b40c 100644
> --- a/lib/netdev-offload-dpdk.h
> +++ b/lib/netdev-offload-dpdk.h
> @@ -23,5 +23,6 @@ struct netdev;
> /* Netdev-specific offload functions. These should only be used by the
> * associated dpif offload provider. */
> int netdev_offload_dpdk_flow_flush(struct netdev *);
> +uint64_t netdev_offload_dpdk_flow_get_n_offloaded(struct netdev *);
>
> #endif /* NETDEV_OFFLOAD_DPDK_H */
> diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h
> index 07068bd82..898df8333 100644
> --- a/lib/netdev-offload-provider.h
> +++ b/lib/netdev-offload-provider.h
> @@ -80,11 +80,6 @@ struct netdev_flow_api {
> int (*flow_del)(struct netdev *, const ovs_u128 *ufid,
> struct dpif_flow_stats *);
>
> - /* Get the number of flows offloaded to netdev.
> - * 'n_flows' is an array of counters, one per offload thread.
> - * Return 0 if successful, otherwise returns a positive errno value. */
> - int (*flow_get_n_flows)(struct netdev *, uint64_t *n_flows);
> -
> /* Recover the packet state (contents and data) for continued processing
> * in software.
> * Return 0 if successful, otherwise returns a positive errno value and
> diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
> index 46de23014..af9a10356 100644
> --- a/lib/netdev-offload-tc.c
> +++ b/lib/netdev-offload-tc.c
> @@ -2794,22 +2794,17 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
> return del_filter_and_ufid_mapping(&id, ufid, stats);
> }
>
> -static int
> -netdev_tc_get_n_flows(struct netdev *netdev, uint64_t *n_flows)
> +uint64_t
> +dpif_offload_tc_flow_get_n_offloaded(const struct dpif_offload *offload
> + OVS_UNUSED)
> {
> - struct ufid_tc_data *data;
> - uint64_t total = 0;
> + uint64_t total;
>
> ovs_mutex_lock(&ufid_lock);
> - HMAP_FOR_EACH (data, tc_to_ufid_node, &tc_to_ufid) {
> - if (data->netdev == netdev) {
> - total++;
> - }
> - }
> + total = hmap_count(&tc_to_ufid);
> ovs_mutex_unlock(&ufid_lock);
>
> - *n_flows = total;
> - return 0;
> + return total;
> }
>
> static void
> @@ -3453,6 +3448,5 @@ const struct netdev_flow_api netdev_offload_tc = {
> .flow_put = netdev_tc_flow_put,
> .flow_get = netdev_tc_flow_get,
> .flow_del = netdev_tc_flow_del,
> - .flow_get_n_flows = netdev_tc_get_n_flows,
> .init_flow_api = netdev_tc_init_flow_api,
> };
> diff --git a/lib/netdev-offload-tc.h b/lib/netdev-offload-tc.h
> index a6b000852..5002ab00b 100644
> --- a/lib/netdev-offload-tc.h
> +++ b/lib/netdev-offload-tc.h
> @@ -31,5 +31,6 @@ int dpif_offload_tc_meter_get(const struct dpif_offload *,
> ofproto_meter_id,
> struct ofputil_meter_stats *);
> int dpif_offload_tc_meter_del(const struct dpif_offload *, ofproto_meter_id,
> struct ofputil_meter_stats *);
> +uint64_t dpif_offload_tc_flow_get_n_offloaded(const struct dpif_offload *);
>
> #endif /* NETDEV_OFFLOAD_TC_H */
> diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c
> index abbb930be..0c4209290 100644
> --- a/lib/netdev-offload.c
> +++ b/lib/netdev-offload.c
> @@ -309,17 +309,6 @@ netdev_flow_del(struct netdev *netdev, const ovs_u128
> *ufid,
> : EOPNOTSUPP;
> }
>
> -int
> -netdev_flow_get_n_flows(struct netdev *netdev, uint64_t *n_flows)
> -{
> - const struct netdev_flow_api *flow_api =
> - ovsrcu_get(const struct netdev_flow_api *, &netdev->flow_api);
> -
> - return (flow_api && flow_api->flow_get_n_flows)
> - ? flow_api->flow_get_n_flows(netdev, n_flows)
> - : EOPNOTSUPP;
> -}
> -
> int
> netdev_init_flow_api(struct netdev *netdev)
> {
> @@ -717,31 +706,6 @@ netdev_ports_remove(odp_port_t port_no, const char
> *dpif_type)
> return ret;
> }
>
> -int
> -netdev_ports_get_n_flows(const char *dpif_type, odp_port_t port_no,
> - uint64_t *n_flows)
> -{
> - struct port_to_netdev_data *data;
> - int ret = EOPNOTSUPP;
> -
> - ovs_rwlock_rdlock(&port_to_netdev_rwlock);
> - data = netdev_ports_lookup(port_no, dpif_type);
> - if (data) {
> - uint64_t thread_n_flows[MAX_OFFLOAD_THREAD_NB] = {0};
> - unsigned int tid;
> -
> - ret = netdev_flow_get_n_flows(data->netdev, thread_n_flows);
> - *n_flows = 0;
> - if (!ret) {
> - for (tid = 0; tid < netdev_offload_thread_nb(); tid++) {
> - *n_flows += thread_n_flows[tid];
> - }
> - }
> - }
> - ovs_rwlock_unlock(&port_to_netdev_rwlock);
> - return ret;
> -}
> -
> odp_port_t
> netdev_ifindex_to_odp_port(int ifindex)
> {
> diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h
> index 8552b6e0b..2b32179ec 100644
> --- a/lib/netdev-offload.h
> +++ b/lib/netdev-offload.h
> @@ -123,7 +123,6 @@ int netdev_get_hw_info(struct netdev *, int);
> void netdev_set_hw_info(struct netdev *, int, int);
> bool netdev_any_oor(void);
> void netdev_set_flow_api_enabled(const struct smap *ovs_other_config);
> -int netdev_flow_get_n_flows(struct netdev *netdev, uint64_t *n_flows);
>
> struct dpif_port;
> int netdev_ports_insert(struct netdev *, struct dpif_port *);
> @@ -151,8 +150,6 @@ int netdev_ports_flow_get(const char *dpif_type, struct
> match *match,
> struct dpif_flow_stats *stats,
> struct dpif_flow_attrs *attrs,
> struct ofpbuf *buf);
> -int netdev_ports_get_n_flows(const char *dpif_type,
> - odp_port_t port_no, uint64_t *n_flows);
>
> #ifdef __cplusplus
> }
> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
> index 4273b3ea6..3fa96b673 100644
> --- a/ofproto/ofproto-dpif-upcall.c
> +++ b/ofproto/ofproto-dpif-upcall.c
> @@ -830,11 +830,7 @@ udpif_get_n_flows(struct udpif *udpif)
> if (!dpif_synced_dp_layers(udpif->dpif)) {
> /* If the dpif layer does not sync the flows, we need to include
> * the hardware offloaded flows separately. */
> - uint64_t hw_flows;
> -
> - if (!dpif_get_n_offloaded_flows(udpif->dpif, &hw_flows)) {
> - flow_count += hw_flows;
> - }
> + flow_count += dpif_offload_flow_get_n_offloaded(udpif->dpif);
> }
>
> atomic_store_relaxed(&udpif->n_flows, flow_count);
> @@ -3171,7 +3167,8 @@ upcall_unixctl_show(struct unixctl_conn *conn, int argc
> OVS_UNUSED,
> ds_put_format(&ds, " flows : (current %lu)"
> " (avg %u) (max %u) (limit %u)\n", udpif_get_n_flows(udpif),
> udpif->avg_n_flows, udpif->max_n_flows, flow_limit);
> - if (!dpif_get_n_offloaded_flows(udpif->dpif, &n_offloaded_flows)) {
> + n_offloaded_flows = dpif_offload_flow_get_n_offloaded(udpif->dpif);
> + if (n_offloaded_flows) {
> ds_put_format(&ds, " offloaded flows : %"PRIu64"\n",
> n_offloaded_flows);
> }
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev