sch_api.c revision 66c6f529c31e2886536aad4b2320d566deb1f150
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/sched.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/socket.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sockios.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kmod.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/processor.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid,
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct Qdisc *old, struct Qdisc *new);
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 struct Qdisc *q, unsigned long cl, int event);
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Short review.
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This file consists of two interrelated parts:
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   1. queueing disciplines manager frontend.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   2. traffic classes manager frontend.
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Generally, queueing discipline ("qdisc") is a black box,
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   which is able to enqueue packets and to dequeue them (when
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   device is ready to send something) in order and at times
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   determined by algorithm hidden in it.
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   qdisc's are divided to two categories:
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "queues", which have no internal structure visible from outside.
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "schedulers", which split all the packets to "traffic classes",
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     using "packet classifiers" (look at cls_api.c)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   In turn, classes may have child qdiscs (as rule, queues)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   attached to them etc. etc. etc.
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   The goal of the routines in this file is to translate
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   information supplied by user in the form of handles
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to more intelligible for kernel form, to make some sanity
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   checks and part of work, which is common to all qdiscs
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   and to provide rtnetlink notifications.
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   All real intelligent work is done inside qdisc modules.
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Every discipline has two major routines: enqueue and dequeue.
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---dequeue
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   dequeue usually returns a skb to send. It is allowed to return NULL,
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   but it does not mean that queue is empty, it just means that
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   discipline does not want to send anything this time.
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Queue is really empty if q->q.qlen == 0.
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   For complicated disciplines with multiple queues q->q is not
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   real packet queue, but however q->q.qlen must be valid.
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---enqueue
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   enqueue returns 0, if packet was enqueued successfully.
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   If packet (this one or another one) was dropped, it returns
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   not zero error code.
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_DROP 	- this packet dropped
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: do not backoff, but wait until queue will clear.
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_CN	 	- probably this packet enqueued, but another one dropped.
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or ignore
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_POLICED	- dropped by police.
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or error to real-time apps.
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Auxiliary routines:
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---requeue
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   requeues once dequeued packet. It is used for non-standard or
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   just buggy devices, which can defer output even if dev->tbusy=0.
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---reset
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   returns qdisc to initial state: purge all buffers, clear all
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   timers, counters (except for statistics) etc.
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---init
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   initializes newly created qdisc.
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---destroy
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   destroys resources allocated by init and during lifetime of qdisc.
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---change
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   changes qdisc parameters.
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protects list of registered TC modules. It is pure SMP lock. */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_RWLOCK(qdisc_mod_lock);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Queueing disciplines manipulation.	*
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The list of all installed queueing disciplines. */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_ops *qdisc_base;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register/uregister queueing discipline */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint register_qdisc(struct Qdisc_ops *qops)
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = -EEXIST;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strcmp(qops->id, q->id))
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->enqueue == NULL)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->enqueue = noop_qdisc_ops.enqueue;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->requeue == NULL)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->requeue = noop_qdisc_ops.requeue;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->dequeue == NULL)
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->dequeue = noop_qdisc_ops.dequeue;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qops->next = NULL;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*qp = qops;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 0;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint unregister_qdisc(struct Qdisc_ops *qops)
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOENT;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q == qops)
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q) {
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*qp = q->next;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q->next = NULL;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = 0;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We know handle. Find qdisc among all qdisc's attached to device
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (root qdisc, all its children, children of children etc.)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19885670cc1faa2e1472e4a423cbf0b5e3d55c5ba88Patrick McHardy	read_lock(&qdisc_tree_lock);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(q, &dev->qdisc_list, list) {
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q->handle == handle) {
20185670cc1faa2e1472e4a423cbf0b5e3d55c5ba88Patrick McHardy			read_unlock(&qdisc_tree_lock);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return q;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20585670cc1faa2e1472e4a423cbf0b5e3d55c5ba88Patrick McHardy	read_unlock(&qdisc_tree_lock);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_class_ops *cops = p->ops->cl_ops;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cl = cops->get(p, classid);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(p, cl);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops->put(p, cl);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return leaf;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find queueing discipline by name */
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_ops *qdisc_lookup_ops(struct rtattr *kind)
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q = NULL;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind) {
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_lock(&qdisc_mod_lock);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (q = qdisc_base; q; q = q->next) {
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rtattr_strcmp(kind, q->id) == 0) {
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!try_module_get(q->owner))
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					q = NULL;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_unlock(&qdisc_mod_lock);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return q;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct qdisc_rate_table *qdisc_rtab_list;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *tab)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) {
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) == 0) {
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtab->refcnt++;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return rtab;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tab == NULL || r->rate == 0 || r->cell_log == 0 || RTA_PAYLOAD(tab) != 1024)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rtab = kmalloc(sizeof(*rtab), GFP_KERNEL);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rtab) {
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->rate = *r;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->refcnt = 1;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(rtab->data, RTA_DATA(tab), 1024);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->next = qdisc_rtab_list;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_rtab_list = rtab;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rtab;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qdisc_put_rtab(struct qdisc_rate_table *tab)
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab, **rtabp;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tab || --tab->refcnt)
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (rtabp = &qdisc_rtab_list; (rtab=*rtabp) != NULL; rtabp = &rtab->next) {
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rtab == tab) {
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*rtabp = rtab->next;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(rtab);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Allocate an unique handle from space managed by kernel */
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 qdisc_alloc_handle(struct net_device *dev)
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0x10000;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u32 autohandle = TC_H_MAKE(0x80000000U, 0);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		autohandle += TC_H_MAKE(0x10000U, 0);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (autohandle == TC_H_MAKE(TC_H_ROOT, 0))
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			autohandle = TC_H_MAKE(0x80000000U, 0);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while	(qdisc_lookup(dev, autohandle) && --i > 0);
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i>0 ? autohandle : 0;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Attach toplevel qdisc to device dev */
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdev_graft_qdisc(struct net_device *dev, struct Qdisc *qdisc)
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *oqdisc;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags & IFF_UP)
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_deactivate(dev);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qdisc_lock_tree(dev);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qdisc && qdisc->flags&TCQ_F_INGRESS) {
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		oqdisc = dev->qdisc_ingress;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Prune old scheduler */
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) {
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* delete */
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qdisc_reset(oqdisc);
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->qdisc_ingress = NULL;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {  /* new */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->qdisc_ingress = qdisc;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		oqdisc = dev->qdisc_sleeping;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Prune old scheduler */
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1)
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qdisc_reset(oqdisc);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ... and graft new one */
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qdisc == NULL)
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qdisc = &noop_qdisc;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->qdisc_sleeping = qdisc;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->qdisc = &noop_qdisc;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qdisc_unlock_tree(dev);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags & IFF_UP)
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_activate(dev);
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return oqdisc;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Graft qdisc "new" to class "classid" of qdisc "parent" or
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to device "dev".
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Old qdisc is not destroyed but returned in *old.
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       u32 classid,
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       struct Qdisc *new, struct Qdisc **old)
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = *old;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (parent == NULL) {
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q && q->flags&TCQ_F_INGRESS) {
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*old = dev_graft_qdisc(dev, q);
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*old = dev_graft_qdisc(dev, new);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct Qdisc_class_ops *cops = parent->ops->cl_ops;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EINVAL;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cops) {
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long cl = cops->get(parent, classid);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cl) {
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = cops->graft(parent, cl, new, old);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (new)
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					new->parent = classid;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cops->put(parent, cl);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Allocate and initialize new qdisc.
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Parameters are passed via opt.
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsqdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rtattr *kind = tca[TCA_KIND-1];
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *sch;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *ops;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ops = qdisc_lookup_ops(kind);
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_KMOD
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL && kind != NULL) {
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char name[IFNAMSIZ];
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rtattr_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* We dropped the RTNL semaphore in order to
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * perform the module load.  So, even if we
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * succeeded in loading the module we have to
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * tell the caller to replay the request.  We
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * indicate this using -EAGAIN.
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * We replay the request because the device may
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * go away in the mean time.
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_unlock();
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			request_module("sch_%s", name);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_lock();
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ops = qdisc_lookup_ops(kind);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ops != NULL) {
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* We will try again qdisc_lookup_ops,
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * so don't keep a reference.
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				module_put(ops->owner);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = -EAGAIN;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_out;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
433b9e2cc0f0e47ad351349156018ef8a365e9c6d25Jamal Hadi Salim	err = -ENOENT;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL)
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4373d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	sch = qdisc_alloc(dev, ops);
4383d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (IS_ERR(sch)) {
4393d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		err = PTR_ERR(sch);
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out2;
4413d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	}
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4433d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (handle == TC_H_INGRESS) {
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->flags |= TCQ_F_INGRESS;
4453d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		handle = TC_H_MAKE(TC_H_INGRESS, 0);
4463d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	} else if (handle == 0) {
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		handle = qdisc_alloc_handle(dev);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (handle == 0)
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out3;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4533d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	sch->handle = handle;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) {
456023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf#ifdef CONFIG_NET_ESTIMATOR
457023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf		if (tca[TCA_RATE-1]) {
458023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf			err = gen_new_estimator(&sch->bstats, &sch->rate_est,
459023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf						sch->stats_lock,
460023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf						tca[TCA_RATE-1]);
461023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf			if (err) {
462023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				/*
463023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				 * Any broken qdiscs that would require
464023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				 * a ops->reset() here? The qdisc was never
465023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				 * in action so it shouldn't be necessary.
466023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				 */
467023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				if (ops->destroy)
468023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf					ops->destroy(sch);
469023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf				goto err_out3;
470023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf			}
471023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf		}
472023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf#endif
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_lock_tree(dev);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_add_tail(&sch->list, &dev->qdisc_list);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_unlock_tree(dev);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sch;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out3:
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
4813d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	kfree((char *) sch - sch->padded);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out2:
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	module_put(ops->owner);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*errp = err;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_change(struct Qdisc *sch, struct rtattr **tca)
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tca[TCA_OPTIONS-1]) {
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int err;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sch->ops->change == NULL)
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = sch->ops->change(sch, tca[TCA_OPTIONS-1]);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_ESTIMATOR
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tca[TCA_RATE-1])
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gen_replace_estimator(&sch->bstats, &sch->rate_est,
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sch->stats_lock, tca[TCA_RATE-1]);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct check_loop_arg
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_walker 	w;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc		*p;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			depth;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w);
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop(struct Qdisc *q, struct Qdisc *p, int depth)
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg	arg;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->cl_ops == NULL)
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.stop = arg.w.skip = arg.w.count = 0;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.fn = check_loop_fn;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.depth = depth;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.p = p;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->ops->cl_ops->walk(q, &arg.w);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return arg.w.stop ? -ELOOP : 0;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w)
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_class_ops *cops = q->ops->cl_ops;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg *arg = (struct check_loop_arg *)w;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(q, cl);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (leaf) {
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (leaf == arg->p || arg->depth > 7)
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ELOOP;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return check_loop(leaf, arg->p, arg->depth + 1);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete/get qdisc.
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm = NLMSG_DATA(n);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rtattr **tca = arg;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid = tcm->tcm_parent;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *p = NULL;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL)
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) {
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else { /* ingress */
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = dev->qdisc_ingress;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        }
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			q = dev->qdisc_sleeping;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q)
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tcm->tcm_handle && q->handle != tcm->tcm_handle)
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL)
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n->nlmsg_type == RTM_DELQDISC) {
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!clid)
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q->handle == 0)
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((err = qdisc_graft(dev, p, clid, NULL, &q)) != 0)
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q) {
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qdisc_notify(skb, n, clid, q, NULL);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock_bh(&dev->queue_lock);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qdisc_destroy(q);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_bh(&dev->queue_lock);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_notify(skb, n, clid, NULL, q);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Create/change qdisc.
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rtattr **tca;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q, *p;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreplay:
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reinit, just in case something touches this. */
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(n);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tca = arg;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clid = tcm->tcm_parent;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q = p = NULL;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL)
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (clid != TC_H_INGRESS) {
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL)
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else { /*ingress */
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = dev->qdisc_ingress;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			q = dev->qdisc_sleeping;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* It may be default qdisc, ignore it */
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q && q->handle == 0)
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			q = NULL;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) {
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tcm->tcm_handle) {
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q && !(n->nlmsg_flags&NLM_F_REPLACE))
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (TC_H_MIN(tcm->tcm_handle))
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL)
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (n->nlmsg_flags&NLM_F_EXCL)
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q == p ||
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (p && check_loop(q, p, 0)))
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ELOOP;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				atomic_inc(&q->refcnt);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto graft;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q == NULL)
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* This magic test requires explanation.
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   We know, that some child q is already
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   attached to this parent and have choice:
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   either to change it or to create/graft new one.
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   1. We are allowed to create/graft only
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   if CREATE and REPLACE flags are set.
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   2. If EXCL is set, requestor wanted to say,
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   that qdisc tcm_handle is not expected
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   to exist, so that we choose create/graft too.
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   3. The last case is when no flags are set.
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   Alas, it is sort of hole in API, we
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   cannot decide what to do unambiguously.
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   For now we select create/graft, if
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   user gave KIND, which does not match existing.
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((n->nlmsg_flags&NLM_F_CREATE) &&
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (n->nlmsg_flags&NLM_F_REPLACE) &&
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    ((n->nlmsg_flags&NLM_F_EXCL) ||
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     (tca[TCA_KIND-1] &&
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))))
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!tcm->tcm_handle)
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = qdisc_lookup(dev, tcm->tcm_handle);
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Change qdisc parameters */
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL)
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n->nlmsg_flags&NLM_F_EXCL)
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EEXIST;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = qdisc_change(q, tca);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_notify(skb, n, clid, NULL, q);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscreate_n_graft:
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(n->nlmsg_flags&NLM_F_CREATE))
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid == TC_H_INGRESS)
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = qdisc_create(dev, tcm->tcm_parent, tca, &err);
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        else
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = qdisc_create(dev, tcm->tcm_handle, tca, &err);
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL) {
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err == -EAGAIN)
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto replay;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgraft:
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (1) {
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct Qdisc *old_q = NULL;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = qdisc_graft(dev, p, clid, q, &old_q);
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err) {
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (q) {
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock_bh(&dev->queue_lock);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				qdisc_destroy(q);
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock_bh(&dev->queue_lock);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_notify(skb, n, clid, old_q, q);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (old_q) {
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock_bh(&dev->queue_lock);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qdisc_destroy(old_q);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_bh(&dev->queue_lock);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
751e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim			 u32 pid, u32 seq, u16 flags, int event)
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	 *b = skb->tail;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
758e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(nlh);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
7619ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad1 = 0;
7629ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad2 = 0;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_ifindex = q->dev->ifindex;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = clid;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = atomic_read(&q->refcnt);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RTA_PUT(skb, TCA_KIND, IFNAMSIZ, q->ops->id);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump && q->ops->dump(q, skb) < 0)
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rtattr_failure;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->qstats.qlen = q->q.qlen;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			TCA_XSTATS, q->stats_lock, &d) < 0)
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rtattr_failure;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0)
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rtattr_failure;
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_ESTIMATOR
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 ||
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    gnet_stats_copy_queue(&d, &q->qstats) < 0)
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rtattr_failure;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rtattr_failure;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nlh->nlmsg_len = skb->tail - b;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure:
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrtattr_failure:
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_trim(skb, b - skb->data);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 clid, struct Qdisc *old, struct Qdisc *new)
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old && old->handle) {
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0)
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new) {
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb->len)
818ac6d439d2097b72ea0cbc2322ce1263a38bc1fd0Patrick McHardy		return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx, q_idx;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int s_idx, s_q_idx;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_idx = cb->args[0];
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_q_idx = q_idx = cb->args[1];
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock(&dev_base_lock);
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx < s_idx)
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx > s_idx)
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s_q_idx = 0;
84085670cc1faa2e1472e4a423cbf0b5e3d55c5ba88Patrick McHardy		read_lock(&qdisc_tree_lock);
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q_idx = 0;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry(q, &dev->qdisc_list, list) {
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (q_idx < s_q_idx) {
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q_idx++;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {
84985670cc1faa2e1472e4a423cbf0b5e3d55c5ba88Patrick McHardy				read_unlock(&qdisc_tree_lock);
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto done;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			q_idx++;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
85485670cc1faa2e1472e4a423cbf0b5e3d55c5ba88Patrick McHardy		read_unlock(&qdisc_tree_lock);
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock(&dev_base_lock);
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = idx;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[1] = q_idx;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Traffic classes manipulation.		*
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm = NLMSG_DATA(n);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rtattr **tca = arg;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_class_ops *cops;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl = 0;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long new_cl;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = tcm->tcm_parent;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid = tcm->tcm_handle;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 qid = TC_H_MAJ(clid);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL)
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_UNSPEC - unspecified parent.
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_ROOT   - class is root, which has no parent.
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:0	 - parent is root class.
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:Y	 - parent is a node in hierarchy.
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == 0:Y	 - parent is X:Y, where X:0 is qdisc.
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:0	 - generate handle from kernel pool.
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:Y	 - class is X:Y, where X:0 is qdisc.
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:Y	 - clear.
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:0	 - root class.
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Step 1. Determine qdisc handle X:0 */
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pid != TC_H_ROOT) {
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 qid1 = TC_H_MAJ(pid);
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid && qid1) {
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* If both majors are known, they must be identical. */
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (qid != qid1)
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EINVAL;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid1) {
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qid = qid1;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid == 0)
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qid = dev->qdisc_sleeping->handle;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Now qid is genuine qdisc handle consistent
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   both with parent and child.
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   TC_H_MAJ(pid) still may be unspecified, complete it now.
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pid)
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pid = TC_H_MAKE(qid, pid);
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid == 0)
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qid = dev->qdisc_sleeping->handle;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* OK. Locate qdisc */
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((q = qdisc_lookup(dev, qid)) == NULL)
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* An check that it supports classes */
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops = q->ops->cl_ops;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now try to get class */
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid == 0) {
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pid == TC_H_ROOT)
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clid = qid;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clid = TC_H_MAKE(qid, clid);
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid)
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cl = cops->get(q, clid);
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0) {
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOENT;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (n->nlmsg_type != RTM_NEWTCLASS || !(n->nlmsg_flags&NLM_F_CREATE))
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (n->nlmsg_type) {
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_NEWTCLASS:
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EEXIST;
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (n->nlmsg_flags&NLM_F_EXCL)
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_DELTCLASS:
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = cops->delete(q, cl);
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (err == 0)
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tclass_notify(skb, n, q, cl, RTM_DELTCLASS);
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_GETTCLASS:
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = tclass_notify(skb, n, q, cl, RTM_NEWTCLASS);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EINVAL;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_cl = cl;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = cops->change(q, clid, pid, tca, &new_cl);
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS);
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl)
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cops->put(q, cl);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  unsigned long cl,
989e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim			  u32 pid, u32 seq, u16 flags, int event)
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	 *b = skb->tail;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_class_ops *cl_ops = q->ops->cl_ops;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
997e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(nlh);
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_ifindex = q->dev->ifindex;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = q->handle;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = 0;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RTA_PUT(skb, TCA_KIND, IFNAMSIZ, q->ops->id);
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0)
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rtattr_failure;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			TCA_XSTATS, q->stats_lock, &d) < 0)
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rtattr_failure;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0)
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rtattr_failure;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rtattr_failure;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nlh->nlmsg_len = skb->tail - b;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure:
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrtattr_failure:
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_trim(skb, b - skb->data);
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  struct Qdisc *q, unsigned long cl, int event)
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tc_fill_tclass(skb, q, cl, pid, n->nlmsg_seq, 0, event) < 0) {
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1042ac6d439d2097b72ea0cbc2322ce1263a38bc1fd0Patrick McHardy	return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct qdisc_dump_args
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_walker w;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netlink_callback *cb;
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg)
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_dump_args *a = (struct qdisc_dump_args *)arg;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tc_fill_tclass(a->skb, q, cl, NETLINK_CB(a->cb->skb).pid,
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int t;
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int s_t;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q;
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh);
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_dump_args arg;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL)
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_t = cb->args[0];
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t = 0;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
107785670cc1faa2e1472e4a423cbf0b5e3d55c5ba88Patrick McHardy	read_lock(&qdisc_tree_lock);
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(q, &dev->qdisc_list, list) {
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (t < s_t || !q->ops->cl_ops ||
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (tcm->tcm_parent &&
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     TC_H_MAJ(tcm->tcm_parent) != q->handle)) {
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			t++;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (t > s_t)
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		arg.w.fn = qdisc_class_dump;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		arg.skb = skb;
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		arg.cb = cb;
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		arg.w.stop  = 0;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		arg.w.skip = cb->args[1];
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		arg.w.count = 0;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q->ops->cl_ops->walk(q, &arg.w);
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cb->args[1] = arg.w.count;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg.w.stop)
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t++;
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
109985670cc1faa2e1472e4a423cbf0b5e3d55c5ba88Patrick McHardy	read_unlock(&qdisc_tree_lock);
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = t;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Main classifier routine: scans classifier chain attached
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to this qdisc, (optionally) tests for protocol and asks
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   specific classifiers.
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcf_result *res)
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
111566c6f529c31e2886536aad4b2320d566deb1f150Al Viro	__be16 protocol = skb->protocol;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcf_proto *otp = tp;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreclassify:
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	protocol = skb->protocol;
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for ( ; tp; tp = tp->next) {
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((tp->protocol == protocol ||
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tp->protocol == __constant_htons(ETH_P_ALL)) &&
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(err = tp->classify(skb, tp, res)) >= 0) {
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ( TC_ACT_RECLASSIFY == err) {
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				__u32 verd = (__u32) G_TC_VERD(skb->tc_verd);
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tp = otp;
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (MAX_REC_LOOP < verd++) {
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("rule prio %d protocol %02x reclassify is buggy packet dropped\n",
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						tp->prio&0xffff, ntohs(tp->protocol));
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return TC_ACT_SHOT;
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb->tc_verd = SET_TC_VERD(skb->tc_verd,verd);
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto reclassify;
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (skb->tc_verd)
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					skb->tc_verd = SET_TC_VERD(skb->tc_verd,0);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return err;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_us_per_tick = 1;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_tick_per_us = 1;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_show(struct seq_file *seq, void *v)
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_printf(seq, "%08x %08x %08x %08x\n",
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      psched_tick_per_us, psched_us_per_tick,
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      1000000, HZ);
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_open(struct inode *inode, struct file *file)
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return single_open(file, psched_show, PDE(inode)->data);
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct file_operations psched_fops = {
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner = THIS_MODULE,
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = psched_open,
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read  = seq_read,
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek = seq_lseek,
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release = single_release,
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_SCH_CLK_CPU
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspsched_tdiff_t psched_clock_per_hz;
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint psched_clock_scale;
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(psched_clock_per_hz);
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(psched_clock_scale);
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspsched_time_t psched_time_base;
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscycles_t psched_time_mark;
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(psched_time_mark);
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(psched_time_base);
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Periodically adjust psched_time_base to avoid overflow
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with 32-bit get_cycles(). Safe up to 4GHz CPU.
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void psched_tick(unsigned long);
11968d06afab73a75f40ae2864e6c296356bab1ab473Ingo Molnarstatic DEFINE_TIMER(psched_timer, psched_tick, 0, 0);
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void psched_tick(unsigned long dummy)
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sizeof(cycles_t) == sizeof(u32)) {
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		psched_time_t dummy_stamp;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PSCHED_GET_TIME(dummy_stamp);
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		psched_timer.expires = jiffies + 1*HZ;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_timer(&psched_timer);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init psched_calibrate_clock(void)
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_time_t stamp, stamp1;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval tv, tv1;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_tdiff_t delay;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long rdelay;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stop;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_tick(0);
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stop = jiffies + HZ/10;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PSCHED_GET_TIME(stamp);
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday(&tv);
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, stop)) {
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpu_relax();
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PSCHED_GET_TIME(stamp1);
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday(&tv1);
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	delay = PSCHED_TDIFF(stamp1, stamp);
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rdelay = tv1.tv_usec - tv.tv_usec;
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rdelay += (tv1.tv_sec - tv.tv_sec)*1000000;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rdelay > delay)
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	delay /= rdelay;
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_tick_per_us = delay;
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((delay>>=1) != 0)
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		psched_clock_scale++;
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_us_per_tick = 1<<psched_clock_scale;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_clock_per_hz = (psched_tick_per_us*(1000000/HZ))>>psched_clock_scale;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pktsched_init(void)
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rtnetlink_link *link_p;
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_SCH_CLK_CPU
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (psched_calibrate_clock() < 0)
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#elif defined(CONFIG_NET_SCH_CLK_JIFFIES)
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_tick_per_us = HZ<<PSCHED_JSCALE;
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_us_per_tick = 1000000;
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	link_p = rtnetlink_links[PF_UNSPEC];
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup rtnetlink links. It is made here to avoid
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   exporting large number of public symbols.
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (link_p) {
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link_p[RTM_NEWQDISC-RTM_BASE].doit = tc_modify_qdisc;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link_p[RTM_DELQDISC-RTM_BASE].doit = tc_get_qdisc;
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link_p[RTM_GETQDISC-RTM_BASE].doit = tc_get_qdisc;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link_p[RTM_GETQDISC-RTM_BASE].dumpit = tc_dump_qdisc;
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link_p[RTM_NEWTCLASS-RTM_BASE].doit = tc_ctl_tclass;
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link_p[RTM_DELTCLASS-RTM_BASE].doit = tc_ctl_tclass;
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link_p[RTM_GETTCLASS-RTM_BASE].doit = tc_ctl_tclass;
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link_p[RTM_GETTCLASS-RTM_BASE].dumpit = tc_dump_tclass;
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&pfifo_qdisc_ops);
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&bfifo_qdisc_ops);
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	proc_net_fops_create("psched", 0, &psched_fops);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(pktsched_init);
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1280d5d75cd6b10ddad2f375b61092754474ad78aec7Stephen HemmingerEXPORT_SYMBOL(qdisc_lookup);
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qdisc_get_rtab);
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qdisc_put_rtab);
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(register_qdisc);
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(unregister_qdisc);
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(tc_classify);
1286