From: Jianbo Liu <jian...@nvidia.com> OVS meters are created in advance and openflow rules refer to them by their unique ID. In order to offload meters, they are mapped to tc police actions with one-to-one relationship, then these actions can be used in tc filter rules by the index. So a police action is created when meter is created, and deleted after meter is deleted.
An id-pool is used to manage all the available police indexes, which are 50000-59999, reserved only for OVS. Signed-off-by: Jianbo Liu <jian...@nvidia.com> Reviewed-by: Roi Dayan <r...@nvidia.com> --- lib/dpif-netlink.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 235 insertions(+), 5 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 34fc04237333..fa68e69efbbe 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -37,6 +37,7 @@ #include "dpif-provider.h" #include "fat-rwlock.h" #include "flow.h" +#include "id-pool.h" #include "netdev-linux.h" #include "netdev-offload.h" #include "netdev-provider.h" @@ -122,6 +123,23 @@ static void dpif_netlink_unixctl_dispatch_mode(struct unixctl_conn *conn, int argc, const char *argv[], void *aux); +#define METER_POLICE_IDS_BASE 50000 +#define METER_POLICE_IDS_MAX 59999 +/* Protects below meter ids pool and hashmaps. */ +static struct ovs_mutex meter_mutex = OVS_MUTEX_INITIALIZER; +static struct id_pool *meter_police_ids; +static struct hmap meter_id_to_police_idx OVS_GUARDED_BY(meter_mutex) + = HMAP_INITIALIZER(&meter_id_to_police_idx); + +struct meter_id_to_police_idx_data { + struct hmap_node meter_id_node; + uint32_t meter_id; + uint32_t police_idx; +}; + +static int +meter_id_lookup(uint32_t meter_id, uint32_t *police_idx); + struct dpif_netlink_flow { /* Generic Netlink header. */ uint8_t cmd; @@ -704,6 +722,7 @@ dpif_netlink_destroy(struct dpif *dpif_) struct dpif_netlink *dpif = dpif_netlink_cast(dpif_); struct dpif_netlink_dp dp; + id_pool_destroy(meter_police_ids); dpif_netlink_dp_init(&dp); dp.cmd = OVS_DP_CMD_DEL; dp.dp_ifindex = dpif->dp_ifindex; @@ -3921,6 +3940,96 @@ dpif_netlink_ct_timeout_policy_dump_done(struct dpif *dpif OVS_UNUSED, * zero. Check for that condition and disable meters on those kernels. */ static bool probe_broken_meters(struct dpif *); +static struct meter_id_to_police_idx_data * +meter_id_find_locked(uint32_t meter_id) + OVS_REQUIRES(meter_mutex) +{ + struct meter_id_to_police_idx_data *data; + size_t hash = hash_int(meter_id, 0); + + HMAP_FOR_EACH_WITH_HASH (data, meter_id_node, hash, + &meter_id_to_police_idx) { + if (data->meter_id == meter_id) { + return data; + } + } + + return NULL; +} + +static int +meter_id_lookup(uint32_t meter_id, uint32_t *police_idx) +{ + struct meter_id_to_police_idx_data *data; + int ret = 0; + + ovs_mutex_lock(&meter_mutex); + data = meter_id_find_locked(meter_id); + if (data) { + *police_idx = data->police_idx; + } else { + ret = ENOENT; + } + ovs_mutex_unlock(&meter_mutex); + + return ret; +} + +static void +meter_id_insert(uint32_t meter_id, uint32_t police_idx) +{ + struct meter_id_to_police_idx_data *data; + + ovs_mutex_lock(&meter_mutex); + data = meter_id_find_locked(meter_id); + if (!data) { + data = xzalloc(sizeof *data); + data->meter_id = meter_id; + data->police_idx = police_idx; + hmap_insert(&meter_id_to_police_idx, &data->meter_id_node, + hash_int(meter_id, 0)); + } else { + VLOG_WARN_RL(&error_rl, + "try to insert meter %d (%d) with different police (%d)", + meter_id, data->police_idx, police_idx); + } + ovs_mutex_unlock(&meter_mutex); +} + +static void +meter_id_remove(uint32_t meter_id) +{ + struct meter_id_to_police_idx_data *data; + + ovs_mutex_lock(&meter_mutex); + data = meter_id_find_locked(meter_id); + if (data) { + hmap_remove(&meter_id_to_police_idx, &data->meter_id_node); + free(data); + } + ovs_mutex_unlock(&meter_mutex); +} + +static bool +meter_alloc_police_index(uint32_t *police_index) +{ + bool ret; + + ovs_mutex_lock(&meter_mutex); + ret = id_pool_alloc_id(meter_police_ids, police_index); + ovs_mutex_unlock(&meter_mutex); + + return ret; +} + +static void +meter_free_police_index(uint32_t police_index) +{ + ovs_mutex_lock(&meter_mutex); + id_pool_free_id(meter_police_ids, police_index); + ovs_mutex_unlock(&meter_mutex); +} + static void dpif_netlink_meter_init(struct dpif_netlink *dpif, struct ofpbuf *buf, void *stub, size_t size, uint32_t command) @@ -4107,14 +4216,75 @@ dpif_netlink_meter_set__(struct dpif *dpif_, ofproto_meter_id meter_id, } static int +dpif_netlink_meter_set_policer(struct dpif *dpif_, ofproto_meter_id meter_id, + struct ofputil_meter_config *config) +{ + uint32_t police_index; + uint32_t rate, burst; + bool add_policer; + int err; + + ovs_assert(config->bands != NULL); + + rate = config->bands[0].rate; + if (config->flags & OFPMF13_BURST) { + burst = config->bands[0].burst_size; + } else { + burst = config->bands[0].rate; + } + + add_policer = (meter_id_lookup(meter_id.uint32, &police_index) == ENOENT); + if (add_policer) { + if (!meter_alloc_police_index(&police_index)) { + VLOG_WARN_RL(&error_rl, "%s: no free police index for meter id %d", + dpif_name(dpif_), meter_id.uint32); + return ENOENT; + } + } + + err = tc_add_policer_action(police_index, + (config->flags & OFPMF13_KBPS) ? rate : 0, + (config->flags & OFPMF13_KBPS) ? burst : 0, + (config->flags & OFPMF13_PKTPS) ? rate : 0, + (config->flags & OFPMF13_PKTPS) ? burst : 0, + !add_policer); + if (err) { + VLOG_WARN_RL(&error_rl, + "%s: failed to %s police %d for meter id %d: %s", + dpif_name(dpif_), add_policer ? "add" : "modify", + police_index, meter_id.uint32, ovs_strerror(err)); + goto err_add_policer; + } + + if (add_policer) { + meter_id_insert(meter_id.uint32, police_index); + } + + return 0; + +err_add_policer: + if (add_policer) { + meter_free_police_index(police_index); + } + return err; +} + +static int dpif_netlink_meter_set(struct dpif *dpif_, ofproto_meter_id meter_id, struct ofputil_meter_config *config) { + int err; + if (probe_broken_meters(dpif_)) { return ENOMEM; } - return dpif_netlink_meter_set__(dpif_, meter_id, config); + err = dpif_netlink_meter_set__(dpif_, meter_id, config); + if (!err && netdev_is_flow_api_enabled()) { + dpif_netlink_meter_set_policer(dpif_, meter_id, config); + } + + return err; } /* Retrieve statistics and/or delete meter 'meter_id'. Statistics are @@ -4202,19 +4372,77 @@ dpif_netlink_meter_get_stats(const struct dpif *dpif_, } static int +dpif_netlink_meter_get_policer(const struct dpif *dpif, + ofproto_meter_id meter_id, + struct ofputil_meter_stats *stats) +{ + uint32_t police_index; + int err = 0; + + if (!meter_id_lookup(meter_id.uint32, &police_index)) { + err = tc_get_policer_action(police_index, stats); + if (err) { + VLOG_WARN_RL(&error_rl, + "%s: failed to get police %d stats for meter %d: %s", + dpif_name(dpif), police_index, meter_id.uint32, + ovs_strerror(err)); + } + } + + return err; +} + +static int dpif_netlink_meter_get(const struct dpif *dpif, ofproto_meter_id meter_id, struct ofputil_meter_stats *stats, uint16_t max_bands) { - return dpif_netlink_meter_get_stats(dpif, meter_id, stats, max_bands, - OVS_METER_CMD_GET); + int err; + + err = dpif_netlink_meter_get_stats(dpif, meter_id, stats, max_bands, + OVS_METER_CMD_GET); + if (!err && netdev_is_flow_api_enabled()) { + dpif_netlink_meter_get_policer(dpif, meter_id, stats); + } + + return err; +} + +static int +dpif_netlink_meter_del_policer(struct dpif *dpif, ofproto_meter_id meter_id, + struct ofputil_meter_stats *stats) +{ + uint32_t police_index; + int err = 0; + + if (!meter_id_lookup(meter_id.uint32, &police_index)) { + err = tc_del_policer_action(police_index, stats); + if (err) { + VLOG_WARN_RL(&error_rl, + "%s: failed to del police %d for meter %d: %s", + dpif_name(dpif), police_index, + meter_id.uint32, ovs_strerror(err)); + } else { + meter_free_police_index(police_index); + } + meter_id_remove(meter_id.uint32); + } + + return err; } static int dpif_netlink_meter_del(struct dpif *dpif, ofproto_meter_id meter_id, struct ofputil_meter_stats *stats, uint16_t max_bands) { - return dpif_netlink_meter_get_stats(dpif, meter_id, stats, max_bands, - OVS_METER_CMD_DEL); + int err; + + err = dpif_netlink_meter_get_stats(dpif, meter_id, stats, + max_bands, OVS_METER_CMD_DEL); + if (!err && netdev_is_flow_api_enabled()) { + dpif_netlink_meter_del_policer(dpif, meter_id, stats); + } + + return err; } static bool @@ -4256,6 +4484,8 @@ probe_broken_meters(struct dpif *dpif) static bool broken_meters = false; if (ovsthread_once_start(&once)) { + meter_police_ids = id_pool_create(METER_POLICE_IDS_BASE, + METER_POLICE_IDS_MAX - METER_POLICE_IDS_BASE + 1); broken_meters = probe_broken_meters__(dpif); ovsthread_once_done(&once); } -- 2.8.0 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev