From patchwork Thu Jan 1 01:39:06 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: kan.liang@intel.com X-Patchwork-Id: 655903 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3s507Y2rX0z9stY for ; Fri, 5 Aug 2016 05:17:29 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965719AbcHDTRG (ORCPT ); Thu, 4 Aug 2016 15:17:06 -0400 Received: from mga03.intel.com ([134.134.136.65]:49783 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965485AbcHDTNE (ORCPT ); Thu, 4 Aug 2016 15:13:04 -0400 Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga103.jf.intel.com with ESMTP; 04 Aug 2016 12:13:00 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.28,471,1464678000"; d="scan'208";a="859869549" Received: from otc-wp-01.jf.intel.com ([10.54.39.157]) by orsmga003.jf.intel.com with ESMTP; 04 Aug 2016 12:13:02 -0700 From: kan.liang@intel.com To: davem@davemloft.net, linux-kernel@vger.kernel.org, netdev@vger.kernel.org Cc: jeffrey.t.kirsher@intel.com, mingo@redhat.com, peterz@infradead.org, kuznet@ms2.inr.ac.ru, jmorris@namei.org, yoshfuji@linux-ipv6.org, kaber@trash.net, akpm@linux-foundation.org, keescook@chromium.org, viro@zeniv.linux.org.uk, gorcunov@openvz.org, john.stultz@linaro.org, aduyck@mirantis.com, ben@decadent.org.uk, decot@googlers.com, fw@strlen.de, alexander.duyck@gmail.com, daniel@iogearbox.net, tom@herbertland.com, rdunlap@infradead.org, xiyou.wangcong@gmail.com, hannes@stressinduktion.org, jesse.brandeburg@intel.com, andi@firstfloor.org, Kan Liang Subject: [RFC V2 PATCH 17/25] net/netpolicy: introduce netpolicy_pick_queue Date: Wed, 31 Dec 2014 20:39:06 -0500 Message-Id: <1420076354-4861-18-git-send-email-kan.liang@intel.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1420076354-4861-1-git-send-email-kan.liang@intel.com> References: <1420076354-4861-1-git-send-email-kan.liang@intel.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Kan Liang To achieve better network performance, the key step is to distribute the packets to dedicated queues according to policy and system run time status. This patch provides an interface which can return the proper dedicated queue for socket/task. Then the packets of the socket/task will be redirect to the dedicated queue for better network performance. For selecting the proper queue, currently it uses round-robin algorithm to find the available object from the given policy object list. The algorithm is good enough for now. But it could be improved by some adaptive algorithm later. The selected object will be stored in hashtable. So it does not need to go through the whole object list every time. Signed-off-by: Kan Liang --- include/linux/netpolicy.h | 5 ++ net/core/netpolicy.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/include/linux/netpolicy.h b/include/linux/netpolicy.h index 5900252..a522015 100644 --- a/include/linux/netpolicy.h +++ b/include/linux/netpolicy.h @@ -97,6 +97,7 @@ extern void update_netpolicy_sys_map(void); extern int netpolicy_register(struct netpolicy_instance *instance, enum netpolicy_name policy); extern void netpolicy_unregister(struct netpolicy_instance *instance); +extern int netpolicy_pick_queue(struct netpolicy_instance *instance, bool is_rx); #else static inline void update_netpolicy_sys_map(void) { @@ -111,6 +112,10 @@ static inline void netpolicy_unregister(struct netpolicy_instance *instance) { } +static inline int netpolicy_pick_queue(struct netpolicy_instance *instance, bool is_rx) +{ + return 0; +} #endif #endif /*__LINUX_NETPOLICY_H*/ diff --git a/net/core/netpolicy.c b/net/core/netpolicy.c index 3605761..98ca430 100644 --- a/net/core/netpolicy.c +++ b/net/core/netpolicy.c @@ -290,6 +290,142 @@ static void netpolicy_record_clear_dev_node(struct net_device *dev) spin_unlock_bh(&np_hashtable_lock); } +static struct netpolicy_object *get_avail_object(struct net_device *dev, + enum netpolicy_name policy, + bool is_rx) +{ + int dir = is_rx ? NETPOLICY_RX : NETPOLICY_TX; + struct netpolicy_object *tmp, *obj = NULL; + int val = -1; + + /* Check if net policy is supported */ + if (!dev || !dev->netpolicy) + return NULL; + + /* The system should have queues which support the request policy. */ + if ((policy != dev->netpolicy->cur_policy) && + (dev->netpolicy->cur_policy != NET_POLICY_MIX)) + return NULL; + + spin_lock_bh(&dev->np_ob_list_lock); + list_for_each_entry(tmp, &dev->netpolicy->obj_list[dir][policy], list) { + if ((val > atomic_read(&tmp->refcnt)) || + (val == -1)) { + val = atomic_read(&tmp->refcnt); + obj = tmp; + } + } + + if (WARN_ON(!obj)) { + spin_unlock_bh(&dev->np_ob_list_lock); + return NULL; + } + atomic_inc(&obj->refcnt); + spin_unlock_bh(&dev->np_ob_list_lock); + + return obj; +} + +static int get_avail_queue(struct netpolicy_instance *instance, bool is_rx) +{ + struct netpolicy_record *old_record, *new_record; + struct net_device *dev = instance->dev; + unsigned long ptr_id = (uintptr_t)instance->ptr; + int queue = -1; + + spin_lock_bh(&np_hashtable_lock); + old_record = netpolicy_record_search(ptr_id); + if (!old_record) { + pr_warn("NETPOLICY: doesn't registered. Remove net policy settings!\n"); + instance->policy = NET_POLICY_INVALID; + goto err; + } + + if (is_rx && old_record->rx_obj) { + queue = old_record->rx_obj->queue; + } else if (!is_rx && old_record->tx_obj) { + queue = old_record->tx_obj->queue; + } else { + new_record = kzalloc(sizeof(*new_record), GFP_KERNEL); + if (!new_record) + goto err; + memcpy(new_record, old_record, sizeof(*new_record)); + + if (is_rx) { + new_record->rx_obj = get_avail_object(dev, new_record->policy, is_rx); + if (!new_record->dev) + new_record->dev = dev; + if (!new_record->rx_obj) { + kfree(new_record); + goto err; + } + queue = new_record->rx_obj->queue; + } else { + new_record->tx_obj = get_avail_object(dev, new_record->policy, is_rx); + if (!new_record->dev) + new_record->dev = dev; + if (!new_record->tx_obj) { + kfree(new_record); + goto err; + } + queue = new_record->tx_obj->queue; + } + /* update record */ + hlist_replace_rcu(&old_record->hash_node, &new_record->hash_node); + kfree(old_record); + } +err: + spin_unlock_bh(&np_hashtable_lock); + return queue; +} + +static inline bool policy_validate(struct netpolicy_instance *instance) +{ + struct net_device *dev = instance->dev; + enum netpolicy_name cur_policy; + + cur_policy = dev->netpolicy->cur_policy; + if ((instance->policy == NET_POLICY_NONE) || + (cur_policy == NET_POLICY_NONE)) + return false; + + if (((cur_policy != NET_POLICY_MIX) && (cur_policy != instance->policy)) || + ((cur_policy == NET_POLICY_MIX) && (instance->policy == NET_POLICY_CPU))) { + pr_warn("NETPOLICY: %s current device policy %s doesn't support required policy %s! Remove net policy settings!\n", + dev->name, policy_name[cur_policy], + policy_name[instance->policy]); + return false; + } + return true; +} + +/** + * netpolicy_pick_queue() - Find proper queue + * @instance: NET policy per socket/task instance info + * @is_rx: RX queue or TX queue + * + * This function intends to find the proper queue according to policy. + * For selecting the proper queue, currently it uses round-robin algorithm + * to find the available object from the given policy object list. + * The selected object will be stored in hashtable. So it does not need to + * go through the whole object list every time. + * + * Return: negative on failure, otherwise on the assigned queue + */ +int netpolicy_pick_queue(struct netpolicy_instance *instance, bool is_rx) +{ + struct net_device *dev = instance->dev; + + if (!dev || !dev->netpolicy) + return -EINVAL; + + if (!policy_validate(instance)) + return -EINVAL; + + return get_avail_queue(instance, is_rx); +} +EXPORT_SYMBOL(netpolicy_pick_queue); + /** * netpolicy_register() - Register per socket/task policy request * @instance: NET policy per socket/task instance info