From: Peng Zhang <[email protected]> Add support of DPDK meter action logic. With flow add/destroy from the HW, add/del the meter in the HW.
Signed-off-by: Peng Zhang <[email protected]> Signed-off-by: Jin Liu <[email protected]> Co-authored-by: Jin Liu <[email protected]> Signed-off-by: Simon Horman <[email protected]> --- lib/netdev-offload-dpdk.c | 131 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 6 deletions(-) diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c index 9d010d6003f3..d9b8329f261d 100644 --- a/lib/netdev-offload-dpdk.c +++ b/lib/netdev-offload-dpdk.c @@ -35,6 +35,8 @@ #include "packets.h" #include "uuid.h" +#define MAX_METERS 1 << 18 + VLOG_DEFINE_THIS_MODULE(netdev_offload_dpdk); static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(600, 600); @@ -66,6 +68,7 @@ struct ufid_to_rte_flow_data { struct netdev *physdev; struct ovs_mutex lock; unsigned int creation_tid; + uint32_t meter_id; bool dead; }; @@ -95,6 +98,19 @@ struct meter_id_to_meter_data { int flag; }; +static struct dpdk_meter_proxy * +netdev_lookup_meter_proxy(const int proxy_id, + struct meter_id_to_meter_data *meter_data) +{ + struct dpdk_meter_proxy *dmp; + LIST_FOR_EACH (dmp, node, &meter_data->meter_relate_proxy) { + if (proxy_id == dmp->proxy_id) { + return dmp; + } + } + return NULL; +} + static struct meter_id_to_meter_data * netdev_lookup_meter_data(const uint32_t meter_id) { @@ -246,7 +262,7 @@ ufid_to_rte_flow_data_find_protected(struct netdev *netdev, static inline struct ufid_to_rte_flow_data * ufid_to_rte_flow_associate(const ovs_u128 *ufid, struct netdev *netdev, struct netdev *physdev, struct rte_flow *rte_flow, - bool actions_offloaded) + bool actions_offloaded, uint32_t meter_id) { size_t hash = hash_bytes(ufid, sizeof *ufid, 0); struct cmap *map = offload_data_map(netdev); @@ -277,6 +293,7 @@ ufid_to_rte_flow_associate(const ovs_u128 *ufid, struct netdev *netdev, data->physdev = netdev != physdev ? netdev_ref(physdev) : physdev; data->rte_flow = rte_flow; data->actions_offloaded = actions_offloaded; + data->meter_id = meter_id; data->creation_tid = netdev_offload_thread_id(); ovs_mutex_init(&data->lock); @@ -2149,6 +2166,50 @@ parse_clone_actions(struct netdev *netdev, return 0; } +static void OVS_UNUSED +parse_meter_action(struct netdev *netdev, struct flow_actions *actions, + uint32_t meter_id) +{ + struct meter_id_to_meter_data *meter_data; + struct rte_flow_action_meter *rte_meter; + struct dpdk_meter_proxy *dmp; + int proxy_id; + + ovs_mutex_lock(&netdev_meter_mutex); + meter_data = netdev_lookup_meter_data(meter_id); + ovs_mutex_unlock(&netdev_meter_mutex); + if (meter_data == NULL) { + VLOG_DBG("netdev: meter '%u can't be found.", meter_id); + goto parse_meter; + } + + proxy_id = netdev_dpdk_get_prox_port_id(netdev); + + ovs_mutex_lock(&netdev_meter_mutex); + dmp = netdev_lookup_meter_proxy(proxy_id, meter_data); + if (dmp != NULL) { + dmp->refcnt++; + goto out_unlock; + } + + dmp = (struct dpdk_meter_proxy *) xmalloc(sizeof(struct dpdk_meter_proxy)); + dmp->proxy_id = netdev_dpdk_get_prox_port_id(netdev); + dmp->refcnt = 1; + ovs_list_insert(&meter_data->meter_relate_proxy, &dmp->node); + + if (netdev_dpdk_meter_create(proxy_id, meter_id, meter_data->rate, + meter_data->burst, meter_data->flag)) { + VLOG_ERR("Failed offload the flow to the %s", netdev->name); + } + +out_unlock: + ovs_mutex_unlock(&netdev_meter_mutex); +parse_meter: + rte_meter = xzalloc(sizeof *rte_meter); + rte_meter->mtr_id = meter_id; + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_METER, rte_meter); +} + static void add_jump_action(struct flow_actions *actions, uint32_t group) { @@ -2206,7 +2267,8 @@ static int parse_flow_actions(struct netdev *netdev, struct flow_actions *actions, struct nlattr *nl_actions, - size_t nl_actions_len) + size_t nl_actions_len, + uint32_t *meter_id OVS_UNUSED) { struct nlattr *nla; size_t left; @@ -2255,6 +2317,9 @@ parse_flow_actions(struct netdev *netdev, if (add_tnl_pop_action(netdev, actions, nla)) { return -1; } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_METER) { + *meter_id = nl_attr_get_u32(nla); + parse_meter_action(netdev, actions, *meter_id); #endif } else { VLOG_DBG_RL(&rl, "Unsupported action type %d", nl_attr_type(nla)); @@ -2275,7 +2340,8 @@ static struct rte_flow * netdev_offload_dpdk_actions(struct netdev *netdev, struct flow_patterns *patterns, struct nlattr *nl_actions, - size_t actions_len) + size_t actions_len, + uint32_t *meter_id) { const struct rte_flow_attr flow_attr = { .transfer = 1 }; struct flow_actions actions = { @@ -2287,7 +2353,8 @@ netdev_offload_dpdk_actions(struct netdev *netdev, struct rte_flow_error error; int ret; - ret = parse_flow_actions(netdev, &actions, nl_actions, actions_len); + ret = parse_flow_actions(netdev, &actions, nl_actions, actions_len, + meter_id); if (ret) { goto out; } @@ -2312,6 +2379,7 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, .s_tnl = DS_EMPTY_INITIALIZER, }; struct ufid_to_rte_flow_data *flows_data = NULL; + uint32_t meter_id = MAX_METERS; bool actions_offloaded = true; struct rte_flow *flow; @@ -2322,7 +2390,7 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, } flow = netdev_offload_dpdk_actions(patterns.physdev, &patterns, nl_actions, - actions_len); + actions_len, &meter_id); if (!flow && !netdev_vport_is_vport_class(netdev->netdev_class)) { /* If we failed to offload the rule actions fallback to MARK+RSS * actions. @@ -2336,7 +2404,7 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, goto out; } flows_data = ufid_to_rte_flow_associate(ufid, netdev, patterns.physdev, - flow, actions_offloaded); + flow, actions_offloaded, meter_id); VLOG_DBG("%s/%s: installed flow %p by ufid "UUID_FMT, netdev_get_name(netdev), netdev_get_name(patterns.physdev), flow, UUID_ARGS((struct uuid *) ufid)); @@ -2346,6 +2414,53 @@ out: return flows_data; } +static void +netdev_dpdk_rte_mtr_del(uint32_t meter_id, struct netdev *netdev) +{ + struct meter_id_to_meter_data *meter_data; + uint32_t meter_profile_id = meter_id; + uint32_t meter_policy_id = meter_id; + struct dpdk_meter_proxy *dmp; + int proxy_id; + + if (meter_id >= MAX_METERS) { + return; + } + + ovs_mutex_lock(&netdev_meter_mutex); + meter_data = netdev_lookup_meter_data(meter_id); + ovs_mutex_unlock(&netdev_meter_mutex); + + if (meter_data == NULL) { + VLOG_DBG("netdev: meter '%u' can't be found.", meter_id); + return; + } + + proxy_id = netdev_dpdk_get_prox_port_id(netdev); + + ovs_mutex_lock(&netdev_meter_mutex); + dmp = netdev_lookup_meter_proxy(proxy_id, meter_data); + if (dmp == NULL) { + VLOG_ERR("Failed get the meter data from the %s", netdev->name); + goto out_unlock; + } + + dmp->refcnt--; + if (dmp->refcnt) { + goto out_unlock; + } + + ovs_list_moved(&meter_data->meter_relate_proxy, &dmp->node); + if (netdev_dpdk_meter_del(proxy_id, meter_id, meter_profile_id, + meter_policy_id)) { + VLOG_ERR("Failed delete the meter %u from the %s", meter_id, + netdev->name); + } + +out_unlock: + ovs_mutex_unlock(&netdev_meter_mutex); +} + static int netdev_offload_dpdk_flow_destroy(struct ufid_to_rte_flow_data *rte_flow_data) { @@ -2353,6 +2468,7 @@ netdev_offload_dpdk_flow_destroy(struct ufid_to_rte_flow_data *rte_flow_data) struct rte_flow *rte_flow; struct netdev *physdev; struct netdev *netdev; + uint32_t meter_id; ovs_u128 *ufid; bool transfer; int ret; @@ -2371,10 +2487,13 @@ netdev_offload_dpdk_flow_destroy(struct ufid_to_rte_flow_data *rte_flow_data) physdev = rte_flow_data->physdev; netdev = rte_flow_data->netdev; ufid = &rte_flow_data->ufid; + meter_id = rte_flow_data->meter_id; ret = netdev_dpdk_rte_flow_destroy(physdev, transfer, rte_flow, &error); if (ret == 0) { + netdev_dpdk_rte_mtr_del(meter_id, netdev); + struct netdev_offload_dpdk_data *data; unsigned int tid = netdev_offload_thread_id(); -- 2.30.2 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
