Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 94134bf8 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sched-cls_api-small-cleanup'



Jiri Pirko says:

====================
sched: cls_api: small cleanup

This patchset makes couple of things in cls_api code a bit nicer and easier
for reader to digest.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b4c4ebcf 40c81b25
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@ struct tcf_walker {
int register_tcf_proto_ops(struct tcf_proto_ops *ops);
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);

void tcf_destroy_chain(struct tcf_proto __rcu **fl);

static inline unsigned long
__cls_set_class(unsigned long *clp, unsigned long cl)
{
+0 −2
Original line number Diff line number Diff line
@@ -405,8 +405,6 @@ struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
				const struct Qdisc_ops *ops, u32 parentid);
void __qdisc_calculate_pkt_len(struct sk_buff *skb,
			       const struct qdisc_size_table *stab);
bool tcf_destroy(struct tcf_proto *tp, bool force);
void tcf_destroy_chain(struct tcf_proto __rcu **fl);
int skb_do_redirect(struct sk_buff *);

static inline void skb_reset_tc(struct sk_buff *skb)
+113 −78
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/kmod.h>
@@ -38,14 +39,14 @@ static DEFINE_RWLOCK(cls_mod_lock);

/* Find classifier type by string name */

static const struct tcf_proto_ops *tcf_proto_lookup_ops(struct nlattr *kind)
static const struct tcf_proto_ops *tcf_proto_lookup_ops(const char *kind)
{
	const struct tcf_proto_ops *t, *res = NULL;

	if (kind) {
		read_lock(&cls_mod_lock);
		list_for_each_entry(t, &tcf_proto_base, head) {
			if (nla_strcmp(kind, t->kind) == 0) {
			if (strcmp(kind, t->kind) == 0) {
				if (try_module_get(t->owner))
					res = t;
				break;
@@ -127,6 +128,77 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
	return first;
}

static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
					  u32 prio, u32 parent, struct Qdisc *q)
{
	struct tcf_proto *tp;
	int err;

	tp = kzalloc(sizeof(*tp), GFP_KERNEL);
	if (!tp)
		return ERR_PTR(-ENOBUFS);

	err = -ENOENT;
	tp->ops = tcf_proto_lookup_ops(kind);
	if (!tp->ops) {
#ifdef CONFIG_MODULES
		rtnl_unlock();
		request_module("cls_%s", kind);
		rtnl_lock();
		tp->ops = tcf_proto_lookup_ops(kind);
		/* We dropped the RTNL semaphore in order to perform
		 * the module load. So, even if we succeeded in loading
		 * the module we have to replay the request. We indicate
		 * this using -EAGAIN.
		 */
		if (tp->ops) {
			module_put(tp->ops->owner);
			err = -EAGAIN;
		} else {
			err = -ENOENT;
		}
		goto errout;
#endif
	}
	tp->classify = tp->ops->classify;
	tp->protocol = protocol;
	tp->prio = prio;
	tp->classid = parent;
	tp->q = q;

	err = tp->ops->init(tp);
	if (err) {
		module_put(tp->ops->owner);
		goto errout;
	}
	return tp;

errout:
	kfree(tp);
	return ERR_PTR(err);
}

static bool tcf_proto_destroy(struct tcf_proto *tp, bool force)
{
	if (tp->ops->destroy(tp, force)) {
		module_put(tp->ops->owner);
		kfree_rcu(tp, rcu);
		return true;
	}
	return false;
}

void tcf_destroy_chain(struct tcf_proto __rcu **fl)
{
	struct tcf_proto *tp;

	while ((tp = rtnl_dereference(*fl)) != NULL) {
		RCU_INIT_POINTER(*fl, tp->next);
		tcf_proto_destroy(tp, true);
	}
}
EXPORT_SYMBOL(tcf_destroy_chain);

/* Add/change/delete/get a filter node */

static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
@@ -142,8 +214,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
	struct Qdisc  *q;
	struct tcf_proto __rcu **back;
	struct tcf_proto __rcu **chain;
	struct tcf_proto *next;
	struct tcf_proto *tp;
	const struct tcf_proto_ops *tp_ops;
	const struct Qdisc_class_ops *cops;
	unsigned long cl;
	unsigned long fh;
@@ -222,9 +294,10 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)

	/* And the last stroke */
	chain = cops->tcf_chain(q, cl);
	if (chain == NULL) {
		err = -EINVAL;
	if (chain == NULL)
		goto errout;
	}
	if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
		tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER);
		tcf_destroy_chain(chain);
@@ -239,10 +312,13 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
		if (tp->prio >= prio) {
			if (tp->prio == prio) {
				if (!nprio ||
				    (tp->protocol != protocol && protocol))
				    (tp->protocol != protocol && protocol)) {
					err = -EINVAL;
					goto errout;
			} else
				}
			} else {
				tp = NULL;
			}
			break;
		}
	}
@@ -250,110 +326,69 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
	if (tp == NULL) {
		/* Proto-tcf does not exist, create new one */

		if (tca[TCA_KIND] == NULL || !protocol)
		if (tca[TCA_KIND] == NULL || !protocol) {
			err = -EINVAL;
			goto errout;
		}

		err = -ENOENT;
		if (n->nlmsg_type != RTM_NEWTFILTER ||
		    !(n->nlmsg_flags & NLM_F_CREATE))
			goto errout;


		/* Create new proto tcf */

		err = -ENOBUFS;
		tp = kzalloc(sizeof(*tp), GFP_KERNEL);
		if (tp == NULL)
			goto errout;
		    !(n->nlmsg_flags & NLM_F_CREATE)) {
			err = -ENOENT;
		tp_ops = tcf_proto_lookup_ops(tca[TCA_KIND]);
		if (tp_ops == NULL) {
#ifdef CONFIG_MODULES
			struct nlattr *kind = tca[TCA_KIND];
			char name[IFNAMSIZ];

			if (kind != NULL &&
			    nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
				rtnl_unlock();
				request_module("cls_%s", name);
				rtnl_lock();
				tp_ops = tcf_proto_lookup_ops(kind);
				/* We dropped the RTNL semaphore in order to
				 * perform the module load.  So, even if we
				 * succeeded in loading the module we have to
				 * replay the request.  We indicate this using
				 * -EAGAIN.
				 */
				if (tp_ops != NULL) {
					module_put(tp_ops->owner);
					err = -EAGAIN;
				}
			}
#endif
			kfree(tp);
			goto errout;
		}
		tp->ops = tp_ops;
		tp->protocol = protocol;
		tp->prio = nprio ? :
			       TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));
		tp->q = q;
		tp->classify = tp_ops->classify;
		tp->classid = parent;

		err = tp_ops->init(tp);
		if (err != 0) {
			module_put(tp_ops->owner);
			kfree(tp);
		if (!nprio)
			nprio = TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));

		tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
				      protocol, nprio, parent, q);
		if (IS_ERR(tp)) {
			err = PTR_ERR(tp);
			goto errout;
		}

		tp_created = 1;

	} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind))
	} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
		err = -EINVAL;
		goto errout;
	}

	fh = tp->ops->get(tp, t->tcm_handle);

	if (fh == 0) {
		if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
			struct tcf_proto *next = rtnl_dereference(tp->next);

			next = rtnl_dereference(tp->next);
			RCU_INIT_POINTER(*back, next);

			tfilter_notify(net, skb, n, tp, fh,
				       RTM_DELTFILTER, false);
			tcf_destroy(tp, true);
			tcf_proto_destroy(tp, true);
			err = 0;
			goto errout;
		}

		err = -ENOENT;
		if (n->nlmsg_type != RTM_NEWTFILTER ||
		    !(n->nlmsg_flags & NLM_F_CREATE))
		    !(n->nlmsg_flags & NLM_F_CREATE)) {
			err = -ENOENT;
			goto errout;
		}
	} else {
		switch (n->nlmsg_type) {
		case RTM_NEWTFILTER:
			err = -EEXIST;
			if (n->nlmsg_flags & NLM_F_EXCL) {
				if (tp_created)
					tcf_destroy(tp, true);
					tcf_proto_destroy(tp, true);
				err = -EEXIST;
				goto errout;
			}
			break;
		case RTM_DELTFILTER:
			err = tp->ops->delete(tp, fh);
			if (err == 0) {
				struct tcf_proto *next = rtnl_dereference(tp->next);

				tfilter_notify(net, skb, n, tp,
					       t->tcm_handle,
			if (err)
				goto errout;
			next = rtnl_dereference(tp->next);
			tfilter_notify(net, skb, n, tp, t->tcm_handle,
				       RTM_DELTFILTER, false);
				if (tcf_destroy(tp, false))
			if (tcf_proto_destroy(tp, false))
				RCU_INIT_POINTER(*back, next);
			}
			goto errout;
		case RTM_GETTFILTER:
			err = tfilter_notify(net, skb, n, tp, fh,
					     RTM_NEWTFILTER, true);
@@ -374,7 +409,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
		tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER, false);
	} else {
		if (tp_created)
			tcf_destroy(tp, true);
			tcf_proto_destroy(tp, true);
	}

errout:
+0 −22
Original line number Diff line number Diff line
@@ -1900,28 +1900,6 @@ int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
}
EXPORT_SYMBOL(tc_classify);

bool tcf_destroy(struct tcf_proto *tp, bool force)
{
	if (tp->ops->destroy(tp, force)) {
		module_put(tp->ops->owner);
		kfree_rcu(tp, rcu);
		return true;
	}

	return false;
}

void tcf_destroy_chain(struct tcf_proto __rcu **fl)
{
	struct tcf_proto *tp;

	while ((tp = rtnl_dereference(*fl)) != NULL) {
		RCU_INIT_POINTER(*fl, tp->next);
		tcf_destroy(tp, true);
	}
}
EXPORT_SYMBOL(tcf_destroy_chain);

#ifdef CONFIG_PROC_FS
static int psched_show(struct seq_file *seq, void *v)
{
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/file.h>		/* for fput */
#include <net/netlink.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>

/*
 * The ATM queuing discipline provides a framework for invoking classifiers
Loading