From patchwork Mon Dec 11 20:38:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Herbert X-Patchwork-Id: 847218 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=quantonium-net.20150623.gappssmtp.com header.i=@quantonium-net.20150623.gappssmtp.com header.b="Ydp3F3/0"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ywZZN5H8lz9t2M for ; Tue, 12 Dec 2017 07:39:40 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752582AbdLKUjj (ORCPT ); Mon, 11 Dec 2017 15:39:39 -0500 Received: from mail-pf0-f193.google.com ([209.85.192.193]:34339 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752525AbdLKUjU (ORCPT ); Mon, 11 Dec 2017 15:39:20 -0500 Received: by mail-pf0-f193.google.com with SMTP id a90so12445273pfk.1 for ; Mon, 11 Dec 2017 12:39:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quantonium-net.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=mVNpAdTpPd+Tws3/SM+yeEqvVKbvongI0b781kbDaB4=; b=Ydp3F3/0+5t+ERIS2BKXL/KxN2OsSVA+roeOW5vLRyPS0+nOB2GR22IQ3yt/Hwmobf 21nUaw6xgozNzi8t7V15n0RiDAktV9kztkGY3eykKw1sWXPZ31oE0aLDzpU4A3BQahDA sOJ2cSbwpQ0r3eA48pr9U56iN1OWXnNUBpgyZ9HINQ068e0eCy9aKgxw+MypR/U8HzHf MSni3my04p/dMka4nYnBAvP8gssm3X+Qh+5FlMlf7UtgSHg3620pklvaW5e7yZ/SgPfQ ue2imnBITlqVxKma2e+NnZQ5VqJYrFEP37J56h2xkGTBqmb70YcUcCmJWUHhkCbKxgvW 8wSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=mVNpAdTpPd+Tws3/SM+yeEqvVKbvongI0b781kbDaB4=; b=g5UZzaT+GrDACgtKZFYTd0hezPzcWwphiqXtXnDKsDgBvBHBLzJLRShkYlP1P1nEEz P5Kk7yRaQOcQ1H31dXYEzK6yI03Ya6Z2IjyLDoDnK1Ft7SvN2OvgFB/EhOUZu0WUba2I ASf8WnEJsTfbG8pY1VEc9j/peU5IGNCZ397DimhmARJ2NZuJMPnjoWMDeC4DC1itmmTr B9VsmORCURfx947aARtNqfUf1l5e6lRHXAf/+6FUY9X1sjMV7TpgUQqmGB2RAkyLipw9 B/X+SyT5K01XlZBQ/md//jGmdxTWBqqiwqpub5hXjritEShUN2ugFX5RcqqZDJw0IgJM yqwQ== X-Gm-Message-State: AKGB3mJffpkn2AD/IhLvVS9NFeE3PAjbWa21nOA+XUpV8jOzQFloDBHa /txiGyk9TsM0LXEGgIAQ0EWQRA== X-Google-Smtp-Source: ACJfBotxx/ZI9m6EoJFiHgt6K0BnipvuZq9MEqvJy+elQXdU6w2iA98SRj9p0npiBmVJLWxIvrFr5g== X-Received: by 10.159.231.24 with SMTP id w24mr1487113plq.272.1513024759789; Mon, 11 Dec 2017 12:39:19 -0800 (PST) Received: from localhost.localdomain (67-207-98-108.static.wiline.com. [67.207.98.108]) by smtp.gmail.com with ESMTPSA id t6sm26426790pfl.76.2017.12.11.12.39.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 11 Dec 2017 12:39:18 -0800 (PST) From: Tom Herbert To: davem@davemloft.net Cc: netdev@vger.kernel.org, roopa@cumulusnetworks.com, rohit@quantonium.net, Tom Herbert Subject: [PATCH v3 net-next 8/9] resolver: add netlink control Date: Mon, 11 Dec 2017 12:38:36 -0800 Message-Id: <20171211203837.2540-9-tom@quantonium.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171211203837.2540-1-tom@quantonium.net> References: <20171211203837.2540-1-tom@quantonium.net> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add interfaces into resolver backend that can be used to provide netlink. The interface includes fucntions to support the common netlink commands (get, add, list, delete, and flush). The frontend that is using the resolver implements the actual netlink interfaces for its service and calls the backend functions to provide netlink for the resolver. Signed-off-by: Tom Herbert --- include/net/resolver.h | 26 +++- net/ipv6/ila/ila_resolver.c | 3 +- net/resolver/resolver.c | 280 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 305 insertions(+), 4 deletions(-) diff --git a/include/net/resolver.h b/include/net/resolver.h index f38c7e9f1205..307938ad91a6 100644 --- a/include/net/resolver.h +++ b/include/net/resolver.h @@ -14,12 +14,21 @@ #include #include +#include +#include struct net_rslv; typedef int (*net_rslv_cmpfn)(struct net_rslv *nrslv, const void *key, const void *object); +struct net_rslv_netlink_map { + int dst_attr; + int timo_attr; + int get_cmd; + struct genl_family *genl_family; +}; + struct net_rslv { struct rhashtable rhash_table; struct rhashtable_params params; @@ -28,10 +37,12 @@ struct net_rslv { spinlock_t *locks; unsigned int locks_mask; unsigned int hash_rnd; + const struct net_rslv_netlink_map *nlmap; }; struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len, - size_t max_size, net_rslv_cmpfn cmp_fn); + size_t max_size, net_rslv_cmpfn cmp_fn, + const struct net_rslv_netlink_map *nlmap); void net_rslv_destroy(struct net_rslv *nrslv); @@ -40,4 +51,17 @@ int net_rslv_lookup_and_create(struct net_rslv *nrslv, void *key, void net_rslv_resolved(struct net_rslv *nrslv, void *key); +int net_rslv_nl_cmd_add(struct net_rslv *nrslv, struct sk_buff *skb, + struct genl_info *info); +int net_rslv_nl_cmd_del(struct net_rslv *nrslv, struct sk_buff *skb, + struct genl_info *info); +int net_rslv_nl_cmd_get(struct net_rslv *nrslv, struct sk_buff *skb, + struct genl_info *info); +int net_rslv_nl_cmd_flush(struct net_rslv *nrslv, struct sk_buff *skb, + struct genl_info *info); +int net_rslv_nl_dump_start(struct net_rslv *nrslv, struct netlink_callback *cb); +int net_rslv_nl_dump_done(struct net_rslv *nrslv, struct netlink_callback *cb); +int net_rslv_nl_dump(struct net_rslv *nrslv, struct sk_buff *skb, + struct netlink_callback *cb); + #endif /* __NET_RESOLVER_H */ diff --git a/net/ipv6/ila/ila_resolver.c b/net/ipv6/ila/ila_resolver.c index 8b9a3c5305a4..2aebc0526221 100644 --- a/net/ipv6/ila/ila_resolver.c +++ b/net/ipv6/ila/ila_resolver.c @@ -215,7 +215,8 @@ int ila_rslv_init_net(struct net *net) struct net_rslv *nrslv; nrslv = net_rslv_create(sizeof(struct ila_addr), - sizeof(struct ila_addr), ILA_MAX_SIZE, NULL); + sizeof(struct ila_addr), ILA_MAX_SIZE, NULL, + NULL); if (IS_ERR(nrslv)) return PTR_ERR(nrslv); diff --git a/net/resolver/resolver.c b/net/resolver/resolver.c index 32a915ed8f93..e2496b0bf852 100644 --- a/net/resolver/resolver.c +++ b/net/resolver/resolver.c @@ -19,11 +19,13 @@ #include #include #include +#include #include #include #include #include #include +#include struct net_rslv_ent { struct rhash_head node; @@ -192,8 +194,8 @@ static int net_rslv_cmp(struct rhashtable_compare_arg *arg, #define MAX_LOCKS 1024 struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len, - size_t max_size, - net_rslv_cmpfn cmp_fn) + size_t max_size, net_rslv_cmpfn cmp_fn, + const struct net_rslv_netlink_map *nlmap) { struct net_rslv *nrslv; int err; @@ -212,6 +214,7 @@ struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len, nrslv->obj_size = obj_size; nrslv->rslv_cmp = cmp_fn; + nrslv->nlmap = nlmap; get_random_bytes(&nrslv->hash_rnd, sizeof(nrslv->hash_rnd)); nrslv->params.head_offset = offsetof(struct net_rslv_ent, node); @@ -278,6 +281,279 @@ void net_rslv_destroy(struct net_rslv *nrslv) } EXPORT_SYMBOL_GPL(net_rslv_destroy); +/* Netlink access utility functions and structures. */ + +struct net_rslv_params { + unsigned int timeout; + __u8 key[MAX_ADDR_LEN]; + size_t keysize; +}; + +static int parse_nl_config(struct net_rslv *nrslv, struct genl_info *info, + struct net_rslv_params *np) +{ + if (!info->attrs[nrslv->nlmap->dst_attr] || + nla_len(info->attrs[nrslv->nlmap->dst_attr]) != + nrslv->params.key_len) + return -EINVAL; + + memset(np, 0, sizeof(*np)); + + memcpy(np->key, nla_data(info->attrs[nrslv->nlmap->dst_attr]), + nla_len(info->attrs[nrslv->nlmap->dst_attr])); + + if (info->attrs[nrslv->nlmap->timo_attr]) + np->timeout = nla_get_u32(info->attrs[nrslv->nlmap->timo_attr]); + + return 0; +} + +int net_rslv_nl_cmd_add(struct net_rslv *nrslv, struct sk_buff *skb, + struct genl_info *info) +{ + struct net_rslv_params p; + int err; + + err = parse_nl_config(nrslv, info, &p); + if (err) + return err; + + return net_rslv_lookup_and_create(nrslv, p.key, p.timeout); +} +EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_add); + +int net_rslv_nl_cmd_del(struct net_rslv *nrslv, struct sk_buff *skb, + struct genl_info *info) +{ + struct net_rslv_params p; + int err; + + err = parse_nl_config(nrslv, info, &p); + if (err) + return err; + + /* Treat removal as being resolved */ + net_rslv_resolved(nrslv, p.key); + + return 0; +} +EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_del); + +static int net_rslv_fill_info(struct net_rslv *nrslv, + struct net_rslv_ent *nrent, + struct sk_buff *msg) +{ + int from_now = 0; + + if (delayed_work_pending(&nrent->timeout_work)) { + unsigned long expires = nrent->timeout_work.timer.expires; + + from_now = jiffies_to_msecs(expires - jiffies); + + if (from_now < 0) + from_now = 0; + } + + if (nla_put(msg, nrslv->nlmap->dst_attr, nrslv->params.key_len, + nrent->object) || + nla_put_s32(msg, nrslv->nlmap->timo_attr, from_now)) + return -1; + + return 0; +} + +static int net_rslv_dump_info(struct net_rslv *nrslv, + struct net_rslv_ent *nrent, u32 portid, u32 seq, + u32 flags, struct sk_buff *skb, u8 cmd) +{ + void *hdr; + + hdr = genlmsg_put(skb, portid, seq, nrslv->nlmap->genl_family, flags, + cmd); + if (!hdr) + return -ENOMEM; + + if (net_rslv_fill_info(nrslv, nrent, skb) < 0) + goto nla_put_failure; + + genlmsg_end(skb, hdr); + return 0; + +nla_put_failure: + genlmsg_cancel(skb, hdr); + return -EMSGSIZE; +} + +int net_rslv_nl_cmd_get(struct net_rslv *nrslv, struct sk_buff *skb, + struct genl_info *info) +{ + struct net_rslv_ent *nrent; + struct net_rslv_params p; + struct sk_buff *msg; + int err; + + err = parse_nl_config(nrslv, info, &p); + if (err) + return err; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + rcu_read_lock(); + + nrent = rhashtable_lookup_fast(&nrslv->rhash_table, p.key, + nrslv->params); + if (nrent) + err = net_rslv_dump_info(nrslv, nrent, info->snd_portid, + info->snd_seq, 0, msg, + info->genlhdr->cmd); + + rcu_read_unlock(); + + if (err < 0) + goto out_free; + + return genlmsg_reply(msg, info); + +out_free: + nlmsg_free(msg); + return err; +} +EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_get); + +int net_rslv_nl_cmd_flush(struct net_rslv *nrslv, struct sk_buff *skb, + struct genl_info *info) +{ + struct rhashtable_iter iter; + struct net_rslv_ent *nrent; + spinlock_t *lock; + int ret; + + ret = rhashtable_walk_init(&nrslv->rhash_table, &iter, GFP_KERNEL); + if (ret) + return ret; + + rhashtable_walk_start(&iter); + + for (;;) { + nrent = rhashtable_walk_next(&iter); + + if (IS_ERR(nrent)) { + if (PTR_ERR(nrent) == -EAGAIN) { + /* New table, we're okay to continue */ + continue; + } + ret = PTR_ERR(nrent); + break; + } else if (!nrent) { + break; + } + + lock = net_rslv_get_lock(nrslv, nrent->object); + + spin_lock(lock); + ret = rhashtable_remove_fast(&nrslv->rhash_table, &nrent->node, + nrslv->params); + spin_unlock(lock); + + if (ret) + break; + } + + rhashtable_walk_stop(&iter); + rhashtable_walk_exit(&iter); + + return ret; +} +EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_flush); + +int net_rslv_nl_dump_start(struct net_rslv *nrslv, struct netlink_callback *cb) +{ + struct rhashtable_iter *iter; + int ret; + + iter = kmalloc(sizeof(*iter), GFP_KERNEL); + if (!iter) + return -ENOMEM; + + ret = rhashtable_walk_init(&nrslv->rhash_table, iter, GFP_KERNEL); + if (ret) { + kfree(iter); + return ret; + } + + cb->args[0] = (long)iter; + + return 0; +} +EXPORT_SYMBOL_GPL(net_rslv_nl_dump_start); + +int net_rslv_nl_dump_done(struct net_rslv *nrslv, struct netlink_callback *cb) +{ + struct rhashtable_iter *iter = + (struct rhashtable_iter *)cb->args[0]; + + rhashtable_walk_exit(iter); + + kfree(iter); + + return 0; +} +EXPORT_SYMBOL_GPL(net_rslv_nl_dump_done); + +int net_rslv_nl_dump(struct net_rslv *nrslv, struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct rhashtable_iter *iter = + (struct rhashtable_iter *)cb->args[0]; + struct net_rslv_ent *nrent; + int ret; + + ret = rhashtable_walk_start_check(iter); + if (ret) + goto done; + + /* Get first entty */ + nrent = rhashtable_walk_peek(iter); + + for (;;) { + if (IS_ERR(nrent)) { + ret = PTR_ERR(nrent); + if (ret == -EAGAIN) { + /* Table has changed and iter has reset. Return + * -EAGAIN to the application even if we have + * written data to the skb. The application + * needs to deal with this. + */ + + goto done; + } + break; + } else if (!nrent) { + break; + } + + ret = net_rslv_dump_info(nrslv, nrent, + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, + NLM_F_MULTI, skb, + nrslv->nlmap->get_cmd); + if (ret) + break; + + /* Get next and advance the iter */ + nrent = rhashtable_walk_next(iter); + } + + ret = (skb->len ? : ret); + +done: + rhashtable_walk_stop(iter); + return ret; +} +EXPORT_SYMBOL_GPL(net_rslv_nl_dump); + MODULE_AUTHOR("Tom Herbert "); MODULE_LICENSE("GPL");