From: Peng Zhang <[email protected]> Add API to offload DPDK meter to HW, and the corresponding functions to call the DPDK meter callbacks from all the registered flow API providers. The interfaces are like those related to DPDK meter in dpif_class, in order to pass necessary info to HW.
Signed-off-by: Peng Zhang <[email protected]> Signed-off-by: Jin Liu <[email protected]> Signed-off-by: Simon Horman <[email protected]> --- Documentation/howto/dpdk.rst | 5 +- lib/netdev-offload-provider.h | 30 +++++++++++ lib/netdev-offload.c | 99 +++++++++++++++++++++++++++++++++++ lib/netdev-offload.h | 9 ++++ 4 files changed, 141 insertions(+), 2 deletions(-) diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst index 04609b20bd21..02fc568770ee 100644 --- a/Documentation/howto/dpdk.rst +++ b/Documentation/howto/dpdk.rst @@ -401,10 +401,11 @@ Supported actions for hardware offload are: - Modification of IPv6 (set_field:<ADDR>->ipv6_src/ipv6_dst/mod_nw_ttl). - Clone/output (tnl_push and output) for encapsulating over a tunnel. - Tunnel pop, for packets received on physical ports. +- Meter. .. note:: - Tunnel offloads are experimental APIs in DPDK. In order to enable it, - compile with -DALLOW_EXPERIMENTAL_API. + Tunnel offloads and Meter offloads are experimental APIs in DPDK. To enable + these features, compile with -DALLOW_EXPERIMENTAL_API. Multiprocess ------------ diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h index 9108856d18d1..7ecbb8d026f1 100644 --- a/lib/netdev-offload-provider.h +++ b/lib/netdev-offload-provider.h @@ -102,6 +102,16 @@ struct netdev_flow_api { int (*meter_set)(ofproto_meter_id meter_id, struct ofputil_meter_config *config); + /* Offloads or modifies the offloaded meter on the netdev with the given + * 'meter_id' and the configuration in 'config'. On failure, a non-zero + * error code is returned. + * + * The meter id specified through 'config->meter_id' is converted as an + * internal meter id. */ + int (*dpdk_meter_set)(struct netdev *, + ofproto_meter_id meter_id, + struct ofputil_meter_config *); + /* Queries HW for meter stats with the given 'meter_id'. Store the stats * of dropped packets to band 0. On failure, a non-zero error code is * returned. @@ -113,6 +123,18 @@ struct netdev_flow_api { int (*meter_get)(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats); + /* Queries netdev for meter stats with the given 'meter_id'. Store the + * stats of dropped packets to band 0. On failure, a non-zero error code + * is returned. + * + * Note that the 'stats' structure is already initialized, and only the + * available statistics should be incremented, not replaced. Those fields + * are packet_in_count, byte_in_count and band[]->byte_count and + * band[]->packet_count. */ + int (*dpdk_meter_get)(struct netdev *, + ofproto_meter_id meter_id, + struct ofputil_meter_stats *); + /* Removes meter 'meter_id' from HW. Store the stats of dropped packets to * band 0. On failure, a non-zero error code is returned. * @@ -121,6 +143,14 @@ struct netdev_flow_api { int (*meter_del)(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats); + /* Removes meter 'meter_id' from netdev. Store the stats of dropped packets + * to band 0. On failure, a non-zero error code is returned. + * + * If del success, 'stats' will be set zero. */ + int (*dpdk_meter_del)(struct netdev *, + ofproto_meter_id meter_id, + struct ofputil_meter_stats *stats); + /* Initializies the netdev flow api. * Return 0 if successful, otherwise returns a positive errno value. */ int (*init_flow_api)(struct netdev *); diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c index 4592262bd34e..44cab0c4ee79 100644 --- a/lib/netdev-offload.c +++ b/lib/netdev-offload.c @@ -895,3 +895,102 @@ netdev_set_flow_api_enabled(const struct smap *ovs_other_config) } } } + +void +dpdk_meter_offload_set(const char *dpif_type, + ofproto_meter_id meter_id, + struct ofputil_meter_config *config) +{ + struct netdev_registered_flow_api *rfa; + struct port_to_netdev_data *data; + struct netdev *dev; + int ret; + + ovs_rwlock_rdlock(&netdev_hmap_rwlock); + HMAP_FOR_EACH (data, portno_node, &port_to_netdev) { + dev = data->netdev; + if (netdev_get_dpif_type(dev) == dpif_type) { + /* Offload APIs could fail, for example, because the offload is not + * supported. This is fine, as the offload API should take care of + * this. */ + CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) { + if (rfa->flow_api->dpdk_meter_set) { + ret = rfa->flow_api->dpdk_meter_set(dev, meter_id, config); + if (ret) { + VLOG_DBG_RL(&rl, "Failed setting meter %u for flow api" + " %s, error %d", meter_id.uint32, + rfa->flow_api->type, ret); + } + } + } + } + } + ovs_rwlock_unlock(&netdev_hmap_rwlock); +} + +void +dpdk_meter_offload_get(const char *dpif_type, + ofproto_meter_id meter_id, + struct ofputil_meter_stats *stats) +{ + struct netdev_registered_flow_api *rfa; + struct ofputil_meter_stats offload_stats; + struct port_to_netdev_data *data; + struct netdev *dev; + int ret; + + ovs_rwlock_rdlock(&netdev_hmap_rwlock); + HMAP_FOR_EACH (data, portno_node, &port_to_netdev) { + memset(&offload_stats, 0, sizeof(struct ofputil_meter_stats)); + dev = data->netdev; + if (netdev_get_dpif_type(dev) == dpif_type) { + CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) { + if (rfa->flow_api->dpdk_meter_get) { + ret = rfa->flow_api->dpdk_meter_get(dev, meter_id, stats); + if (ret) { + VLOG_DBG_RL(&rl, "Failed getting meter %u for flow " + "api %s, error %d", meter_id.uint32, + rfa->flow_api->type, ret); + } + } + } + + if (!offload_stats.byte_in_count && + !offload_stats.packet_in_count) { + continue; + } + stats->byte_in_count += offload_stats.byte_in_count; + stats->packet_in_count += offload_stats.packet_in_count; + } + } + ovs_rwlock_unlock(&netdev_hmap_rwlock); +} + +void +dpdk_meter_offload_del(const char *dpif_type, + ofproto_meter_id meter_id, + struct ofputil_meter_stats *stats) +{ + struct netdev_registered_flow_api *rfa; + struct port_to_netdev_data *data; + struct netdev *dev; + int ret; + + ovs_rwlock_rdlock(&netdev_hmap_rwlock); + HMAP_FOR_EACH (data, portno_node, &port_to_netdev) { + dev = data->netdev; + if (netdev_get_dpif_type(dev) == dpif_type) { + CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) { + if (rfa->flow_api->dpdk_meter_del) { + ret = rfa->flow_api->dpdk_meter_del(dev, meter_id, stats); + if (ret) { + VLOG_DBG_RL(&rl, "Failed deleting meter %u for flow " + "api %s, error %d", meter_id.uint32, + rfa->flow_api->type, ret); + } + } + } + } + } + ovs_rwlock_unlock(&netdev_hmap_rwlock); +} diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h index edc843cd99a3..e53f70a277b3 100644 --- a/lib/netdev-offload.h +++ b/lib/netdev-offload.h @@ -161,6 +161,15 @@ int netdev_ports_get_n_flows(const char *dpif_type, void meter_offload_set(ofproto_meter_id, struct ofputil_meter_config *); int meter_offload_get(ofproto_meter_id, struct ofputil_meter_stats *); int meter_offload_del(ofproto_meter_id, struct ofputil_meter_stats *); +void dpdk_meter_offload_set(const char *dpif_type, + ofproto_meter_id meter_id, + struct ofputil_meter_config *config); +void dpdk_meter_offload_del(const char *dpif_type, + ofproto_meter_id meter_id_, + struct ofputil_meter_stats *stats); +void dpdk_meter_offload_get(const char *dpif_type, + ofproto_meter_id meter_id_, + struct ofputil_meter_stats *stats); #ifdef __cplusplus } -- 2.30.2 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
