sch_api.c revision 4d8863a29c4755a0461cd31b6865026187d6c43a
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>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h>
33b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev#include <net/sock.h>
34dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo#include <net/netlink.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid,
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct Qdisc *old, struct Qdisc *new);
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 struct Qdisc *q, unsigned long cl, int event);
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Short review.
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This file consists of two interrelated parts:
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   1. queueing disciplines manager frontend.
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   2. traffic classes manager frontend.
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Generally, queueing discipline ("qdisc") is a black box,
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   which is able to enqueue packets and to dequeue them (when
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   device is ready to send something) in order and at times
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   determined by algorithm hidden in it.
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   qdisc's are divided to two categories:
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "queues", which have no internal structure visible from outside.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "schedulers", which split all the packets to "traffic classes",
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     using "packet classifiers" (look at cls_api.c)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   In turn, classes may have child qdiscs (as rule, queues)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   attached to them etc. etc. etc.
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   The goal of the routines in this file is to translate
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   information supplied by user in the form of handles
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to more intelligible for kernel form, to make some sanity
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   checks and part of work, which is common to all qdiscs
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   and to provide rtnetlink notifications.
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   All real intelligent work is done inside qdisc modules.
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Every discipline has two major routines: enqueue and dequeue.
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---dequeue
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   dequeue usually returns a skb to send. It is allowed to return NULL,
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   but it does not mean that queue is empty, it just means that
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   discipline does not want to send anything this time.
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Queue is really empty if q->q.qlen == 0.
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   For complicated disciplines with multiple queues q->q is not
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   real packet queue, but however q->q.qlen must be valid.
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---enqueue
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   enqueue returns 0, if packet was enqueued successfully.
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   If packet (this one or another one) was dropped, it returns
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   not zero error code.
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_DROP 	- this packet dropped
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: do not backoff, but wait until queue will clear.
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_CN	 	- probably this packet enqueued, but another one dropped.
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or ignore
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_POLICED	- dropped by police.
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or error to real-time apps.
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Auxiliary routines:
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---requeue
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   requeues once dequeued packet. It is used for non-standard or
103e65d22e18038eed7307276e46810d884c402d57dDavid S. Miller   just buggy devices, which can defer output even if netif_queue_stopped()=0.
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---reset
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   returns qdisc to initial state: purge all buffers, clear all
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   timers, counters (except for statistics) etc.
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---init
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   initializes newly created qdisc.
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---destroy
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   destroys resources allocated by init and during lifetime of qdisc.
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---change
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   changes qdisc parameters.
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protects list of registered TC modules. It is pure SMP lock. */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_RWLOCK(qdisc_mod_lock);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Queueing disciplines manipulation.	*
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The list of all installed queueing disciplines. */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_ops *qdisc_base;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register/uregister queueing discipline */
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint register_qdisc(struct Qdisc_ops *qops)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = -EEXIST;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strcmp(qops->id, q->id))
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->enqueue == NULL)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->enqueue = noop_qdisc_ops.enqueue;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->requeue == NULL)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->requeue = noop_qdisc_ops.requeue;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->dequeue == NULL)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->dequeue = noop_qdisc_ops.dequeue;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qops->next = NULL;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*qp = qops;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 0;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16262e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(register_qdisc);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint unregister_qdisc(struct Qdisc_ops *qops)
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOENT;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next)
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q == qops)
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q) {
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*qp = q->next;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q->next = NULL;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = 0;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18162e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(unregister_qdisc);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We know handle. Find qdisc among all qdisc's attached to device
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (root qdisc, all its children, children of children etc.)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1878123b421e8ed944671d7241323ed3198cccb4041David S. Millerstruct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
1888123b421e8ed944671d7241323ed3198cccb4041David S. Miller{
1898123b421e8ed944671d7241323ed3198cccb4041David S. Miller	struct Qdisc *q;
1908123b421e8ed944671d7241323ed3198cccb4041David S. Miller
1918123b421e8ed944671d7241323ed3198cccb4041David S. Miller	if (!(root->flags & TCQ_F_BUILTIN) &&
1928123b421e8ed944671d7241323ed3198cccb4041David S. Miller	    root->handle == handle)
1938123b421e8ed944671d7241323ed3198cccb4041David S. Miller		return root;
1948123b421e8ed944671d7241323ed3198cccb4041David S. Miller
1958123b421e8ed944671d7241323ed3198cccb4041David S. Miller	list_for_each_entry(q, &root->list, list) {
1968123b421e8ed944671d7241323ed3198cccb4041David S. Miller		if (q->handle == handle)
1978123b421e8ed944671d7241323ed3198cccb4041David S. Miller			return q;
1988123b421e8ed944671d7241323ed3198cccb4041David S. Miller	}
1998123b421e8ed944671d7241323ed3198cccb4041David S. Miller	return NULL;
2008123b421e8ed944671d7241323ed3198cccb4041David S. Miller}
2018123b421e8ed944671d7241323ed3198cccb4041David S. Miller
202ead81cc5fc6d996db6afb20f211241612610a07aDavid S. Millerstruct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	unsigned int i;
2053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
2063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	for (i = 0; i < dev->num_tx_queues; i++) {
2073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
208827ebd6410005b05b3c930ef6a116666c6986886David S. Miller		struct Qdisc *q, *txq_root = txq->qdisc_sleeping;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2108123b421e8ed944671d7241323ed3198cccb4041David S. Miller		q = qdisc_match_from_root(txq_root, handle);
2118123b421e8ed944671d7241323ed3198cccb4041David S. Miller		if (q)
2128123b421e8ed944671d7241323ed3198cccb4041David S. Miller			return q;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2148123b421e8ed944671d7241323ed3198cccb4041David S. Miller	return qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
22120fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops = p->ops->cl_ops;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cl = cops->get(p, classid);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(p, cl);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops->put(p, cl);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return leaf;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find queueing discipline by name */
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic struct Qdisc_ops *qdisc_lookup_ops(struct nlattr *kind)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q = NULL;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind) {
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_lock(&qdisc_mod_lock);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (q = qdisc_base; q; q = q->next) {
2431e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy			if (nla_strcmp(kind, q->id) == 0) {
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!try_module_get(q->owner))
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					q = NULL;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_unlock(&qdisc_mod_lock);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return q;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct qdisc_rate_table *qdisc_rtab_list;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystruct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) {
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) == 0) {
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtab->refcnt++;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return rtab;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2675feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy	if (tab == NULL || r->rate == 0 || r->cell_log == 0 ||
2685feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy	    nla_len(tab) != TC_RTAB_SIZE)
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rtab = kmalloc(sizeof(*rtab), GFP_KERNEL);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rtab) {
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->rate = *r;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->refcnt = 1;
2751e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		memcpy(rtab->data, nla_data(tab), 1024);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->next = qdisc_rtab_list;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_rtab_list = rtab;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rtab;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
28162e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_get_rtab);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qdisc_put_rtab(struct qdisc_rate_table *tab)
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab, **rtabp;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tab || --tab->refcnt)
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (rtabp = &qdisc_rtab_list; (rtab=*rtabp) != NULL; rtabp = &rtab->next) {
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rtab == tab) {
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*rtabp = rtab->next;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(rtab);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
29862e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_put_rtab);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
300175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic LIST_HEAD(qdisc_stab_list);
301175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic DEFINE_SPINLOCK(qdisc_stab_lock);
302175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
303175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = {
304175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	[TCA_STAB_BASE]	= { .len = sizeof(struct tc_sizespec) },
305175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	[TCA_STAB_DATA] = { .type = NLA_BINARY },
306175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna};
307175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
308175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt)
309175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
310175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct nlattr *tb[TCA_STAB_MAX + 1];
311175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab;
312175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct tc_sizespec *s;
313175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	unsigned int tsize = 0;
314175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	u16 *tab = NULL;
315175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int err;
316175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
317175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy);
318175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (err < 0)
319175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(err);
320175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!tb[TCA_STAB_BASE])
321175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-EINVAL);
322175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
323175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	s = nla_data(tb[TCA_STAB_BASE]);
324175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
325175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (s->tsize > 0) {
326175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (!tb[TCA_STAB_DATA])
327175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			return ERR_PTR(-EINVAL);
328175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		tab = nla_data(tb[TCA_STAB_DATA]);
329175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16);
330175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
331175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
332175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!s || tsize != s->tsize || (!tab && tsize > 0))
333175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-EINVAL);
334175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
3351cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski	spin_lock_bh(&qdisc_stab_lock);
336175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
337175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	list_for_each_entry(stab, &qdisc_stab_list, list) {
338175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (memcmp(&stab->szopts, s, sizeof(*s)))
339175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			continue;
340175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16)))
341175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			continue;
342175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		stab->refcnt++;
3431cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski		spin_unlock_bh(&qdisc_stab_lock);
344175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return stab;
345175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
346175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
3471cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski	spin_unlock_bh(&qdisc_stab_lock);
348175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
349175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL);
350175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!stab)
351175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-ENOMEM);
352175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
353175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab->refcnt = 1;
354175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab->szopts = *s;
355175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tsize > 0)
356175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		memcpy(stab->data, tab, tsize * sizeof(u16));
357175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
3581cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski	spin_lock_bh(&qdisc_stab_lock);
359175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	list_add_tail(&stab->list, &qdisc_stab_list);
3601cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski	spin_unlock_bh(&qdisc_stab_lock);
361175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
362175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return stab;
363175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
364175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
365175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_put_stab(struct qdisc_size_table *tab)
366175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
367175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!tab)
368175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return;
369175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
3701cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski	spin_lock_bh(&qdisc_stab_lock);
371175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
372175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (--tab->refcnt == 0) {
373175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		list_del(&tab->list);
374175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		kfree(tab);
375175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
376175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
3771cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski	spin_unlock_bh(&qdisc_stab_lock);
378175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
379175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_put_stab);
380175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
381175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab)
382175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
383175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct nlattr *nest;
384175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
385175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	nest = nla_nest_start(skb, TCA_STAB);
386175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	NLA_PUT(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts);
387175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	nla_nest_end(skb, nest);
388175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
389175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return skb->len;
390175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
391175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnanla_put_failure:
392175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return -1;
393175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
394175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
395175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_calculate_pkt_len(struct sk_buff *skb, struct qdisc_size_table *stab)
396175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
397175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int pkt_len, slot;
398175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
399175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	pkt_len = skb->len + stab->szopts.overhead;
400175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(!stab->szopts.tsize))
401175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		goto out;
402175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
403175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	slot = pkt_len + stab->szopts.cell_align;
404175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(slot < 0))
405175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		slot = 0;
406175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
407175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	slot >>= stab->szopts.cell_log;
408175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (likely(slot < stab->szopts.tsize))
409175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = stab->data[slot];
410175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	else
411175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = stab->data[stab->szopts.tsize - 1] *
412175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				(slot / stab->szopts.tsize) +
413175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				stab->data[slot % stab->szopts.tsize];
414175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
415175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	pkt_len <<= stab->szopts.size_log;
416175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnaout:
417175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(pkt_len < 1))
418175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = 1;
419175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	qdisc_skb_cb(skb)->pkt_len = pkt_len;
420175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
421175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_calculate_pkt_len);
422175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
4234179477f637caa730626bd597fdf28c5bad73565Patrick McHardystatic enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
4244179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4254179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,
4264179477f637caa730626bd597fdf28c5bad73565Patrick McHardy						 timer);
4274179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4284179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc->flags &= ~TCQ_F_THROTTLED;
42911274e5a43266d531140530adebead6903380cafStephen Hemminger	smp_wmb();
4308608db031b4d2932d645709e2cfe8fbcd91a7305David S. Miller	__netif_schedule(qdisc_root(wd->qdisc));
4311936502d00ae6c2aa3931c42f6cf54afaba094f2Stephen Hemminger
4324179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	return HRTIMER_NORESTART;
4334179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4344179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4354179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc)
4364179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4374179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
4384179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->timer.function = qdisc_watchdog;
4394179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc = qdisc;
4404179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4414179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_init);
4424179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4434179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires)
4444179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4454179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	ktime_t time;
4464179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4474179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc->flags |= TCQ_F_THROTTLED;
4484179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	time = ktime_set(0, 0);
4494179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	time = ktime_add_ns(time, PSCHED_US2NS(expires));
4504179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS);
4514179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4524179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_schedule);
4534179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4544179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_cancel(struct qdisc_watchdog *wd)
4554179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4564179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	hrtimer_cancel(&wd->timer);
4574179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc->flags &= ~TCQ_F_THROTTLED;
4584179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4594179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_cancel);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461a94f779f9d82eb2d758a8715eaae5df98e8dcb21Adrian Bunkstatic struct hlist_head *qdisc_class_hash_alloc(unsigned int n)
4626fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
4636fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = n * sizeof(struct hlist_head), i;
4646fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_head *h;
4656fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
4666fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (size <= PAGE_SIZE)
4676fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		h = kmalloc(size, GFP_KERNEL);
4686fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	else
4696fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		h = (struct hlist_head *)
4706fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			__get_free_pages(GFP_KERNEL, get_order(size));
4716fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
4726fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (h != NULL) {
4736fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		for (i = 0; i < n; i++)
4746fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			INIT_HLIST_HEAD(&h[i]);
4756fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	}
4766fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	return h;
4776fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
4786fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
4796fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardystatic void qdisc_class_hash_free(struct hlist_head *h, unsigned int n)
4806fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
4816fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = n * sizeof(struct hlist_head);
4826fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
4836fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (size <= PAGE_SIZE)
4846fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		kfree(h);
4856fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	else
4866fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		free_pages((unsigned long)h, get_order(size));
4876fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
4886fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
4896fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_grow(struct Qdisc *sch, struct Qdisc_class_hash *clhash)
4906fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
4916fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct Qdisc_class_common *cl;
4926fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_node *n, *next;
4936fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_head *nhash, *ohash;
4946fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int nsize, nmask, osize;
4956fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int i, h;
4966fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
4976fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	/* Rehash when load factor exceeds 0.75 */
4986fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (clhash->hashelems * 4 <= clhash->hashsize * 3)
4996fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return;
5006fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nsize = clhash->hashsize * 2;
5016fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nmask = nsize - 1;
5026fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nhash = qdisc_class_hash_alloc(nsize);
5036fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (nhash == NULL)
5046fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return;
5056fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5066fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	ohash = clhash->hash;
5076fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	osize = clhash->hashsize;
5086fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5096fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	sch_tree_lock(sch);
5106fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	for (i = 0; i < osize; i++) {
5116fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		hlist_for_each_entry_safe(cl, n, next, &ohash[i], hnode) {
5126fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			h = qdisc_class_hash(cl->classid, nmask);
5136fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			hlist_add_head(&cl->hnode, &nhash[h]);
5146fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		}
5156fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	}
5166fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hash     = nhash;
5176fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashsize = nsize;
5186fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashmask = nmask;
5196fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	sch_tree_unlock(sch);
5206fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5216fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	qdisc_class_hash_free(ohash, osize);
5226fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5236fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_grow);
5246fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5256fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyint qdisc_class_hash_init(struct Qdisc_class_hash *clhash)
5266fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5276fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = 4;
5286fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5296fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hash = qdisc_class_hash_alloc(size);
5306fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (clhash->hash == NULL)
5316fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return -ENOMEM;
5326fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashsize  = size;
5336fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashmask  = size - 1;
5346fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems = 0;
5356fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	return 0;
5366fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5376fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_init);
5386fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5396fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_destroy(struct Qdisc_class_hash *clhash)
5406fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5416fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	qdisc_class_hash_free(clhash->hash, clhash->hashsize);
5426fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5436fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_destroy);
5446fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5456fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_insert(struct Qdisc_class_hash *clhash,
5466fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			     struct Qdisc_class_common *cl)
5476fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5486fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int h;
5496fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5506fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	INIT_HLIST_NODE(&cl->hnode);
5516fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	h = qdisc_class_hash(cl->classid, clhash->hashmask);
5526fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	hlist_add_head(&cl->hnode, &clhash->hash[h]);
5536fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems++;
5546fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5556fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_insert);
5566fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5576fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_remove(struct Qdisc_class_hash *clhash,
5586fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			     struct Qdisc_class_common *cl)
5596fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5606fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	hlist_del(&cl->hnode);
5616fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems--;
5626fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5636fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_remove);
5646fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Allocate an unique handle from space managed by kernel */
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 qdisc_alloc_handle(struct net_device *dev)
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0x10000;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u32 autohandle = TC_H_MAKE(0x80000000U, 0);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		autohandle += TC_H_MAKE(0x10000U, 0);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (autohandle == TC_H_MAKE(TC_H_ROOT, 0))
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			autohandle = TC_H_MAKE(0x80000000U, 0);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while	(qdisc_lookup(dev, autohandle) && --i > 0);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i>0 ? autohandle : 0;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
58199194cff398d056e5ee469647c294466c246c88aDavid S. Miller/* Attach toplevel qdisc to device queue. */
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
58399194cff398d056e5ee469647c294466c246c88aDavid S. Millerstatic struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
58499194cff398d056e5ee469647c294466c246c88aDavid S. Miller				     struct Qdisc *qdisc)
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5868d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller	struct Qdisc *oqdisc = dev_queue->qdisc_sleeping;
58753049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller	spinlock_t *root_lock;
58853049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller
58953049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller	root_lock = qdisc_root_lock(oqdisc);
59053049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller	spin_lock_bh(root_lock);
59153049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller
5928d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller	/* Prune old scheduler */
5938d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller	if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1)
5948d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		qdisc_reset(oqdisc);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5968d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller	/* ... and graft new one */
5978d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller	if (qdisc == NULL)
5988d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		qdisc = &noop_qdisc;
5998d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller	dev_queue->qdisc_sleeping = qdisc;
6008d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller	dev_queue->qdisc = &noop_qdisc;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60253049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller	spin_unlock_bh(root_lock);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return oqdisc;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyvoid qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
60843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy{
60920fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops;
61043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	unsigned long cl;
61143effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	u32 parentid;
61243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy
61343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	if (n == 0)
61443effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		return;
61543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	while ((parentid = sch->parent)) {
616066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski		if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
617066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski			return;
618066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski
6195ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller		sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid));
620ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy		if (sch == NULL) {
621ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy			WARN_ON(parentid != TC_H_ROOT);
622ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy			return;
623ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy		}
62443effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		cops = sch->ops->cl_ops;
62543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		if (cops->qlen_notify) {
62643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cl = cops->get(sch, parentid);
62743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cops->qlen_notify(sch, cl);
62843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cops->put(sch, cl);
62943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		}
63043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		sch->q.qlen -= n;
63143effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	}
63243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy}
63343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyEXPORT_SYMBOL(qdisc_tree_decrease_qlen);
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63599194cff398d056e5ee469647c294466c246c88aDavid S. Millerstatic void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid,
63699194cff398d056e5ee469647c294466c246c88aDavid S. Miller			       struct Qdisc *old, struct Qdisc *new)
63799194cff398d056e5ee469647c294466c246c88aDavid S. Miller{
63899194cff398d056e5ee469647c294466c246c88aDavid S. Miller	if (new || old)
63999194cff398d056e5ee469647c294466c246c88aDavid S. Miller		qdisc_notify(skb, n, clid, old, new);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6414d8863a29c4755a0461cd31b6865026187d6c43aDavid S. Miller	if (old)
64299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		qdisc_destroy(old);
64399194cff398d056e5ee469647c294466c246c88aDavid S. Miller}
64499194cff398d056e5ee469647c294466c246c88aDavid S. Miller
64599194cff398d056e5ee469647c294466c246c88aDavid S. Miller/* Graft qdisc "new" to class "classid" of qdisc "parent" or
64699194cff398d056e5ee469647c294466c246c88aDavid S. Miller * to device "dev".
64799194cff398d056e5ee469647c294466c246c88aDavid S. Miller *
64899194cff398d056e5ee469647c294466c246c88aDavid S. Miller * When appropriate send a netlink notification using 'skb'
64999194cff398d056e5ee469647c294466c246c88aDavid S. Miller * and "n".
65099194cff398d056e5ee469647c294466c246c88aDavid S. Miller *
65199194cff398d056e5ee469647c294466c246c88aDavid S. Miller * On success, destroy old qdisc.
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
65599194cff398d056e5ee469647c294466c246c88aDavid S. Miller		       struct sk_buff *skb, struct nlmsghdr *n, u32 classid,
65699194cff398d056e5ee469647c294466c246c88aDavid S. Miller		       struct Qdisc *new, struct Qdisc *old)
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
65899194cff398d056e5ee469647c294466c246c88aDavid S. Miller	struct Qdisc *q = old;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki	if (parent == NULL) {
66299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		unsigned int i, num_q, ingress;
66399194cff398d056e5ee469647c294466c246c88aDavid S. Miller
66499194cff398d056e5ee469647c294466c246c88aDavid S. Miller		ingress = 0;
66599194cff398d056e5ee469647c294466c246c88aDavid S. Miller		num_q = dev->num_tx_queues;
6668d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		if ((q && q->flags & TCQ_F_INGRESS) ||
6678d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		    (new && new->flags & TCQ_F_INGRESS)) {
66899194cff398d056e5ee469647c294466c246c88aDavid S. Miller			num_q = 1;
66999194cff398d056e5ee469647c294466c246c88aDavid S. Miller			ingress = 1;
67099194cff398d056e5ee469647c294466c246c88aDavid S. Miller		}
67199194cff398d056e5ee469647c294466c246c88aDavid S. Miller
67299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (dev->flags & IFF_UP)
67399194cff398d056e5ee469647c294466c246c88aDavid S. Miller			dev_deactivate(dev);
67499194cff398d056e5ee469647c294466c246c88aDavid S. Miller
67599194cff398d056e5ee469647c294466c246c88aDavid S. Miller		for (i = 0; i < num_q; i++) {
67699194cff398d056e5ee469647c294466c246c88aDavid S. Miller			struct netdev_queue *dev_queue = &dev->rx_queue;
67799194cff398d056e5ee469647c294466c246c88aDavid S. Miller
67899194cff398d056e5ee469647c294466c246c88aDavid S. Miller			if (!ingress)
67999194cff398d056e5ee469647c294466c246c88aDavid S. Miller				dev_queue = netdev_get_tx_queue(dev, i);
68099194cff398d056e5ee469647c294466c246c88aDavid S. Miller
6818d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller			old = dev_graft_qdisc(dev_queue, new);
6828d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller			if (new && i > 0)
6838d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller				atomic_inc(&new->refcnt);
6848d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller
68599194cff398d056e5ee469647c294466c246c88aDavid S. Miller			notify_and_destroy(skb, n, classid, old, new);
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
68799194cff398d056e5ee469647c294466c246c88aDavid S. Miller
68899194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (dev->flags & IFF_UP)
68999194cff398d056e5ee469647c294466c246c88aDavid S. Miller			dev_activate(dev);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
69120fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet		const struct Qdisc_class_ops *cops = parent->ops->cl_ops;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EINVAL;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cops) {
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long cl = cops->get(parent, classid);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cl) {
69899194cff398d056e5ee469647c294466c246c88aDavid S. Miller				err = cops->graft(parent, cl, new, &old);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cops->put(parent, cl);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
70299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (!err)
70399194cff398d056e5ee469647c294466c246c88aDavid S. Miller			notify_and_destroy(skb, n, classid, old, new);
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
70825bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski/* lockdep annotation is needed for ingress; egress gets it only for name */
70925bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_tx_lock;
71025bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_rx_lock;
71125bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Allocate and initialize new qdisc.
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Parameters are passed via opt.
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *
719bb949fbd1878973c3539d9aecff52f284482a937David S. Millerqdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
720bb949fbd1878973c3539d9aecff52f284482a937David S. Miller	     u32 parent, u32 handle, struct nlattr **tca, int *errp)
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
7231e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *kind = tca[TCA_KIND];
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *sch;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *ops;
726175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ops = qdisc_lookup_ops(kind);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_KMOD
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL && kind != NULL) {
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char name[IFNAMSIZ];
7321e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		if (nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* We dropped the RTNL semaphore in order to
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * perform the module load.  So, even if we
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * succeeded in loading the module we have to
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * tell the caller to replay the request.  We
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * indicate this using -EAGAIN.
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * We replay the request because the device may
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * go away in the mean time.
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_unlock();
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			request_module("sch_%s", name);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_lock();
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ops = qdisc_lookup_ops(kind);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ops != NULL) {
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* We will try again qdisc_lookup_ops,
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * so don't keep a reference.
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				module_put(ops->owner);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = -EAGAIN;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_out;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
757b9e2cc0f0e47ad351349156018ef8a365e9c6d25Jamal Hadi Salim	err = -ENOENT;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL)
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7615ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	sch = qdisc_alloc(dev_queue, ops);
7623d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (IS_ERR(sch)) {
7633d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		err = PTR_ERR(sch);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out2;
7653d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	}
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
767ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy	sch->parent = parent;
768ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy
7693d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (handle == TC_H_INGRESS) {
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->flags |= TCQ_F_INGRESS;
7713d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		handle = TC_H_MAKE(TC_H_INGRESS, 0);
77225bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski		lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock);
773fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy	} else {
774fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy		if (handle == 0) {
775fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			handle = qdisc_alloc_handle(dev);
776fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			err = -ENOMEM;
777fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			if (handle == 0)
778fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy				goto err_out3;
779fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy		}
78025bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski		lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7833d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	sch->handle = handle;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7851e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) {
786175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (tca[TCA_STAB]) {
787175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			stab = qdisc_get_stab(tca[TCA_STAB]);
788175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			if (IS_ERR(stab)) {
789175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				err = PTR_ERR(stab);
790175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				goto err_out3;
791175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			}
792175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			sch->stab = stab;
793175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		}
7941e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		if (tca[TCA_RATE]) {
795023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf			err = gen_new_estimator(&sch->bstats, &sch->rate_est,
7967698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller						qdisc_root_lock(sch),
7971e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy						tca[TCA_RATE]);
798023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf			if (err) {
799023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				/*
800023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				 * Any broken qdiscs that would require
801023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				 * a ops->reset() here? The qdisc was never
802023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				 * in action so it shouldn't be necessary.
803023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				 */
804023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				if (ops->destroy)
805023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf					ops->destroy(sch);
806023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				goto err_out3;
807023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf			}
808023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf		}
809ee7af8264dafa0c8c76a8dc596803966c2e29ebcDavid S. Miller		if ((parent != TC_H_ROOT) && !(sch->flags & TCQ_F_INGRESS))
810827ebd6410005b05b3c930ef6a116666c6986886David S. Miller			list_add_tail(&sch->list, &dev_queue->qdisc_sleeping->list);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sch;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out3:
815175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	qdisc_put_stab(sch->stab);
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
8173d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	kfree((char *) sch - sch->padded);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out2:
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	module_put(ops->owner);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*errp = err;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
827175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab = NULL;
828175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int err = 0;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
830175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tca[TCA_OPTIONS]) {
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sch->ops->change == NULL)
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
8331e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		err = sch->ops->change(sch, tca[TCA_OPTIONS]);
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
837175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
838175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tca[TCA_STAB]) {
839175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		stab = qdisc_get_stab(tca[TCA_STAB]);
840175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (IS_ERR(stab))
841175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			return PTR_ERR(stab);
842175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
843175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
844175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	qdisc_put_stab(sch->stab);
845175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	sch->stab = stab;
846175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
8471e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (tca[TCA_RATE])
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gen_replace_estimator(&sch->bstats, &sch->rate_est,
8497698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller				      qdisc_root_lock(sch), tca[TCA_RATE]);
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct check_loop_arg
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_walker 	w;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc		*p;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			depth;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop(struct Qdisc *q, struct Qdisc *p, int depth)
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg	arg;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->cl_ops == NULL)
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.stop = arg.w.skip = arg.w.count = 0;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.fn = check_loop_fn;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.depth = depth;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.p = p;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->ops->cl_ops->walk(q, &arg.w);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return arg.w.stop ? -ELOOP : 0;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w)
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
88120fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops = q->ops->cl_ops;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg *arg = (struct check_loop_arg *)w;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(q, cl);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (leaf) {
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (leaf == arg->p || arg->depth > 7)
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ELOOP;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return check_loop(leaf, arg->p, arg->depth + 1);
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete/get qdisc.
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8993b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm = NLMSG_DATA(n);
9011e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid = tcm->tcm_parent;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *p = NULL;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
908b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev	if (net != &init_net)
909b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return -EINVAL;
910b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
911881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman	if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9141e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
9151e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
9161e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
9171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) {
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL)
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else { /* ingress */
9258123b421e8ed944671d7241323ed3198cccb4041David S. Miller				q = dev->rx_queue.qdisc_sleeping;
92610297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki			}
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
928e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller			struct netdev_queue *dev_queue;
929e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller			dev_queue = netdev_get_tx_queue(dev, 0);
930b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller			q = dev_queue->qdisc_sleeping;
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q)
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tcm->tcm_handle && q->handle != tcm->tcm_handle)
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL)
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9421e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n->nlmsg_type == RTM_DELQDISC) {
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!clid)
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q->handle == 0)
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
95099194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0)
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_notify(skb, n, clid, NULL, q);
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Create/change qdisc.
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9643b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
9661e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q, *p;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
972b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev	if (net != &init_net)
973b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return -EINVAL;
974b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreplay:
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reinit, just in case something touches this. */
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(n);
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clid = tcm->tcm_parent;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q = p = NULL;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman	if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9841e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
9851e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
9861e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
9871e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (clid != TC_H_INGRESS) {
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL)
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else { /*ingress */
9958123b421e8ed944671d7241323ed3198cccb4041David S. Miller				q = dev->rx_queue.qdisc_sleeping;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
998e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller			struct netdev_queue *dev_queue;
999e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller			dev_queue = netdev_get_tx_queue(dev, 0);
1000b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller			q = dev_queue->qdisc_sleeping;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* It may be default qdisc, ignore it */
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q && q->handle == 0)
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			q = NULL;
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) {
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tcm->tcm_handle) {
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q && !(n->nlmsg_flags&NLM_F_REPLACE))
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (TC_H_MIN(tcm->tcm_handle))
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL)
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (n->nlmsg_flags&NLM_F_EXCL)
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
10171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q == p ||
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (p && check_loop(q, p, 0)))
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ELOOP;
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				atomic_inc(&q->refcnt);
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto graft;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q == NULL)
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* This magic test requires explanation.
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   We know, that some child q is already
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   attached to this parent and have choice:
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   either to change it or to create/graft new one.
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   1. We are allowed to create/graft only
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   if CREATE and REPLACE flags are set.
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   2. If EXCL is set, requestor wanted to say,
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   that qdisc tcm_handle is not expected
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   to exist, so that we choose create/graft too.
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   3. The last case is when no flags are set.
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   Alas, it is sort of hole in API, we
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   cannot decide what to do unambiguously.
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   For now we select create/graft, if
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   user gave KIND, which does not match existing.
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((n->nlmsg_flags&NLM_F_CREATE) &&
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (n->nlmsg_flags&NLM_F_REPLACE) &&
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    ((n->nlmsg_flags&NLM_F_EXCL) ||
10501e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				     (tca[TCA_KIND] &&
10511e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				      nla_strcmp(tca[TCA_KIND], q->ops->id))))
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!tcm->tcm_handle)
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = qdisc_lookup(dev, tcm->tcm_handle);
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Change qdisc parameters */
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL)
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n->nlmsg_flags&NLM_F_EXCL)
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EEXIST;
10661e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = qdisc_change(q, tca);
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_notify(skb, n, clid, NULL, q);
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscreate_n_graft:
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(n->nlmsg_flags&NLM_F_CREATE))
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid == TC_H_INGRESS)
1077bb949fbd1878973c3539d9aecff52f284482a937David S. Miller		q = qdisc_create(dev, &dev->rx_queue,
1078bb949fbd1878973c3539d9aecff52f284482a937David S. Miller				 tcm->tcm_parent, tcm->tcm_parent,
1079ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy				 tca, &err);
108010297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki	else
1081e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller		q = qdisc_create(dev, netdev_get_tx_queue(dev, 0),
1082bb949fbd1878973c3539d9aecff52f284482a937David S. Miller				 tcm->tcm_parent, tcm->tcm_handle,
1083ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy				 tca, &err);
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL) {
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err == -EAGAIN)
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto replay;
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgraft:
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (1) {
109299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		err = qdisc_graft(dev, p, skb, n, clid, q, NULL);
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err) {
10944d8863a29c4755a0461cd31b6865026187d6c43aDavid S. Miller			if (q)
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				qdisc_destroy(q);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
1103e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim			 u32 pid, u32 seq, u16 flags, int event)
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
110727a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	unsigned char *b = skb_tail_pointer(skb);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1110e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(nlh);
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
11139ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad1 = 0;
11149ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad2 = 0;
11155ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = clid;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = atomic_read(&q->refcnt);
111957e1c487a4f5754cb77abeb00adb21faa88c484fPatrick McHardy	NLA_PUT_STRING(skb, TCA_KIND, q->ops->id);
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump && q->ops->dump(q, skb) < 0)
11211e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->qstats.qlen = q->q.qlen;
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1124175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (q->stab && qdisc_dump_stab(skb, q->stab) < 0)
1125175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		goto nla_put_failure;
1126175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
11287698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller					 TCA_XSTATS, qdisc_root_lock(q), &d) < 0)
11291e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0)
11321e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 ||
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    gnet_stats_copy_queue(&d, &q->qstats) < 0)
11371e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
113810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
11401e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
114110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
114227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure:
11461e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
1147dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo	nlmsg_trim(skb, b);
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 clid, struct Qdisc *old, struct Qdisc *new)
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old && old->handle) {
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0)
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new) {
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb->len)
117197c53cacf00d1f5aa04adabfebcc806ca8b22b10Denis V. Lunev		return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11783072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic bool tc_qdisc_dump_ignore(struct Qdisc *q)
11793072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
11803072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return (q->flags & TCQ_F_BUILTIN) ? true : false;
11813072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
11823072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
11833072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
11843072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			      struct netlink_callback *cb,
11853072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			      int *q_idx_p, int s_q_idx)
11863072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
11873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	int ret = 0, q_idx = *q_idx_p;
11883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct Qdisc *q;
11893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
11903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (!root)
11913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
11923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
11933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	q = root;
11943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (q_idx < s_q_idx) {
11953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
11963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	} else {
11973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (!tc_qdisc_dump_ignore(q) &&
11983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		    tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
11993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
12003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
12013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
12023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
12033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	list_for_each_entry(q, &root->list, list) {
12043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (q_idx < s_q_idx) {
12053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			q_idx++;
12063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			continue;
12073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		}
12083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (!tc_qdisc_dump_ignore(q) &&
12093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		    tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
12103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
12113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
12123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
12133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
12143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerout:
12163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	*q_idx_p = q_idx;
12173072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return ret;
12183072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone:
12193072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	ret = -1;
12203072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	goto out;
12213072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
12223072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12253b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx, q_idx;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int s_idx, s_q_idx;
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1230b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev	if (net != &init_net)
1231b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return 0;
1232b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_idx = cb->args[0];
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_q_idx = q_idx = cb->args[1];
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock(&dev_base_lock);
12367562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov	idx = 0;
1237881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman	for_each_netdev(&init_net, dev) {
12383072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		struct netdev_queue *dev_queue;
12393072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx < s_idx)
12417562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov			goto cont;
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx > s_idx)
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s_q_idx = 0;
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q_idx = 0;
12453072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12463072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		dev_queue = netdev_get_tx_queue(dev, 0);
1247827ebd6410005b05b3c930ef6a116666c6986886David S. Miller		if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0)
12483072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
12493072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12503072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		dev_queue = &dev->rx_queue;
1251827ebd6410005b05b3c930ef6a116666c6986886David S. Miller		if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0)
12523072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
12533072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12547562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianovcont:
12557562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov		idx++;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock(&dev_base_lock);
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = idx;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[1] = q_idx;
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Traffic classes manipulation.		*
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12773b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
1278b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller	struct netdev_queue *dev_queue;
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm = NLMSG_DATA(n);
12801e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
128320fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops;
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl = 0;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long new_cl;
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = tcm->tcm_parent;
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid = tcm->tcm_handle;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 qid = TC_H_MAJ(clid);
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev	if (net != &init_net)
1292b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return -EINVAL;
1293b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
1294881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman	if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12971e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
12981e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
12991e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
13001e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_UNSPEC - unspecified parent.
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_ROOT   - class is root, which has no parent.
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:0	 - parent is root class.
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:Y	 - parent is a node in hierarchy.
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == 0:Y	 - parent is X:Y, where X:0 is qdisc.
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:0	 - generate handle from kernel pool.
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:Y	 - class is X:Y, where X:0 is qdisc.
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:Y	 - clear.
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:0	 - root class.
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Step 1. Determine qdisc handle X:0 */
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1316e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller	dev_queue = netdev_get_tx_queue(dev, 0);
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pid != TC_H_ROOT) {
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 qid1 = TC_H_MAJ(pid);
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid && qid1) {
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* If both majors are known, they must be identical. */
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (qid != qid1)
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EINVAL;
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid1) {
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qid = qid1;
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid == 0)
1327b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller			qid = dev_queue->qdisc_sleeping->handle;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Now qid is genuine qdisc handle consistent
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   both with parent and child.
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   TC_H_MAJ(pid) still may be unspecified, complete it now.
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pid)
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pid = TC_H_MAKE(qid, pid);
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid == 0)
1338b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller			qid = dev_queue->qdisc_sleeping->handle;
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* OK. Locate qdisc */
134210297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki	if ((q = qdisc_lookup(dev, qid)) == NULL)
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* An check that it supports classes */
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops = q->ops->cl_ops;
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now try to get class */
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid == 0) {
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pid == TC_H_ROOT)
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clid = qid;
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clid = TC_H_MAKE(qid, clid);
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid)
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cl = cops->get(q, clid);
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0) {
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOENT;
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (n->nlmsg_type != RTM_NEWTCLASS || !(n->nlmsg_flags&NLM_F_CREATE))
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (n->nlmsg_type) {
136610297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki		case RTM_NEWTCLASS:
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EEXIST;
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (n->nlmsg_flags&NLM_F_EXCL)
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_DELTCLASS:
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = cops->delete(q, cl);
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (err == 0)
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tclass_notify(skb, n, q, cl, RTM_DELTCLASS);
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_GETTCLASS:
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = tclass_notify(skb, n, q, cl, RTM_NEWTCLASS);
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EINVAL;
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_cl = cl;
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = cops->change(q, clid, pid, tca, &new_cl);
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS);
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl)
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cops->put(q, cl);
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  unsigned long cl,
1400e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim			  u32 pid, u32 seq, u16 flags, int event)
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
140427a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	unsigned char *b = skb_tail_pointer(skb);
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
140620fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1408e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(nlh);
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
14115ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = q->handle;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = 0;
141557e1c487a4f5754cb77abeb00adb21faa88c484fPatrick McHardy	NLA_PUT_STRING(skb, TCA_KIND, q->ops->id);
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0)
14171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
14207698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller					 TCA_XSTATS, qdisc_root_lock(q), &d) < 0)
14211e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0)
14241e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
14271e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
142927a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure:
14331e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
1434dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo	nlmsg_trim(skb, b);
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  struct Qdisc *q, unsigned long cl, int event)
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tc_fill_tclass(skb, q, cl, pid, n->nlmsg_seq, 0, event) < 0) {
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
145397c53cacf00d1f5aa04adabfebcc806ca8b22b10Denis V. Lunev	return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct qdisc_dump_args
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_walker w;
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netlink_callback *cb;
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg)
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_dump_args *a = (struct qdisc_dump_args *)arg;
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tc_fill_tclass(a->skb, q, cl, NETLINK_CB(a->cb->skb).pid,
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS);
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14713072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb,
14723072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				struct tcmsg *tcm, struct netlink_callback *cb,
14733072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				int *t_p, int s_t)
14743072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
14753072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct qdisc_dump_args arg;
14763072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
14773072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (tc_qdisc_dump_ignore(q) ||
14783072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	    *t_p < s_t || !q->ops->cl_ops ||
14793072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	    (tcm->tcm_parent &&
14803072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	     TC_H_MAJ(tcm->tcm_parent) != q->handle)) {
14813072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		(*t_p)++;
14823072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
14833072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
14843072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (*t_p > s_t)
14853072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
14863072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.fn = qdisc_class_dump;
14873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.skb = skb;
14883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.cb = cb;
14893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.stop  = 0;
14903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.skip = cb->args[1];
14913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.count = 0;
14923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	q->ops->cl_ops->walk(q, &arg.w);
14933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	cb->args[1] = arg.w.count;
14943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (arg.w.stop)
14953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return -1;
14963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	(*t_p)++;
14973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return 0;
14983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
14993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb,
15013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			       struct tcmsg *tcm, struct netlink_callback *cb,
15023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			       int *t_p, int s_t)
15033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
15043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct Qdisc *q;
15053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (!root)
15073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
15083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0)
15103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return -1;
15113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	list_for_each_entry(q, &root->list, list) {
15133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0)
15143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			return -1;
15153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
15163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15173072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return 0;
15183072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
15193072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15223072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh);
15233b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
15243072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct netdev_queue *dev_queue;
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
15263072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	int t, s_t;
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1528b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev	if (net != &init_net)
1529b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return 0;
1530b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1533881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman	if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_t = cb->args[0];
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t = 0;
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15393072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	dev_queue = netdev_get_tx_queue(dev, 0);
15408123b421e8ed944671d7241323ed3198cccb4041David S. Miller	if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0)
15413072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		goto done;
15423072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15433072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	dev_queue = &dev->rx_queue;
15448123b421e8ed944671d7241323ed3198cccb4041David S. Miller	if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0)
15453072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		goto done;
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15473072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone:
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = t;
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Main classifier routine: scans classifier chain attached
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to this qdisc, (optionally) tests for protocol and asks
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   specific classifiers.
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
155873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyint tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp,
155973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		       struct tcf_result *res)
156073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy{
156173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	__be16 protocol = skb->protocol;
156273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	int err = 0;
156373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
156473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	for (; tp; tp = tp->next) {
156573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		if ((tp->protocol == protocol ||
156673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		     tp->protocol == htons(ETH_P_ALL)) &&
156773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		    (err = tp->classify(skb, tp, res)) >= 0) {
156873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#ifdef CONFIG_NET_CLS_ACT
156973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			if (err != TC_ACT_RECLASSIFY && skb->tc_verd)
157073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy				skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0);
157173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif
157273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			return err;
157373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		}
157473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	}
157573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	return -1;
157673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy}
157773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify_compat);
157873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
158073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		struct tcf_result *res)
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
158373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	__be16 protocol;
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcf_proto *otp = tp;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreclassify:
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	protocol = skb->protocol;
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	err = tc_classify_compat(skb, tp, res);
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
159273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	if (err == TC_ACT_RECLASSIFY) {
159373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		u32 verd = G_TC_VERD(skb->tc_verd);
159473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		tp = otp;
159573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
159673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		if (verd++ >= MAX_REC_LOOP) {
159773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			printk("rule prio %u protocol %02x reclassify loop, "
159873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			       "packet dropped\n",
159973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			       tp->prio&0xffff, ntohs(tp->protocol));
160073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			return TC_ACT_SHOT;
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
160273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd);
160373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		goto reclassify;
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
160573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif
160673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	return err;
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
160873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify);
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1610a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyvoid tcf_destroy(struct tcf_proto *tp)
1611a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{
1612a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	tp->ops->destroy(tp);
1613a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	module_put(tp->ops->owner);
1614a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	kfree(tp);
1615a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy}
1616a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
1617ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardyvoid tcf_destroy_chain(struct tcf_proto **fl)
1618a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{
1619a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	struct tcf_proto *tp;
1620a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
1621ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy	while ((tp = *fl) != NULL) {
1622ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy		*fl = tp->next;
1623a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy		tcf_destroy(tp);
1624a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	}
1625a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy}
1626a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyEXPORT_SYMBOL(tcf_destroy_chain);
1627a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_show(struct seq_file *seq, void *v)
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16313c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy	struct timespec ts;
16323c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy
16333c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy	hrtimer_get_res(CLOCK_MONOTONIC, &ts);
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_printf(seq, "%08x %08x %08x %08x\n",
1635641b9e0e8b7f96425da6ce98f3361e3af0baee29Patrick McHardy		   (u32)NSEC_PER_USEC, (u32)PSCHED_US2NS(1),
1636514bca322cb9220308d22691ac1e74038bfabac3Patrick McHardy		   1000000,
16373c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy		   (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts)));
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_open(struct inode *inode, struct file *file)
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return single_open(file, psched_show, PDE(inode)->data);
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1647da7071d7e32d15149cc513f096a3638097b66387Arjan van de Venstatic const struct file_operations psched_fops = {
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner = THIS_MODULE,
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = psched_open,
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read  = seq_read,
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek = seq_lseek,
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release = single_release,
165310297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki};
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pktsched_init(void)
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&pfifo_qdisc_ops);
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&bfifo_qdisc_ops);
1660457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman	proc_net_fops_create(&init_net, "psched", 0, &psched_fops);
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1662be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL);
1663be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL);
1664be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc);
1665be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL);
1666be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL);
1667be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass);
1668be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(pktsched_init);
1673