@@ -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
------------
@@ -98,27 +98,42 @@ struct netdev_flow_api {
* and the configuration in 'config'. On failure, a non-zero error code is
* returned.
*
+ * If the datapath is netdev, the api needs the param struct netdev *,
+ * If the datapath is system, the param struct netdev* is unused and
+ * should be NULL.
+ *
* The meter id specified through 'config->meter_id' is ignored. */
- int (*meter_set)(ofproto_meter_id meter_id,
+ int (*meter_set)(struct netdev *,
+ ofproto_meter_id meter_id,
struct ofputil_meter_config *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.
*
+ * If the datapath is netdev, the api needs the param struct netdev *,
+ * If the datapath is system, the param struct netdev* is unused and
+ * should be NULL.
+ *
* 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 (*meter_get)(ofproto_meter_id meter_id,
+ int (*meter_get)(struct netdev *,
+ ofproto_meter_id meter_id,
struct ofputil_meter_stats *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.
*
+ * If the datapath is netdev, the api needs the param struct netdev *,
+ * If the datapath is system, the param struct netdev* is unused and
+ * should be NULL.
+ *
* 'stats' may be passed in as NULL if no stats are needed, See the above
* function for additional details on the 'stats' usage. */
- int (*meter_del)(ofproto_meter_id meter_id,
+ int (*meter_del)(struct netdev *,
+ ofproto_meter_id meter_id,
struct ofputil_meter_stats *stats);
/* Initializies the netdev flow api.
@@ -2892,7 +2892,8 @@ meter_free_police_index(uint32_t police_index)
}
static int
-meter_tc_set_policer(ofproto_meter_id meter_id,
+meter_tc_set_policer(struct netdev *netdev OVS_UNUSED,
+ ofproto_meter_id meter_id,
struct ofputil_meter_config *config)
{
uint32_t police_index;
@@ -2946,7 +2947,8 @@ meter_tc_set_policer(ofproto_meter_id meter_id,
}
static int
-meter_tc_get_policer(ofproto_meter_id meter_id,
+meter_tc_get_policer(struct netdev *netdev OVS_UNUSED,
+ ofproto_meter_id meter_id,
struct ofputil_meter_stats *stats)
{
uint32_t police_index;
@@ -2965,7 +2967,8 @@ meter_tc_get_policer(ofproto_meter_id meter_id,
}
static int
-meter_tc_del_policer(ofproto_meter_id meter_id,
+meter_tc_del_policer(struct netdev *netdev OVS_UNUSED,
+ ofproto_meter_id meter_id,
struct ofputil_meter_stats *stats)
{
uint32_t police_index;
@@ -206,7 +206,7 @@ meter_offload_set(ofproto_meter_id meter_id,
CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
if (rfa->flow_api->meter_set) {
- int ret = rfa->flow_api->meter_set(meter_id, config);
+ int ret = rfa->flow_api->meter_set(NULL, 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,
@@ -225,7 +225,7 @@ meter_offload_get(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats)
CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
if (rfa->flow_api->meter_get) {
- int ret = rfa->flow_api->meter_get(meter_id, stats);
+ int ret = rfa->flow_api->meter_get(NULL, 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,
@@ -244,7 +244,7 @@ meter_offload_del(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats)
CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
if (rfa->flow_api->meter_del) {
- int ret = rfa->flow_api->meter_del(meter_id, stats);
+ int ret = rfa->flow_api->meter_del(NULL, 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,
@@ -895,3 +895,132 @@ netdev_set_flow_api_enabled(const struct smap *ovs_other_config)
}
}
}
+struct dpdk_meter_aux {
+ struct ofputil_meter_config *config;
+ struct ofputil_meter_stats *stats;
+ ofproto_meter_id meter_id;
+ odp_port_t odp_port;
+};
+
+static bool
+dpdk_meter_set_cb(struct netdev *netdev,
+ odp_port_t odp_port,
+ void *aux_)
+{
+ struct netdev_registered_flow_api *rfa;
+ struct dpdk_meter_aux *aux = aux_;
+ ofproto_meter_id meter_id;
+ int ret;
+
+ meter_id = aux->meter_id;
+ CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
+ if (rfa->flow_api->meter_set) {
+ ret = rfa->flow_api->meter_set(netdev, meter_id, aux->config);
+ if (ret) {
+ VLOG_DBG_RL(&rl, "Failed setting meter %u for flow api %s with"
+ " port number %u, error %d", meter_id.uint32,
+ rfa->flow_api->type, odp_port, ret);
+ }
+ }
+ }
+
+ return 0;
+}
+
+void
+dpdk_meter_offload_set(const char *dpif_type,
+ ofproto_meter_id meter_id,
+ struct ofputil_meter_config *config)
+{
+ struct dpdk_meter_aux aux = {
+ .meter_id = meter_id,
+ .config = config,
+ };
+ netdev_ports_traverse(dpif_type, dpdk_meter_set_cb, &aux);
+}
+
+static bool
+dpdk_meter_get_cb(struct netdev *netdev,
+ odp_port_t odp_port,
+ void *aux_)
+{
+ struct ofputil_meter_stats *stats, offload_stats;
+ struct netdev_registered_flow_api *rfa;
+ struct dpdk_meter_aux *aux = aux_;
+ ofproto_meter_id meter_id;
+ int ret;
+
+ memset(&offload_stats, 0, sizeof(struct ofputil_meter_stats));
+ meter_id = aux->meter_id;
+ stats = aux->stats;
+ CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
+ if (rfa->flow_api->meter_get) {
+ ret = rfa->flow_api->meter_get(netdev, meter_id, &offload_stats);
+ if (ret) {
+ VLOG_DBG_RL(&rl, "Failed getting meter %u for flow api %s with"
+ " port number %u, error %d", meter_id.uint32,
+ rfa->flow_api->type, odp_port, ret);
+ }
+ }
+ }
+
+ if (!offload_stats.byte_in_count && !offload_stats.packet_in_count) {
+ return 0;
+ }
+ stats->byte_in_count += offload_stats.byte_in_count;
+ stats->packet_in_count += offload_stats.packet_in_count;
+
+ return 0;
+}
+
+void
+dpdk_meter_offload_get(const char *dpif_type,
+ ofproto_meter_id meter_id,
+ struct ofputil_meter_stats *stats)
+{
+ struct dpdk_meter_aux aux = {
+ .meter_id = meter_id,
+ .stats = stats,
+ };
+ netdev_ports_traverse(dpif_type, dpdk_meter_get_cb, &aux);
+}
+
+static bool
+dpdk_meter_del_cb(struct netdev *netdev,
+ odp_port_t odp_port,
+ void *aux_)
+{
+ struct netdev_registered_flow_api *rfa;
+ struct ofputil_meter_stats *stats;
+ struct dpdk_meter_aux *aux = aux_;
+ ofproto_meter_id meter_id;
+ int ret;
+
+ meter_id = aux->meter_id;
+ stats = aux->stats;
+ CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
+ if (rfa->flow_api->meter_del) {
+ ret = rfa->flow_api->meter_del(netdev, meter_id, stats);
+ if (ret) {
+ VLOG_DBG_RL(&rl, "Failed deleting meter %u for flow api %s"
+ " with port number %u, error %d", meter_id.uint32,
+ rfa->flow_api->type, odp_port, ret);
+ }
+ }
+ }
+
+ return 0;
+}
+
+void
+dpdk_meter_offload_del(const char *dpif_type,
+ ofproto_meter_id meter_id,
+ struct ofputil_meter_stats *stats)
+{
+ struct dpdk_meter_aux aux = {
+ .meter_id = meter_id,
+ .stats = stats,
+ };
+
+ netdev_ports_traverse(dpif_type, dpdk_meter_del_cb, &aux);
+}
@@ -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
}