From patchwork Mon Jul 18 06:56:13 2016 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: 649700 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rtWPm3gG5z9s5J for ; Tue, 19 Jul 2016 04:08:28 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 137AB30DB3; Mon, 18 Jul 2016 18:08:27 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id BQatjVayEDqE; Mon, 18 Jul 2016 18:08:22 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by silver.osuosl.org (Postfix) with ESMTP id B590330EB5; Mon, 18 Jul 2016 18:07:58 +0000 (UTC) X-Original-To: intel-wired-lan@lists.osuosl.org Delivered-To: intel-wired-lan@lists.osuosl.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by ash.osuosl.org (Postfix) with ESMTP id 9C8E11C2A6F for ; Mon, 18 Jul 2016 14:23:28 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 9961B8AD97 for ; Mon, 18 Jul 2016 14:23:28 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Co-sjy5ITfB2 for ; Mon, 18 Jul 2016 14:23:27 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by whitealder.osuosl.org (Postfix) with ESMTP id C85B88ADC9 for ; Mon, 18 Jul 2016 14:23:27 +0000 (UTC) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP; 18 Jul 2016 07:23:27 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.28,384,1464678000"; d="scan'208"; a="1009027622" Received: from otc-grantly-02.jf.intel.com ([10.54.39.33]) by fmsmga001.fm.intel.com with ESMTP; 18 Jul 2016 07:23:28 -0700 From: kan.liang@intel.com To: davem@davemloft.net, linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org Date: Sun, 17 Jul 2016 23:56:13 -0700 Message-Id: <1468824984-65318-20-git-send-email-kan.liang@intel.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1468824984-65318-1-git-send-email-kan.liang@intel.com> References: <1468824984-65318-1-git-send-email-kan.liang@intel.com> X-Mailman-Approved-At: Mon, 18 Jul 2016 18:07:53 +0000 Cc: decot@googlers.com, aduyck@mirantis.com, andi@firstfloor.org, keescook@chromium.org, peterz@infradead.org, Kan Liang , jmorris@namei.org, yoshfuji@linux-ipv6.org, mingo@redhat.com, john.stultz@linaro.org, gorcunov@openvz.org, kuznet@ms2.inr.ac.ru, akpm@linux-foundation.org, ben@decadent.org.uk, kaber@trash.net, viro@zeniv.linux.org.uk Subject: [Intel-wired-lan] [RFC PATCH 19/30] net/netpolicy: implement netpolicy register X-BeenThere: intel-wired-lan@lists.osuosl.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Intel Wired Ethernet Linux Kernel Driver Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-wired-lan-bounces@lists.osuosl.org Sender: "Intel-wired-lan" From: Kan Liang User can register itself in netpolicy module with specific policy. If it's the first time to register, an record will be created and inserted into RCU hash table. The record includes ptr, policy and object information. ptr is assigned by the user which is used as key to search the record in hash table. Object will be assigned by netpolicy later. If CPU/device are removed(hotplug), the assigned object will be clear. This patch also introduces a new type NET_POLICY_INVALID, which indicates that the task/socket are not registered. np_hashtable_lock is introduced to protect the hash table. Signed-off-by: Kan Liang --- include/linux/netpolicy.h | 26 ++++++++ net/core/netpolicy.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) diff --git a/include/linux/netpolicy.h b/include/linux/netpolicy.h index cc75e3c..89361d9 100644 --- a/include/linux/netpolicy.h +++ b/include/linux/netpolicy.h @@ -17,6 +17,7 @@ #define __LINUX_NETPOLICY_H enum netpolicy_name { + NET_POLICY_INVALID = -1, NET_POLICY_NONE = 0, NET_POLICY_CPU, NET_POLICY_BULK, @@ -79,12 +80,37 @@ struct netpolicy_info { struct list_head obj_list[NETPOLICY_RXTX][NET_POLICY_MAX]; }; +struct netpolicy_reg { + struct net_device *dev; + enum netpolicy_name policy; /* required policy */ + void *ptr; /* pointers */ +}; + +/* check if policy is valid */ +static inline int is_net_policy_valid(enum netpolicy_name policy) +{ + return ((policy < NET_POLICY_MAX) && (policy > NET_POLICY_INVALID)); +} + #ifdef CONFIG_NETPOLICY extern void update_netpolicy_sys_map(void); +extern int netpolicy_register(struct netpolicy_reg *reg, + enum netpolicy_name policy); +extern void netpolicy_unregister(struct netpolicy_reg *reg); #else static inline void update_netpolicy_sys_map(void) { } + +static inline int netpolicy_register(struct netpolicy_reg *reg, + enum netpolicy_name policy) +{ return 0; +} + +static inline void netpolicy_unregister(struct netpolicy_reg *reg) +{ +} + #endif #endif /*__LINUX_NETPOLICY_H*/ diff --git a/net/core/netpolicy.c b/net/core/netpolicy.c index da7d9f1..13ab5e1 100644 --- a/net/core/netpolicy.c +++ b/net/core/netpolicy.c @@ -38,6 +38,19 @@ #include #include #include +#include + +struct netpolicy_record { + struct hlist_node hash_node; + unsigned long ptr_id; + enum netpolicy_name policy; + struct net_device *dev; + struct netpolicy_object *rx_obj; + struct netpolicy_object *tx_obj; +}; + +static DEFINE_HASHTABLE(np_record_hash, 10); +static DEFINE_SPINLOCK(np_hashtable_lock); static int netpolicy_get_dev_info(struct net_device *dev, struct netpolicy_dev_info *d_info) @@ -223,6 +236,140 @@ static int netpolicy_enable(struct net_device *dev) return 0; } +static struct netpolicy_record *netpolicy_record_search(unsigned long ptr_id) +{ + struct netpolicy_record *rec = NULL; + + hash_for_each_possible_rcu(np_record_hash, rec, hash_node, ptr_id) { + if (rec->ptr_id == ptr_id) + break; + } + + return rec; +} + +static void netpolicy_record_clear_obj(void) +{ + struct netpolicy_record *rec; + int i; + + spin_lock_bh(&np_hashtable_lock); + hash_for_each_rcu(np_record_hash, i, rec, hash_node) { + rec->rx_obj = NULL; + rec->tx_obj = NULL; + } + spin_unlock_bh(&np_hashtable_lock); +} + +static void netpolicy_record_clear_dev_node(struct net_device *dev) +{ + struct netpolicy_record *rec; + int i; + + spin_lock_bh(&np_hashtable_lock); + hash_for_each_rcu(np_record_hash, i, rec, hash_node) { + if (rec->dev == dev) { + hash_del_rcu(&rec->hash_node); + kfree(rec); + } + } + spin_unlock_bh(&np_hashtable_lock); +} + +static void put_queue(struct net_device *dev, + struct netpolicy_object *rx_obj, + struct netpolicy_object *tx_obj) +{ + if (!dev || !dev->netpolicy) + return; + + if (rx_obj) + atomic_dec(&rx_obj->refcnt); + if (tx_obj) + atomic_dec(&tx_obj->refcnt); +} + +/** + * netpolicy_register() - Register per socket/task policy request + * @reg: NET policy register info + * @policy: request NET policy + * + * This function intends to register per socket/task policy request. + * If it's the first time to register, an record will be created and + * inserted into RCU hash table. + * + * The record includes ptr, policy and object info. ptr of the socket/task + * is the key to search the record in hash table. Object will be assigned + * until the first packet is received/transmitted. + * + * Return: 0 on success, others on failure + */ +int netpolicy_register(struct netpolicy_reg *reg, + enum netpolicy_name policy) +{ + unsigned long ptr_id = (uintptr_t)reg->ptr; + struct netpolicy_record *new, *old; + + if (!is_net_policy_valid(policy)) { + reg->policy = NET_POLICY_INVALID; + return -EINVAL; + } + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) { + reg->policy = NET_POLICY_INVALID; + return -ENOMEM; + } + + spin_lock_bh(&np_hashtable_lock); + /* Check it in mapping table */ + old = netpolicy_record_search(ptr_id); + if (old) { + if (old->policy != policy) { + put_queue(old->dev, old->rx_obj, old->tx_obj); + old->policy = policy; + } + kfree(new); + } else { + new->ptr_id = ptr_id; + new->dev = reg->dev; + new->policy = policy; + hash_add_rcu(np_record_hash, &new->hash_node, ptr_id); + } + reg->policy = policy; + spin_unlock_bh(&np_hashtable_lock); + + return 0; +} +EXPORT_SYMBOL(netpolicy_register); + +/** + * netpolicy_unregister() - Unregister per socket/task policy request + * @reg: NET policy register info + * + * This function intends to unregister policy request by del related record + * from hash table. + * + */ +void netpolicy_unregister(struct netpolicy_reg *reg) +{ + struct netpolicy_record *record; + unsigned long ptr_id = (uintptr_t)reg->ptr; + + spin_lock_bh(&np_hashtable_lock); + /* del from hash table */ + record = netpolicy_record_search(ptr_id); + if (record) { + hash_del_rcu(&record->hash_node); + /* The record cannot be share. It can be safely free. */ + put_queue(record->dev, record->rx_obj, record->tx_obj); + kfree(record); + } + reg->policy = NET_POLICY_INVALID; + spin_unlock_bh(&np_hashtable_lock); +} +EXPORT_SYMBOL(netpolicy_unregister); + const char *policy_name[NET_POLICY_MAX] = { "NONE", "CPU", @@ -825,6 +972,7 @@ static int netpolicy_notify(struct notifier_block *this, break; case NETDEV_GOING_DOWN: uninit_netpolicy(dev); + netpolicy_record_clear_dev_node(dev); #ifdef CONFIG_PROC_FS proc_remove(dev->proc_dev); dev->proc_dev = NULL; @@ -863,6 +1011,8 @@ void update_netpolicy_sys_map(void) dev->netpolicy->cur_policy = NET_POLICY_NONE; + /* clear mapping table */ + netpolicy_record_clear_obj(); /* rebuild everything */ netpolicy_disable(dev); netpolicy_enable(dev);