sch_api.c revision 1b34ec43c9b3de44a5420841ab293d1b2035a94c
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * net/sched/sch_api.c	Packet scheduler API.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		This program is free software; you can redistribute it and/or
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		modify it under the terms of the GNU General Public License
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		as published by the Free Software Foundation; either version
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		2 of the License, or (at your option) any later version.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes:
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Rani Assaf <rani@magic.metawire.com> :980802: JIFFIES and CPU clock sources are repaired.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Eduardo J. Blanco <ejbs@netlabs.com.uy> :990222: kmod support
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Jamal Hadi Salim <hadi@nortelnetworks.com>: 990601: ingress support
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kmod.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
294179477f637caa730626bd597fdf28c5bad73565Patrick McHardy#include <linux/hrtimer.h>
3025bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski#include <linux/lockdep.h>
315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h>
34b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev#include <net/sock.h>
35dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo#include <net/netlink.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
387316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int qdisc_notify(struct net *net, struct sk_buff *oskb,
397316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			struct nlmsghdr *n, u32 clid,
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct Qdisc *old, struct Qdisc *new);
417316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int tclass_notify(struct net *net, struct sk_buff *oskb,
427316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			 struct nlmsghdr *n, struct Qdisc *q,
437316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			 unsigned long cl, int event);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Short review.
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This file consists of two interrelated parts:
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   1. queueing disciplines manager frontend.
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   2. traffic classes manager frontend.
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Generally, queueing discipline ("qdisc") is a black box,
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   which is able to enqueue packets and to dequeue them (when
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   device is ready to send something) in order and at times
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   determined by algorithm hidden in it.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   qdisc's are divided to two categories:
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "queues", which have no internal structure visible from outside.
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "schedulers", which split all the packets to "traffic classes",
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     using "packet classifiers" (look at cls_api.c)
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   In turn, classes may have child qdiscs (as rule, queues)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   attached to them etc. etc. etc.
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   The goal of the routines in this file is to translate
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   information supplied by user in the form of handles
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to more intelligible for kernel form, to make some sanity
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   checks and part of work, which is common to all qdiscs
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   and to provide rtnetlink notifications.
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   All real intelligent work is done inside qdisc modules.
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Every discipline has two major routines: enqueue and dequeue.
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---dequeue
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   dequeue usually returns a skb to send. It is allowed to return NULL,
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   but it does not mean that queue is empty, it just means that
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   discipline does not want to send anything this time.
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Queue is really empty if q->q.qlen == 0.
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   For complicated disciplines with multiple queues q->q is not
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   real packet queue, but however q->q.qlen must be valid.
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---enqueue
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   enqueue returns 0, if packet was enqueued successfully.
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   If packet (this one or another one) was dropped, it returns
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   not zero error code.
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_DROP 	- this packet dropped
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: do not backoff, but wait until queue will clear.
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_CN	 	- probably this packet enqueued, but another one dropped.
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or ignore
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_POLICED	- dropped by police.
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or error to real-time apps.
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Auxiliary routines:
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10399c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski   ---peek
10499c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski
10599c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski   like dequeue but without removing a packet from the queue
10699c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---reset
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   returns qdisc to initial state: purge all buffers, clear all
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   timers, counters (except for statistics) etc.
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---init
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   initializes newly created qdisc.
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---destroy
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   destroys resources allocated by init and during lifetime of qdisc.
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---change
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   changes qdisc parameters.
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protects list of registered TC modules. It is pure SMP lock. */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_RWLOCK(qdisc_mod_lock);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Queueing disciplines manipulation.	*
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The list of all installed queueing disciplines. */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_ops *qdisc_base;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register/uregister queueing discipline */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint register_qdisc(struct Qdisc_ops *qops)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = -EEXIST;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strcmp(qops->id, q->id))
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->enqueue == NULL)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->enqueue = noop_qdisc_ops.enqueue;
15299c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski	if (qops->peek == NULL) {
15368fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski		if (qops->dequeue == NULL)
15499c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski			qops->peek = noop_qdisc_ops.peek;
15568fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski		else
15668fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski			goto out_einval;
15799c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski	}
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->dequeue == NULL)
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->dequeue = noop_qdisc_ops.dequeue;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16168fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski	if (qops->cl_ops) {
16268fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski		const struct Qdisc_class_ops *cops = qops->cl_ops;
16368fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski
1643e9e5a5921f4b7dc098a01d01e5972bebb36491eJarek Poplawski		if (!(cops->get && cops->put && cops->walk && cops->leaf))
16568fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski			goto out_einval;
16668fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski
16768fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski		if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf))
16868fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski			goto out_einval;
16968fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski	}
17068fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qops->next = NULL;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*qp = qops;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 0;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
17768fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski
17868fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawskiout_einval:
17968fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski	rc = -EINVAL;
18068fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski	goto out;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18262e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(register_qdisc);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint unregister_qdisc(struct Qdisc_ops *qops)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOENT;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
190cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next)
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q == qops)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q) {
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*qp = q->next;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q->next = NULL;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = 0;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20162e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(unregister_qdisc);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We know handle. Find qdisc among all qdisc's attached to device
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (root qdisc, all its children, children of children etc.)
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2076113b748fb9935399ec2bbca3a3dc82008f6167fHannes Ederstatic struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
2088123b421e8ed944671d7241323ed3198cccb4041David S. Miller{
2098123b421e8ed944671d7241323ed3198cccb4041David S. Miller	struct Qdisc *q;
2108123b421e8ed944671d7241323ed3198cccb4041David S. Miller
2118123b421e8ed944671d7241323ed3198cccb4041David S. Miller	if (!(root->flags & TCQ_F_BUILTIN) &&
2128123b421e8ed944671d7241323ed3198cccb4041David S. Miller	    root->handle == handle)
2138123b421e8ed944671d7241323ed3198cccb4041David S. Miller		return root;
2148123b421e8ed944671d7241323ed3198cccb4041David S. Miller
2158123b421e8ed944671d7241323ed3198cccb4041David S. Miller	list_for_each_entry(q, &root->list, list) {
2168123b421e8ed944671d7241323ed3198cccb4041David S. Miller		if (q->handle == handle)
2178123b421e8ed944671d7241323ed3198cccb4041David S. Miller			return q;
2188123b421e8ed944671d7241323ed3198cccb4041David S. Miller	}
2198123b421e8ed944671d7241323ed3198cccb4041David S. Miller	return NULL;
2208123b421e8ed944671d7241323ed3198cccb4041David S. Miller}
2218123b421e8ed944671d7241323ed3198cccb4041David S. Miller
222f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawskistatic void qdisc_list_add(struct Qdisc *q)
223f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski{
224f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawski	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
225af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy		list_add_tail(&q->list, &qdisc_dev(q)->qdisc->list);
226f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski}
227f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
228f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawskivoid qdisc_list_del(struct Qdisc *q)
229f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski{
230f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawski	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
231f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski		list_del(&q->list);
232f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski}
233f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek PoplawskiEXPORT_SYMBOL(qdisc_list_del);
234f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
235ead81cc5fc6d996db6afb20f211241612610a07aDavid S. Millerstruct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
237f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski	struct Qdisc *q;
238f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
239af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy	q = qdisc_match_from_root(dev->qdisc, handle);
240af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy	if (q)
241af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy		goto out;
242f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
24324824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	if (dev_ingress_queue(dev))
24424824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		q = qdisc_match_from_root(
24524824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			dev_ingress_queue(dev)->qdisc_sleeping,
24624824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			handle);
247f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawskiout:
248f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski	return q;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
25520fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops = p->ops->cl_ops;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cl = cops->get(p, classid);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(p, cl);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops->put(p, cl);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return leaf;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find queueing discipline by name */
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic struct Qdisc_ops *qdisc_lookup_ops(struct nlattr *kind)
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q = NULL;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind) {
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_lock(&qdisc_mod_lock);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (q = qdisc_base; q; q = q->next) {
2771e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy			if (nla_strcmp(kind, q->id) == 0) {
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!try_module_get(q->owner))
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					q = NULL;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_unlock(&qdisc_mod_lock);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return q;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct qdisc_rate_table *qdisc_rtab_list;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystruct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) {
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) == 0) {
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtab->refcnt++;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return rtab;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3015feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy	if (tab == NULL || r->rate == 0 || r->cell_log == 0 ||
3025feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy	    nla_len(tab) != TC_RTAB_SIZE)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rtab = kmalloc(sizeof(*rtab), GFP_KERNEL);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rtab) {
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->rate = *r;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->refcnt = 1;
3091e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		memcpy(rtab->data, nla_data(tab), 1024);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->next = qdisc_rtab_list;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_rtab_list = rtab;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rtab;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
31562e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_get_rtab);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qdisc_put_rtab(struct qdisc_rate_table *tab)
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab, **rtabp;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tab || --tab->refcnt)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
324cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	for (rtabp = &qdisc_rtab_list;
325cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	     (rtab = *rtabp) != NULL;
326cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	     rtabp = &rtab->next) {
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rtab == tab) {
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*rtabp = rtab->next;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(rtab);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33462e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_put_rtab);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
336175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic LIST_HEAD(qdisc_stab_list);
337175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic DEFINE_SPINLOCK(qdisc_stab_lock);
338175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
339175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = {
340175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	[TCA_STAB_BASE]	= { .len = sizeof(struct tc_sizespec) },
341175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	[TCA_STAB_DATA] = { .type = NLA_BINARY },
342175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna};
343175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
344175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt)
345175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
346175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct nlattr *tb[TCA_STAB_MAX + 1];
347175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab;
348175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct tc_sizespec *s;
349175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	unsigned int tsize = 0;
350175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	u16 *tab = NULL;
351175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int err;
352175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
353175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy);
354175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (err < 0)
355175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(err);
356175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!tb[TCA_STAB_BASE])
357175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-EINVAL);
358175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
359175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	s = nla_data(tb[TCA_STAB_BASE]);
360175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
361175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (s->tsize > 0) {
362175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (!tb[TCA_STAB_DATA])
363175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			return ERR_PTR(-EINVAL);
364175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		tab = nla_data(tb[TCA_STAB_DATA]);
365175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16);
366175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
367175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
36800093fab980d0a8950a64bdf9e346d0497b9a7e4Dan Carpenter	if (tsize != s->tsize || (!tab && tsize > 0))
369175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-EINVAL);
370175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
371f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_lock(&qdisc_stab_lock);
372175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
373175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	list_for_each_entry(stab, &qdisc_stab_list, list) {
374175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (memcmp(&stab->szopts, s, sizeof(*s)))
375175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			continue;
376175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16)))
377175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			continue;
378175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		stab->refcnt++;
379f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller		spin_unlock(&qdisc_stab_lock);
380175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return stab;
381175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
382175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
383f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_unlock(&qdisc_stab_lock);
384175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
385175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL);
386175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!stab)
387175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-ENOMEM);
388175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
389175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab->refcnt = 1;
390175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab->szopts = *s;
391175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tsize > 0)
392175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		memcpy(stab->data, tab, tsize * sizeof(u16));
393175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
394f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_lock(&qdisc_stab_lock);
395175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	list_add_tail(&stab->list, &qdisc_stab_list);
396f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_unlock(&qdisc_stab_lock);
397175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
398175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return stab;
399175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
400175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
401a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazetstatic void stab_kfree_rcu(struct rcu_head *head)
402a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet{
403a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	kfree(container_of(head, struct qdisc_size_table, rcu));
404a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet}
405a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet
406175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_put_stab(struct qdisc_size_table *tab)
407175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
408175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!tab)
409175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return;
410175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
411f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_lock(&qdisc_stab_lock);
412175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
413175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (--tab->refcnt == 0) {
414175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		list_del(&tab->list);
415a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet		call_rcu_bh(&tab->rcu, stab_kfree_rcu);
416175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
417175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
418f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_unlock(&qdisc_stab_lock);
419175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
420175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_put_stab);
421175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
422175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab)
423175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
424175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct nlattr *nest;
425175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
426175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	nest = nla_nest_start(skb, TCA_STAB);
4273aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy	if (nest == NULL)
4283aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy		goto nla_put_failure;
4291b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts))
4301b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
431175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	nla_nest_end(skb, nest);
432175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
433175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return skb->len;
434175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
435175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnanla_put_failure:
436175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return -1;
437175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
438175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
439a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazetvoid __qdisc_calculate_pkt_len(struct sk_buff *skb, const struct qdisc_size_table *stab)
440175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
441175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int pkt_len, slot;
442175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
443175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	pkt_len = skb->len + stab->szopts.overhead;
444175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(!stab->szopts.tsize))
445175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		goto out;
446175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
447175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	slot = pkt_len + stab->szopts.cell_align;
448175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(slot < 0))
449175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		slot = 0;
450175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
451175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	slot >>= stab->szopts.cell_log;
452175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (likely(slot < stab->szopts.tsize))
453175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = stab->data[slot];
454175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	else
455175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = stab->data[stab->szopts.tsize - 1] *
456175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				(slot / stab->szopts.tsize) +
457175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				stab->data[slot % stab->szopts.tsize];
458175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
459175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	pkt_len <<= stab->szopts.size_log;
460175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnaout:
461175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(pkt_len < 1))
462175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = 1;
463175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	qdisc_skb_cb(skb)->pkt_len = pkt_len;
464175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
465a2da570d62fcb9e8816f6920e1ec02c706b289faEric DumazetEXPORT_SYMBOL(__qdisc_calculate_pkt_len);
466175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
467b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawskivoid qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc)
468b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski{
469b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski	if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {
470cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		pr_warn("%s: %s qdisc %X: is non-work-conserving?\n",
471cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			txt, qdisc->ops->id, qdisc->handle >> 16);
472b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski		qdisc->flags |= TCQ_F_WARN_NONWC;
473b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski	}
474b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski}
475b00355db3f88d96810a60011a30cfb2c3469409dJarek PoplawskiEXPORT_SYMBOL(qdisc_warn_nonwc);
476b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski
4774179477f637caa730626bd597fdf28c5bad73565Patrick McHardystatic enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
4784179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4794179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,
4802fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller						 timer);
4814179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
482fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet	qdisc_unthrottled(wd->qdisc);
4838608db031b4d2932d645709e2cfe8fbcd91a7305David S. Miller	__netif_schedule(qdisc_root(wd->qdisc));
4841936502d00ae6c2aa3931c42f6cf54afaba094f2Stephen Hemminger
4854179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	return HRTIMER_NORESTART;
4864179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4874179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4884179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc)
4894179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4902fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
4912fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	wd->timer.function = qdisc_watchdog;
4924179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc = qdisc;
4934179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4944179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_init);
4954179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4964179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires)
4974179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4984179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	ktime_t time;
4994179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
5002540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski	if (test_bit(__QDISC_STATE_DEACTIVATED,
5012540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski		     &qdisc_root_sleeping(wd->qdisc)->state))
5022540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski		return;
5032540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski
504fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet	qdisc_throttled(wd->qdisc);
5054179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	time = ktime_set(0, 0);
506ca44d6e60f9de26281fda203f58b570e1748c015Jarek Poplawski	time = ktime_add_ns(time, PSCHED_TICKS2NS(expires));
5072fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS);
5084179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
5094179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_schedule);
5104179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
5114179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_cancel(struct qdisc_watchdog *wd)
5124179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
5132fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	hrtimer_cancel(&wd->timer);
514fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet	qdisc_unthrottled(wd->qdisc);
5154179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
5164179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_cancel);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
518a94f779f9d82eb2d758a8715eaae5df98e8dcb21Adrian Bunkstatic struct hlist_head *qdisc_class_hash_alloc(unsigned int n)
5196fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5206fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = n * sizeof(struct hlist_head), i;
5216fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_head *h;
5226fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5236fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (size <= PAGE_SIZE)
5246fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		h = kmalloc(size, GFP_KERNEL);
5256fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	else
5266fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		h = (struct hlist_head *)
5276fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			__get_free_pages(GFP_KERNEL, get_order(size));
5286fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5296fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (h != NULL) {
5306fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		for (i = 0; i < n; i++)
5316fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			INIT_HLIST_HEAD(&h[i]);
5326fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	}
5336fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	return h;
5346fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5356fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5366fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardystatic void qdisc_class_hash_free(struct hlist_head *h, unsigned int n)
5376fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5386fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = n * sizeof(struct hlist_head);
5396fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5406fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (size <= PAGE_SIZE)
5416fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		kfree(h);
5426fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	else
5436fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		free_pages((unsigned long)h, get_order(size));
5446fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5456fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5466fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_grow(struct Qdisc *sch, struct Qdisc_class_hash *clhash)
5476fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5486fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct Qdisc_class_common *cl;
5496fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_node *n, *next;
5506fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_head *nhash, *ohash;
5516fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int nsize, nmask, osize;
5526fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int i, h;
5536fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5546fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	/* Rehash when load factor exceeds 0.75 */
5556fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (clhash->hashelems * 4 <= clhash->hashsize * 3)
5566fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return;
5576fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nsize = clhash->hashsize * 2;
5586fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nmask = nsize - 1;
5596fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nhash = qdisc_class_hash_alloc(nsize);
5606fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (nhash == NULL)
5616fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return;
5626fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5636fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	ohash = clhash->hash;
5646fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	osize = clhash->hashsize;
5656fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5666fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	sch_tree_lock(sch);
5676fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	for (i = 0; i < osize; i++) {
5686fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		hlist_for_each_entry_safe(cl, n, next, &ohash[i], hnode) {
5696fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			h = qdisc_class_hash(cl->classid, nmask);
5706fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			hlist_add_head(&cl->hnode, &nhash[h]);
5716fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		}
5726fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	}
5736fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hash     = nhash;
5746fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashsize = nsize;
5756fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashmask = nmask;
5766fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	sch_tree_unlock(sch);
5776fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5786fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	qdisc_class_hash_free(ohash, osize);
5796fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5806fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_grow);
5816fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5826fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyint qdisc_class_hash_init(struct Qdisc_class_hash *clhash)
5836fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5846fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = 4;
5856fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5866fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hash = qdisc_class_hash_alloc(size);
5876fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (clhash->hash == NULL)
5886fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return -ENOMEM;
5896fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashsize  = size;
5906fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashmask  = size - 1;
5916fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems = 0;
5926fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	return 0;
5936fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5946fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_init);
5956fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5966fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_destroy(struct Qdisc_class_hash *clhash)
5976fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5986fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	qdisc_class_hash_free(clhash->hash, clhash->hashsize);
5996fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
6006fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_destroy);
6016fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
6026fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_insert(struct Qdisc_class_hash *clhash,
6036fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			     struct Qdisc_class_common *cl)
6046fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
6056fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int h;
6066fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
6076fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	INIT_HLIST_NODE(&cl->hnode);
6086fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	h = qdisc_class_hash(cl->classid, clhash->hashmask);
6096fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	hlist_add_head(&cl->hnode, &clhash->hash[h]);
6106fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems++;
6116fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
6126fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_insert);
6136fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
6146fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_remove(struct Qdisc_class_hash *clhash,
6156fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			     struct Qdisc_class_common *cl)
6166fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
6176fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	hlist_del(&cl->hnode);
6186fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems--;
6196fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
6206fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_remove);
6216fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
622fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet/* Allocate an unique handle from space managed by kernel
623fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet * Possible range is [8000-FFFF]:0000 (0x8000 values)
624fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet */
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 qdisc_alloc_handle(struct net_device *dev)
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
627fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet	int i = 0x8000;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u32 autohandle = TC_H_MAKE(0x80000000U, 0);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		autohandle += TC_H_MAKE(0x10000U, 0);
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (autohandle == TC_H_MAKE(TC_H_ROOT, 0))
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			autohandle = TC_H_MAKE(0x80000000U, 0);
634fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet		if (!qdisc_lookup(dev, autohandle))
635fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet			return autohandle;
636fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet		cond_resched();
637fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet	} while	(--i > 0);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
639fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet	return 0;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyvoid qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
64343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy{
64420fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops;
64543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	unsigned long cl;
64643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	u32 parentid;
64743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy
64843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	if (n == 0)
64943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		return;
65043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	while ((parentid = sch->parent)) {
651066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski		if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
652066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski			return;
653066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski
6545ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller		sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid));
655ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy		if (sch == NULL) {
656ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy			WARN_ON(parentid != TC_H_ROOT);
657ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy			return;
658ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy		}
65943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		cops = sch->ops->cl_ops;
66043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		if (cops->qlen_notify) {
66143effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cl = cops->get(sch, parentid);
66243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cops->qlen_notify(sch, cl);
66343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cops->put(sch, cl);
66443effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		}
66543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		sch->q.qlen -= n;
66643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	}
66743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy}
66843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyEXPORT_SYMBOL(qdisc_tree_decrease_qlen);
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6707316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void notify_and_destroy(struct net *net, struct sk_buff *skb,
6717316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			       struct nlmsghdr *n, u32 clid,
67299194cff398d056e5ee469647c294466c246c88aDavid S. Miller			       struct Qdisc *old, struct Qdisc *new)
67399194cff398d056e5ee469647c294466c246c88aDavid S. Miller{
67499194cff398d056e5ee469647c294466c246c88aDavid S. Miller	if (new || old)
6757316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		qdisc_notify(net, skb, n, clid, old, new);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6774d8863a29c4755a0461cd31b6865026187d6c43aDavid S. Miller	if (old)
67899194cff398d056e5ee469647c294466c246c88aDavid S. Miller		qdisc_destroy(old);
67999194cff398d056e5ee469647c294466c246c88aDavid S. Miller}
68099194cff398d056e5ee469647c294466c246c88aDavid S. Miller
68199194cff398d056e5ee469647c294466c246c88aDavid S. Miller/* Graft qdisc "new" to class "classid" of qdisc "parent" or
68299194cff398d056e5ee469647c294466c246c88aDavid S. Miller * to device "dev".
68399194cff398d056e5ee469647c294466c246c88aDavid S. Miller *
68499194cff398d056e5ee469647c294466c246c88aDavid S. Miller * When appropriate send a netlink notification using 'skb'
68599194cff398d056e5ee469647c294466c246c88aDavid S. Miller * and "n".
68699194cff398d056e5ee469647c294466c246c88aDavid S. Miller *
68799194cff398d056e5ee469647c294466c246c88aDavid S. Miller * On success, destroy old qdisc.
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
69199194cff398d056e5ee469647c294466c246c88aDavid S. Miller		       struct sk_buff *skb, struct nlmsghdr *n, u32 classid,
69299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		       struct Qdisc *new, struct Qdisc *old)
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
69499194cff398d056e5ee469647c294466c246c88aDavid S. Miller	struct Qdisc *q = old;
6957316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	struct net *net = dev_net(dev);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki	if (parent == NULL) {
69999194cff398d056e5ee469647c294466c246c88aDavid S. Miller		unsigned int i, num_q, ingress;
70099194cff398d056e5ee469647c294466c246c88aDavid S. Miller
70199194cff398d056e5ee469647c294466c246c88aDavid S. Miller		ingress = 0;
70299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		num_q = dev->num_tx_queues;
7038d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		if ((q && q->flags & TCQ_F_INGRESS) ||
7048d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		    (new && new->flags & TCQ_F_INGRESS)) {
70599194cff398d056e5ee469647c294466c246c88aDavid S. Miller			num_q = 1;
70699194cff398d056e5ee469647c294466c246c88aDavid S. Miller			ingress = 1;
70724824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			if (!dev_ingress_queue(dev))
70824824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet				return -ENOENT;
70999194cff398d056e5ee469647c294466c246c88aDavid S. Miller		}
71099194cff398d056e5ee469647c294466c246c88aDavid S. Miller
71199194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (dev->flags & IFF_UP)
71299194cff398d056e5ee469647c294466c246c88aDavid S. Miller			dev_deactivate(dev);
71399194cff398d056e5ee469647c294466c246c88aDavid S. Miller
7146ec1c69a8f6492fd25722f4762721921da074c12David S. Miller		if (new && new->ops->attach) {
7156ec1c69a8f6492fd25722f4762721921da074c12David S. Miller			new->ops->attach(new);
7166ec1c69a8f6492fd25722f4762721921da074c12David S. Miller			num_q = 0;
7176ec1c69a8f6492fd25722f4762721921da074c12David S. Miller		}
7186ec1c69a8f6492fd25722f4762721921da074c12David S. Miller
71999194cff398d056e5ee469647c294466c246c88aDavid S. Miller		for (i = 0; i < num_q; i++) {
72024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			struct netdev_queue *dev_queue = dev_ingress_queue(dev);
72199194cff398d056e5ee469647c294466c246c88aDavid S. Miller
72299194cff398d056e5ee469647c294466c246c88aDavid S. Miller			if (!ingress)
72399194cff398d056e5ee469647c294466c246c88aDavid S. Miller				dev_queue = netdev_get_tx_queue(dev, i);
72499194cff398d056e5ee469647c294466c246c88aDavid S. Miller
7258d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller			old = dev_graft_qdisc(dev_queue, new);
7268d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller			if (new && i > 0)
7278d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller				atomic_inc(&new->refcnt);
7288d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller
729036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			if (!ingress)
730036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski				qdisc_destroy(old);
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
73299194cff398d056e5ee469647c294466c246c88aDavid S. Miller
733036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski		if (!ingress) {
7347316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			notify_and_destroy(net, skb, n, classid,
7357316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff					   dev->qdisc, new);
736036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			if (new && !new->ops->attach)
737036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski				atomic_inc(&new->refcnt);
738036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			dev->qdisc = new ? : &noop_qdisc;
739036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski		} else {
7407316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			notify_and_destroy(net, skb, n, classid, old, new);
741036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski		}
742af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy
74399194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (dev->flags & IFF_UP)
74499194cff398d056e5ee469647c294466c246c88aDavid S. Miller			dev_activate(dev);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
74620fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet		const struct Qdisc_class_ops *cops = parent->ops->cl_ops;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
748c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy		err = -EOPNOTSUPP;
749c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy		if (cops && cops->graft) {
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long cl = cops->get(parent, classid);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cl) {
75299194cff398d056e5ee469647c294466c246c88aDavid S. Miller				err = cops->graft(parent, cl, new, &old);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cops->put(parent, cl);
754c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy			} else
755c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy				err = -ENOENT;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
75799194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (!err)
7587316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			notify_and_destroy(net, skb, n, classid, old, new);
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76325bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski/* lockdep annotation is needed for ingress; egress gets it only for name */
76425bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_tx_lock;
76525bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_rx_lock;
76625bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Allocate and initialize new qdisc.
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Parameters are passed via opt.
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *
774bb949fbd1878973c3539d9aecff52f284482a937David S. Millerqdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
77523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	     struct Qdisc *p, u32 parent, u32 handle,
77623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	     struct nlattr **tca, int *errp)
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
7791e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *kind = tca[TCA_KIND];
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *sch;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *ops;
782175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ops = qdisc_lookup_ops(kind);
78595a5afca4a8d2e1cb77e1d4bc6ff9f718dc32f7aJohannes Berg#ifdef CONFIG_MODULES
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL && kind != NULL) {
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char name[IFNAMSIZ];
7881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		if (nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* We dropped the RTNL semaphore in order to
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * perform the module load.  So, even if we
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * succeeded in loading the module we have to
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * tell the caller to replay the request.  We
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * indicate this using -EAGAIN.
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * We replay the request because the device may
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * go away in the mean time.
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_unlock();
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			request_module("sch_%s", name);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_lock();
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ops = qdisc_lookup_ops(kind);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ops != NULL) {
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* We will try again qdisc_lookup_ops,
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * so don't keep a reference.
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				module_put(ops->owner);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = -EAGAIN;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_out;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
813b9e2cc0f0e47ad351349156018ef8a365e9c6d25Jamal Hadi Salim	err = -ENOENT;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL)
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8175ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	sch = qdisc_alloc(dev_queue, ops);
8183d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (IS_ERR(sch)) {
8193d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		err = PTR_ERR(sch);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out2;
8213d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	}
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
823ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy	sch->parent = parent;
824ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy
8253d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (handle == TC_H_INGRESS) {
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->flags |= TCQ_F_INGRESS;
8273d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		handle = TC_H_MAKE(TC_H_INGRESS, 0);
82825bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski		lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock);
829fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy	} else {
830fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy		if (handle == 0) {
831fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			handle = qdisc_alloc_handle(dev);
832fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			err = -ENOMEM;
833fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			if (handle == 0)
834fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy				goto err_out3;
835fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy		}
83625bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski		lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8393d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	sch->handle = handle;
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) {
842175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (tca[TCA_STAB]) {
843175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			stab = qdisc_get_stab(tca[TCA_STAB]);
844175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			if (IS_ERR(stab)) {
845175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				err = PTR_ERR(stab);
8467c64b9f3f584008000cf3b960f25cd6a68fce191Jarek Poplawski				goto err_out4;
847175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			}
848a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet			rcu_assign_pointer(sch->stab, stab);
849175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		}
8501e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		if (tca[TCA_RATE]) {
851f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski			spinlock_t *root_lock;
852f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski
85323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			err = -EOPNOTSUPP;
85423bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			if (sch->flags & TCQ_F_MQROOT)
85523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy				goto err_out4;
85623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy
857f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski			if ((sch->parent != TC_H_ROOT) &&
85823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			    !(sch->flags & TCQ_F_INGRESS) &&
85923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			    (!p || !(p->flags & TCQ_F_MQROOT)))
860f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski				root_lock = qdisc_root_sleeping_lock(sch);
861f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski			else
862f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski				root_lock = qdisc_lock(sch);
863f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski
864023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf			err = gen_new_estimator(&sch->bstats, &sch->rate_est,
865f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski						root_lock, tca[TCA_RATE]);
86623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			if (err)
86723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy				goto err_out4;
868023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf		}
869f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
870f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski		qdisc_list_add(sch);
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sch;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out3:
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
8763d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	kfree((char *) sch - sch->padded);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out2:
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	module_put(ops->owner);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*errp = err;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
88223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy
88323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyerr_out4:
88423bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	/*
88523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	 * Any broken qdiscs that would require a ops->reset() here?
88623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	 * The qdisc was never in action so it shouldn't be necessary.
88723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	 */
888a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	qdisc_put_stab(rtnl_dereference(sch->stab));
88923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	if (ops->destroy)
89023bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy		ops->destroy(sch);
89123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	goto err_out3;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8941e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
896a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	struct qdisc_size_table *ostab, *stab = NULL;
897175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int err = 0;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
899175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tca[TCA_OPTIONS]) {
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sch->ops->change == NULL)
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
9021e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		err = sch->ops->change(sch, tca[TCA_OPTIONS]);
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
906175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
907175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tca[TCA_STAB]) {
908175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		stab = qdisc_get_stab(tca[TCA_STAB]);
909175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (IS_ERR(stab))
910175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			return PTR_ERR(stab);
911175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
912175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
913a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	ostab = rtnl_dereference(sch->stab);
914a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	rcu_assign_pointer(sch->stab, stab);
915a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	qdisc_put_stab(ostab);
916175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
91723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	if (tca[TCA_RATE]) {
91871bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		/* NB: ignores errors from replace_estimator
91971bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		   because change can't be undone. */
92023bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy		if (sch->flags & TCQ_F_MQROOT)
92123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			goto out;
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gen_replace_estimator(&sch->bstats, &sch->rate_est,
92371bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger					    qdisc_root_sleeping_lock(sch),
92471bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger					    tca[TCA_RATE]);
92523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	}
92623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyout:
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
930cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstruct check_loop_arg {
931cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	struct qdisc_walker	w;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc		*p;
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			depth;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w);
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop(struct Qdisc *q, struct Qdisc *p, int depth)
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg	arg;
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->cl_ops == NULL)
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.stop = arg.w.skip = arg.w.count = 0;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.fn = check_loop_fn;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.depth = depth;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.p = p;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->ops->cl_ops->walk(q, &arg.w);
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return arg.w.stop ? -ELOOP : 0;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w)
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
95720fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops = q->ops->cl_ops;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg *arg = (struct check_loop_arg *)w;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(q, cl);
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (leaf) {
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (leaf == arg->p || arg->depth > 7)
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ELOOP;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return check_loop(leaf, arg->p, arg->depth + 1);
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete/get qdisc.
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9753b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm = NLMSG_DATA(n);
9771e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid = tcm->tcm_parent;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *p = NULL;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
984cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	dev = __dev_get_by_index(net, tcm->tcm_ifindex);
985cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!dev)
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
9891e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
9901e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
9911e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) {
995cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				p = qdisc_lookup(dev, TC_H_MAJ(clid));
996cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (!p)
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
999cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			} else if (dev_ingress_queue(dev)) {
1000cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				q = dev_ingress_queue(dev)->qdisc_sleeping;
100110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki			}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
1003af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			q = dev->qdisc;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q)
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tcm->tcm_handle && q->handle != tcm->tcm_handle)
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1011cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		q = qdisc_lookup(dev, tcm->tcm_handle);
1012cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (!q)
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10161e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n->nlmsg_type == RTM_DELQDISC) {
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!clid)
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q->handle == 0)
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
1024cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		err = qdisc_graft(dev, p, skb, n, clid, NULL, q);
1025cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (err != 0)
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10287316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		qdisc_notify(net, skb, n, clid, NULL, q);
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1034cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * Create/change qdisc.
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10393b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
10411e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid;
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q, *p;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreplay:
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reinit, just in case something touches this. */
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(n);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clid = tcm->tcm_parent;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q = p = NULL;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1053cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	dev = __dev_get_by_index(net, tcm->tcm_ifindex);
1054cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!dev)
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10571e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
10581e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
10591e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
10601e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (clid != TC_H_INGRESS) {
1064cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				p = qdisc_lookup(dev, TC_H_MAJ(clid));
1065cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (!p)
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
1068cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			} else if (dev_ingress_queue_create(dev)) {
1069cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				q = dev_ingress_queue(dev)->qdisc_sleeping;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
1072af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			q = dev->qdisc;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* It may be default qdisc, ignore it */
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q && q->handle == 0)
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			q = NULL;
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) {
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tcm->tcm_handle) {
1081cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (q && !(n->nlmsg_flags & NLM_F_REPLACE))
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (TC_H_MIN(tcm->tcm_handle))
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
1085cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				q = qdisc_lookup(dev, tcm->tcm_handle);
1086cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (!q)
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
1088cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (n->nlmsg_flags & NLM_F_EXCL)
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
10901e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q == p ||
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (p && check_loop(q, p, 0)))
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ELOOP;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				atomic_inc(&q->refcnt);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto graft;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
1098cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (!q)
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* This magic test requires explanation.
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   We know, that some child q is already
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   attached to this parent and have choice:
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   either to change it or to create/graft new one.
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   1. We are allowed to create/graft only
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   if CREATE and REPLACE flags are set.
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   2. If EXCL is set, requestor wanted to say,
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   that qdisc tcm_handle is not expected
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   to exist, so that we choose create/graft too.
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   3. The last case is when no flags are set.
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   Alas, it is sort of hole in API, we
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   cannot decide what to do unambiguously.
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   For now we select create/graft, if
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   user gave KIND, which does not match existing.
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
1120cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if ((n->nlmsg_flags & NLM_F_CREATE) &&
1121cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				    (n->nlmsg_flags & NLM_F_REPLACE) &&
1122cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				    ((n->nlmsg_flags & NLM_F_EXCL) ||
11231e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				     (tca[TCA_KIND] &&
11241e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				      nla_strcmp(tca[TCA_KIND], q->ops->id))))
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!tcm->tcm_handle)
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = qdisc_lookup(dev, tcm->tcm_handle);
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Change qdisc parameters */
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL)
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
1137cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (n->nlmsg_flags & NLM_F_EXCL)
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EEXIST;
11391e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = qdisc_change(q, tca);
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
11437316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		qdisc_notify(net, skb, n, clid, NULL, q);
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscreate_n_graft:
1147cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!(n->nlmsg_flags & NLM_F_CREATE))
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
114924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	if (clid == TC_H_INGRESS) {
115024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		if (dev_ingress_queue(dev))
115124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			q = qdisc_create(dev, dev_ingress_queue(dev), p,
115224824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet					 tcm->tcm_parent, tcm->tcm_parent,
115324824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet					 tca, &err);
115424824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		else
115524824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			err = -ENOENT;
115624824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	} else {
1157926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		struct netdev_queue *dev_queue;
11586ec1c69a8f6492fd25722f4762721921da074c12David S. Miller
11596ec1c69a8f6492fd25722f4762721921da074c12David S. Miller		if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue)
1160926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski			dev_queue = p->ops->cl_ops->select_queue(p, tcm);
1161926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		else if (p)
1162926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski			dev_queue = p->dev_queue;
1163926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		else
1164926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski			dev_queue = netdev_get_tx_queue(dev, 0);
11656ec1c69a8f6492fd25722f4762721921da074c12David S. Miller
1166926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		q = qdisc_create(dev, dev_queue, p,
1167bb949fbd1878973c3539d9aecff52f284482a937David S. Miller				 tcm->tcm_parent, tcm->tcm_handle,
1168ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy				 tca, &err);
11696ec1c69a8f6492fd25722f4762721921da074c12David S. Miller	}
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL) {
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err == -EAGAIN)
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto replay;
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgraft:
1177e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen	err = qdisc_graft(dev, p, skb, n, clid, q, NULL);
1178e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen	if (err) {
1179e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen		if (q)
1180e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen			qdisc_destroy(q);
1181e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen		return err;
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1183e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
1188e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim			 u32 pid, u32 seq, u16 flags, int event)
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
119227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	unsigned char *b = skb_tail_pointer(skb);
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
1194a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	struct qdisc_size_table *stab;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1196e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(nlh);
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
11999ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad1 = 0;
12009ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad2 = 0;
12015ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = clid;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = atomic_read(&q->refcnt);
12051b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put_string(skb, TCA_KIND, q->ops->id))
12061b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump && q->ops->dump(q, skb) < 0)
12081e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->qstats.qlen = q->q.qlen;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	stab = rtnl_dereference(q->stab);
1212a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	if (stab && qdisc_dump_stab(skb, stab) < 0)
1213175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		goto nla_put_failure;
1214175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
1215102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
1216102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski					 qdisc_root_sleeping_lock(q), &d) < 0)
12171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0)
12201e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
1223d250a5f90e53f5e150618186230795352d154c88Eric Dumazet	    gnet_stats_copy_rate_est(&d, &q->bstats, &q->rate_est) < 0 ||
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    gnet_stats_copy_queue(&d, &q->qstats) < 0)
12251e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
122610297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
12281e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
122910297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
123027a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure:
12341e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
1235dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo	nlmsg_trim(skb, b);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
123953b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazetstatic bool tc_qdisc_dump_ignore(struct Qdisc *q)
124053b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet{
124153b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet	return (q->flags & TCQ_F_BUILTIN) ? true : false;
124253b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet}
124353b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet
12447316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int qdisc_notify(struct net *net, struct sk_buff *oskb,
12457316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			struct nlmsghdr *n, u32 clid,
12467316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			struct Qdisc *old, struct Qdisc *new)
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125553b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet	if (old && !tc_qdisc_dump_ignore(old)) {
1256cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq,
1257cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				  0, RTM_DELQDISC) < 0)
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
126053b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet	if (new && !tc_qdisc_dump_ignore(new)) {
1261cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq,
1262cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				  old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb->len)
1267cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		return rtnetlink_send(skb, net, pid, RTNLGRP_TC,
1268cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				      n->nlmsg_flags & NLM_F_ECHO);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12753072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
12763072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			      struct netlink_callback *cb,
12773072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			      int *q_idx_p, int s_q_idx)
12783072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
12793072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	int ret = 0, q_idx = *q_idx_p;
12803072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct Qdisc *q;
12813072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12823072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (!root)
12833072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
12843072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12853072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	q = root;
12863072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (q_idx < s_q_idx) {
12873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
12883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	} else {
12893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (!tc_qdisc_dump_ignore(q) &&
12903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		    tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
12913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
12923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
12933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
12943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
12953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	list_for_each_entry(q, &root->list, list) {
12963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (q_idx < s_q_idx) {
12973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			q_idx++;
12983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			continue;
12993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		}
1300cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (!tc_qdisc_dump_ignore(q) &&
13013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		    tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
13023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
13033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
13043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
13053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
13063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
13073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerout:
13083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	*q_idx_p = q_idx;
13093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return ret;
13103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone:
13113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	ret = -1;
13123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	goto out;
13133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
13143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13173b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx, q_idx;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int s_idx, s_q_idx;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_idx = cb->args[0];
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_q_idx = q_idx = cb->args[1];
1324f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger
1325f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger	rcu_read_lock();
13267562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov	idx = 0;
13277316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	for_each_netdev_rcu(net, dev) {
13283072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		struct netdev_queue *dev_queue;
13293072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx < s_idx)
13317562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov			goto cont;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx > s_idx)
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s_q_idx = 0;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q_idx = 0;
13353072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
1336af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy		if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0)
13373072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
13383072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
133924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		dev_queue = dev_ingress_queue(dev);
134024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		if (dev_queue &&
134124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		    tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb,
134224824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet				       &q_idx, s_q_idx) < 0)
13433072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
13443072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
13457562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianovcont:
13467562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov		idx++;
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
1350f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger	rcu_read_unlock();
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = idx;
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[1] = q_idx;
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Traffic classes manipulation.		*
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13683b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm = NLMSG_DATA(n);
13701e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
137320fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops;
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl = 0;
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long new_cl;
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = tcm->tcm_parent;
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid = tcm->tcm_handle;
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 qid = TC_H_MAJ(clid);
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	dev = __dev_get_by_index(net, tcm->tcm_ifindex);
1382cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!dev)
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13851e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
13861e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
13871e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
13881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_UNSPEC - unspecified parent.
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_ROOT   - class is root, which has no parent.
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:0	 - parent is root class.
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:Y	 - parent is a node in hierarchy.
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == 0:Y	 - parent is X:Y, where X:0 is qdisc.
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:0	 - generate handle from kernel pool.
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:Y	 - class is X:Y, where X:0 is qdisc.
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:Y	 - clear.
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:0	 - root class.
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Step 1. Determine qdisc handle X:0 */
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pid != TC_H_ROOT) {
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 qid1 = TC_H_MAJ(pid);
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid && qid1) {
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* If both majors are known, they must be identical. */
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (qid != qid1)
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EINVAL;
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid1) {
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qid = qid1;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid == 0)
1414af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			qid = dev->qdisc->handle;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Now qid is genuine qdisc handle consistent
1417cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		 * both with parent and child.
1418cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		 *
1419cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		 * TC_H_MAJ(pid) still may be unspecified, complete it now.
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pid)
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pid = TC_H_MAKE(qid, pid);
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid == 0)
1425af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			qid = dev->qdisc->handle;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* OK. Locate qdisc */
1429cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	q = qdisc_lookup(dev, qid);
1430cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!q)
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* An check that it supports classes */
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops = q->ops->cl_ops;
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now try to get class */
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid == 0) {
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pid == TC_H_ROOT)
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clid = qid;
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clid = TC_H_MAKE(qid, clid);
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid)
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cl = cops->get(q, clid);
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0) {
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOENT;
1450cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (n->nlmsg_type != RTM_NEWTCLASS ||
1451cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		    !(n->nlmsg_flags & NLM_F_CREATE))
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (n->nlmsg_type) {
145510297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki		case RTM_NEWTCLASS:
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EEXIST;
1457cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			if (n->nlmsg_flags & NLM_F_EXCL)
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_DELTCLASS:
1461de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy			err = -EOPNOTSUPP;
1462de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy			if (cops->delete)
1463de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy				err = cops->delete(q, cl);
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (err == 0)
14657316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff				tclass_notify(net, skb, n, q, cl, RTM_DELTCLASS);
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_GETTCLASS:
14687316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS);
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EINVAL;
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_cl = cl;
1477de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy	err = -EOPNOTSUPP;
1478de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy	if (cops->change)
1479de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy		err = cops->change(q, clid, pid, tca, &new_cl);
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
14817316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS);
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl)
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cops->put(q, cl);
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  unsigned long cl,
1493e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim			  u32 pid, u32 seq, u16 flags, int event)
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
149727a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	unsigned char *b = skb_tail_pointer(skb);
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
149920fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops;
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(nlh);
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
150416ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet	tcm->tcm__pad1 = 0;
150516ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet	tcm->tcm__pad2 = 0;
15065ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = q->handle;
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = 0;
15101b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put_string(skb, TCA_KIND, q->ops->id))
15111b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0)
15131e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1515102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
1516102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski					 qdisc_root_sleeping_lock(q), &d) < 0)
15171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0)
15201e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
15231e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152527a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure:
15291e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
1530dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo	nlmsg_trim(skb, b);
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15347316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int tclass_notify(struct net *net, struct sk_buff *oskb,
15357316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			 struct nlmsghdr *n, struct Qdisc *q,
15367316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			 unsigned long cl, int event)
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tc_fill_tclass(skb, q, cl, pid, n->nlmsg_seq, 0, event) < 0) {
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1550cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	return rtnetlink_send(skb, net, pid, RTNLGRP_TC,
1551cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			      n->nlmsg_flags & NLM_F_ECHO);
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1554cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstruct qdisc_dump_args {
1555cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	struct qdisc_walker	w;
1556cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	struct sk_buff		*skb;
1557cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	struct netlink_callback	*cb;
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg)
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_dump_args *a = (struct qdisc_dump_args *)arg;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tc_fill_tclass(a->skb, q, cl, NETLINK_CB(a->cb->skb).pid,
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS);
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15683072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb,
15693072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				struct tcmsg *tcm, struct netlink_callback *cb,
15703072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				int *t_p, int s_t)
15713072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
15723072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct qdisc_dump_args arg;
15733072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15743072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (tc_qdisc_dump_ignore(q) ||
15753072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	    *t_p < s_t || !q->ops->cl_ops ||
15763072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	    (tcm->tcm_parent &&
15773072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	     TC_H_MAJ(tcm->tcm_parent) != q->handle)) {
15783072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		(*t_p)++;
15793072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
15803072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
15813072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (*t_p > s_t)
15823072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
15833072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.fn = qdisc_class_dump;
15843072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.skb = skb;
15853072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.cb = cb;
15863072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.stop  = 0;
15873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.skip = cb->args[1];
15883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.count = 0;
15893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	q->ops->cl_ops->walk(q, &arg.w);
15903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	cb->args[1] = arg.w.count;
15913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (arg.w.stop)
15923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return -1;
15933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	(*t_p)++;
15943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return 0;
15953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
15963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb,
15983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			       struct tcmsg *tcm, struct netlink_callback *cb,
15993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			       int *t_p, int s_t)
16003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
16013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct Qdisc *q;
16023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (!root)
16043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
16053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0)
16073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return -1;
16083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	list_for_each_entry(q, &root->list, list) {
16103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0)
16113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			return -1;
16123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
16133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return 0;
16153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
16163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1619cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	struct tcmsg *tcm = (struct tcmsg *)NLMSG_DATA(cb->nlh);
16203b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
16213072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct netdev_queue *dev_queue;
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
16233072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	int t, s_t;
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1627cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	dev = dev_get_by_index(net, tcm->tcm_ifindex);
1628cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!dev)
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_t = cb->args[0];
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t = 0;
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1634af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy	if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0)
16353072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		goto done;
16363072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
163724824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	dev_queue = dev_ingress_queue(dev);
163824824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	if (dev_queue &&
163924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	    tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb,
164024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet				&t, s_t) < 0)
16413072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		goto done;
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16433072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone:
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = t;
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Main classifier routine: scans classifier chain attached
1651cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * to this qdisc, (optionally) tests for protocol and asks
1652cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * specific classifiers.
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1654dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazetint tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp,
165573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		       struct tcf_result *res)
165673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy{
165773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	__be16 protocol = skb->protocol;
1658cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	int err;
165973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
166073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	for (; tp; tp = tp->next) {
1661cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (tp->protocol != protocol &&
1662cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		    tp->protocol != htons(ETH_P_ALL))
1663cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			continue;
1664cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		err = tp->classify(skb, tp, res);
1665cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet
1666cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (err >= 0) {
166773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#ifdef CONFIG_NET_CLS_ACT
166873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			if (err != TC_ACT_RECLASSIFY && skb->tc_verd)
166973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy				skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0);
167073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif
167173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			return err;
167273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		}
167373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	}
167473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	return -1;
167573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy}
167673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify_compat);
167773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
1678dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazetint tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
167973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		struct tcf_result *res)
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
1683dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazet	const struct tcf_proto *otp = tp;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreclassify:
168552bc97470e22e67f11b054e51a31eee100ef6867Hagen Paul Pfeifer#endif
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
168773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	err = tc_classify_compat(skb, tp, res);
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
168973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	if (err == TC_ACT_RECLASSIFY) {
169073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		u32 verd = G_TC_VERD(skb->tc_verd);
169173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		tp = otp;
169273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
169373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		if (verd++ >= MAX_REC_LOOP) {
1694b60b6592baa69c43a5a0f55d6300a7feaab15338stephen hemminger			if (net_ratelimit())
1695cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				pr_notice("%s: packet reclassify loop"
1696b60b6592baa69c43a5a0f55d6300a7feaab15338stephen hemminger					  " rule prio %u protocol %02x\n",
1697cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet					  tp->q->ops->id,
1698cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet					  tp->prio & 0xffff,
1699cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet					  ntohs(tp->protocol));
170073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			return TC_ACT_SHOT;
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
170273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd);
170373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		goto reclassify;
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
170573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif
170673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	return err;
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
170873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify);
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1710a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyvoid tcf_destroy(struct tcf_proto *tp)
1711a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{
1712a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	tp->ops->destroy(tp);
1713a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	module_put(tp->ops->owner);
1714a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	kfree(tp);
1715a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy}
1716a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
1717ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardyvoid tcf_destroy_chain(struct tcf_proto **fl)
1718a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{
1719a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	struct tcf_proto *tp;
1720a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
1721ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy	while ((tp = *fl) != NULL) {
1722ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy		*fl = tp->next;
1723a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy		tcf_destroy(tp);
1724a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	}
1725a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy}
1726a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyEXPORT_SYMBOL(tcf_destroy_chain);
1727a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_show(struct seq_file *seq, void *v)
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17313c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy	struct timespec ts;
17323c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy
17333c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy	hrtimer_get_res(CLOCK_MONOTONIC, &ts);
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_printf(seq, "%08x %08x %08x %08x\n",
1735ca44d6e60f9de26281fda203f58b570e1748c015Jarek Poplawski		   (u32)NSEC_PER_USEC, (u32)PSCHED_TICKS2NS(1),
1736514bca322cb9220308d22691ac1e74038bfabac3Patrick McHardy		   1000000,
17373c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy		   (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts)));
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_open(struct inode *inode, struct file *file)
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17447e5ab157813993356f021757d0b0dcbdca7c55a1Tom Goff	return single_open(file, psched_show, NULL);
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1747da7071d7e32d15149cc513f096a3638097b66387Arjan van de Venstatic const struct file_operations psched_fops = {
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner = THIS_MODULE,
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = psched_open,
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read  = seq_read,
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek = seq_lseek,
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release = single_release,
175310297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki};
17547316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17557316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int __net_init psched_net_init(struct net *net)
17567316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{
17577316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	struct proc_dir_entry *e;
17587316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17597316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	e = proc_net_fops_create(net, "psched", 0, &psched_fops);
17607316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	if (e == NULL)
17617316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		return -ENOMEM;
17627316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17637316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	return 0;
17647316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}
17657316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17667316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void __net_exit psched_net_exit(struct net *net)
17677316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{
17687316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	proc_net_remove(net, "psched");
17697316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}
17707316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff#else
17717316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int __net_init psched_net_init(struct net *net)
17727316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{
17737316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	return 0;
17747316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}
17757316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17767316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void __net_exit psched_net_exit(struct net *net)
17777316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{
17787316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17817316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic struct pernet_operations psched_net_ops = {
17827316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	.init = psched_net_init,
17837316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	.exit = psched_net_exit,
17847316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff};
17857316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pktsched_init(void)
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17887316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	int err;
17897316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17907316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	err = register_pernet_subsys(&psched_net_ops);
17917316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	if (err) {
1792cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		pr_err("pktsched_init: "
17937316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		       "cannot initialize per netns operations\n");
17947316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		return err;
17957316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	}
17967316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&pfifo_qdisc_ops);
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&bfifo_qdisc_ops);
179957dbb2d83d100ea601c54fe129bfde0678db5deeHagen Paul Pfeifer	register_qdisc(&pfifo_head_drop_qdisc_ops);
18006ec1c69a8f6492fd25722f4762721921da074c12David S. Miller	register_qdisc(&mq_qdisc_ops);
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1802c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL, NULL);
1803c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL, NULL);
1804c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc, NULL);
1805c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL, NULL);
1806c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL, NULL);
1807c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass, NULL);
1808be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(pktsched_init);
1813