sch_api.c revision 57dbb2d83d100ea601c54fe129bfde0678db5dee
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * net/sched/sch_api.c	Packet scheduler API.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		This program is free software; you can redistribute it and/or
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		modify it under the terms of the GNU General Public License
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		as published by the Free Software Foundation; either version
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		2 of the License, or (at your option) any later version.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes:
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Rani Assaf <rani@magic.metawire.com> :980802: JIFFIES and CPU clock sources are repaired.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Eduardo J. Blanco <ejbs@netlabs.com.uy> :990222: kmod support
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Jamal Hadi Salim <hadi@nortelnetworks.com>: 990601: ingress support
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kmod.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
294179477f637caa730626bd597fdf28c5bad73565Patrick McHardy#include <linux/hrtimer.h>
3025bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski#include <linux/lockdep.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h>
33b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev#include <net/sock.h>
34dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo#include <net/netlink.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid,
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct Qdisc *old, struct Qdisc *new);
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 struct Qdisc *q, unsigned long cl, int event);
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Short review.
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This file consists of two interrelated parts:
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   1. queueing disciplines manager frontend.
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   2. traffic classes manager frontend.
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Generally, queueing discipline ("qdisc") is a black box,
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   which is able to enqueue packets and to dequeue them (when
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   device is ready to send something) in order and at times
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   determined by algorithm hidden in it.
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   qdisc's are divided to two categories:
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "queues", which have no internal structure visible from outside.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "schedulers", which split all the packets to "traffic classes",
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     using "packet classifiers" (look at cls_api.c)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   In turn, classes may have child qdiscs (as rule, queues)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   attached to them etc. etc. etc.
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   The goal of the routines in this file is to translate
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   information supplied by user in the form of handles
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to more intelligible for kernel form, to make some sanity
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   checks and part of work, which is common to all qdiscs
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   and to provide rtnetlink notifications.
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   All real intelligent work is done inside qdisc modules.
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Every discipline has two major routines: enqueue and dequeue.
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---dequeue
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   dequeue usually returns a skb to send. It is allowed to return NULL,
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   but it does not mean that queue is empty, it just means that
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   discipline does not want to send anything this time.
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Queue is really empty if q->q.qlen == 0.
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   For complicated disciplines with multiple queues q->q is not
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   real packet queue, but however q->q.qlen must be valid.
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---enqueue
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   enqueue returns 0, if packet was enqueued successfully.
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   If packet (this one or another one) was dropped, it returns
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   not zero error code.
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_DROP 	- this packet dropped
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: do not backoff, but wait until queue will clear.
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_CN	 	- probably this packet enqueued, but another one dropped.
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or ignore
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_POLICED	- dropped by police.
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or error to real-time apps.
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Auxiliary routines:
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10099c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski   ---peek
10199c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski
10299c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski   like dequeue but without removing a packet from the queue
10399c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---reset
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   returns qdisc to initial state: purge all buffers, clear all
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   timers, counters (except for statistics) etc.
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---init
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   initializes newly created qdisc.
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---destroy
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   destroys resources allocated by init and during lifetime of qdisc.
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---change
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   changes qdisc parameters.
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protects list of registered TC modules. It is pure SMP lock. */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_RWLOCK(qdisc_mod_lock);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Queueing disciplines manipulation.	*
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The list of all installed queueing disciplines. */
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_ops *qdisc_base;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register/uregister queueing discipline */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint register_qdisc(struct Qdisc_ops *qops)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = -EEXIST;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strcmp(qops->id, q->id))
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->enqueue == NULL)
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->enqueue = noop_qdisc_ops.enqueue;
14999c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski	if (qops->peek == NULL) {
15099c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski		if (qops->dequeue == NULL) {
15199c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski			qops->peek = noop_qdisc_ops.peek;
15299c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski		} else {
15399c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski			rc = -EINVAL;
15499c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski			goto out;
15599c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski		}
15699c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski	}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->dequeue == NULL)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->dequeue = noop_qdisc_ops.dequeue;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qops->next = NULL;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*qp = qops;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 0;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16762e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(register_qdisc);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint unregister_qdisc(struct Qdisc_ops *qops)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOENT;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q == qops)
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q) {
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*qp = q->next;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q->next = NULL;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = 0;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18662e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(unregister_qdisc);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We know handle. Find qdisc among all qdisc's attached to device
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (root qdisc, all its children, children of children etc.)
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1926113b748fb9935399ec2bbca3a3dc82008f6167fHannes Ederstatic struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
1938123b421e8ed944671d7241323ed3198cccb4041David S. Miller{
1948123b421e8ed944671d7241323ed3198cccb4041David S. Miller	struct Qdisc *q;
1958123b421e8ed944671d7241323ed3198cccb4041David S. Miller
1968123b421e8ed944671d7241323ed3198cccb4041David S. Miller	if (!(root->flags & TCQ_F_BUILTIN) &&
1978123b421e8ed944671d7241323ed3198cccb4041David S. Miller	    root->handle == handle)
1988123b421e8ed944671d7241323ed3198cccb4041David S. Miller		return root;
1998123b421e8ed944671d7241323ed3198cccb4041David S. Miller
2008123b421e8ed944671d7241323ed3198cccb4041David S. Miller	list_for_each_entry(q, &root->list, list) {
2018123b421e8ed944671d7241323ed3198cccb4041David S. Miller		if (q->handle == handle)
2028123b421e8ed944671d7241323ed3198cccb4041David S. Miller			return q;
2038123b421e8ed944671d7241323ed3198cccb4041David S. Miller	}
2048123b421e8ed944671d7241323ed3198cccb4041David S. Miller	return NULL;
2058123b421e8ed944671d7241323ed3198cccb4041David S. Miller}
2068123b421e8ed944671d7241323ed3198cccb4041David S. Miller
207f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawskistatic void qdisc_list_add(struct Qdisc *q)
208f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski{
209f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawski	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
210af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy		list_add_tail(&q->list, &qdisc_dev(q)->qdisc->list);
211f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski}
212f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
213f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawskivoid qdisc_list_del(struct Qdisc *q)
214f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski{
215f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawski	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
216f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski		list_del(&q->list);
217f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski}
218f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek PoplawskiEXPORT_SYMBOL(qdisc_list_del);
219f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
220ead81cc5fc6d996db6afb20f211241612610a07aDavid S. Millerstruct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
222f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski	struct Qdisc *q;
223f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
224af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy	q = qdisc_match_from_root(dev->qdisc, handle);
225af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy	if (q)
226af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy		goto out;
227f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
228f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski	q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle);
229f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawskiout:
230f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski	return q;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
23720fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops = p->ops->cl_ops;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cl = cops->get(p, classid);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0)
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(p, cl);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops->put(p, cl);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return leaf;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find queueing discipline by name */
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic struct Qdisc_ops *qdisc_lookup_ops(struct nlattr *kind)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q = NULL;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind) {
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_lock(&qdisc_mod_lock);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (q = qdisc_base; q; q = q->next) {
2591e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy			if (nla_strcmp(kind, q->id) == 0) {
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!try_module_get(q->owner))
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					q = NULL;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_unlock(&qdisc_mod_lock);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return q;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct qdisc_rate_table *qdisc_rtab_list;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2721e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystruct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) {
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) == 0) {
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtab->refcnt++;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return rtab;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2835feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy	if (tab == NULL || r->rate == 0 || r->cell_log == 0 ||
2845feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy	    nla_len(tab) != TC_RTAB_SIZE)
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rtab = kmalloc(sizeof(*rtab), GFP_KERNEL);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rtab) {
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->rate = *r;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->refcnt = 1;
2911e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		memcpy(rtab->data, nla_data(tab), 1024);
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->next = qdisc_rtab_list;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_rtab_list = rtab;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rtab;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
29762e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_get_rtab);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qdisc_put_rtab(struct qdisc_rate_table *tab)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab, **rtabp;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tab || --tab->refcnt)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (rtabp = &qdisc_rtab_list; (rtab=*rtabp) != NULL; rtabp = &rtab->next) {
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rtab == tab) {
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*rtabp = rtab->next;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(rtab);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
31462e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_put_rtab);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
316175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic LIST_HEAD(qdisc_stab_list);
317175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic DEFINE_SPINLOCK(qdisc_stab_lock);
318175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
319175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = {
320175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	[TCA_STAB_BASE]	= { .len = sizeof(struct tc_sizespec) },
321175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	[TCA_STAB_DATA] = { .type = NLA_BINARY },
322175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna};
323175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
324175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt)
325175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
326175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct nlattr *tb[TCA_STAB_MAX + 1];
327175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab;
328175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct tc_sizespec *s;
329175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	unsigned int tsize = 0;
330175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	u16 *tab = NULL;
331175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int err;
332175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
333175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy);
334175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (err < 0)
335175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(err);
336175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!tb[TCA_STAB_BASE])
337175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-EINVAL);
338175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
339175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	s = nla_data(tb[TCA_STAB_BASE]);
340175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
341175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (s->tsize > 0) {
342175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (!tb[TCA_STAB_DATA])
343175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			return ERR_PTR(-EINVAL);
344175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		tab = nla_data(tb[TCA_STAB_DATA]);
345175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16);
346175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
347175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
348175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!s || tsize != s->tsize || (!tab && tsize > 0))
349175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-EINVAL);
350175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
351f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_lock(&qdisc_stab_lock);
352175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
353175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	list_for_each_entry(stab, &qdisc_stab_list, list) {
354175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (memcmp(&stab->szopts, s, sizeof(*s)))
355175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			continue;
356175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16)))
357175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			continue;
358175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		stab->refcnt++;
359f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller		spin_unlock(&qdisc_stab_lock);
360175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return stab;
361175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
362175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
363f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_unlock(&qdisc_stab_lock);
364175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
365175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL);
366175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!stab)
367175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-ENOMEM);
368175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
369175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab->refcnt = 1;
370175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab->szopts = *s;
371175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tsize > 0)
372175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		memcpy(stab->data, tab, tsize * sizeof(u16));
373175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
374f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_lock(&qdisc_stab_lock);
375175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	list_add_tail(&stab->list, &qdisc_stab_list);
376f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_unlock(&qdisc_stab_lock);
377175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
378175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return stab;
379175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
380175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
381175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_put_stab(struct qdisc_size_table *tab)
382175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
383175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!tab)
384175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return;
385175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
386f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_lock(&qdisc_stab_lock);
387175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
388175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (--tab->refcnt == 0) {
389175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		list_del(&tab->list);
390175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		kfree(tab);
391175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
392175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
393f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_unlock(&qdisc_stab_lock);
394175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
395175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_put_stab);
396175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
397175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab)
398175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
399175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct nlattr *nest;
400175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
401175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	nest = nla_nest_start(skb, TCA_STAB);
4023aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy	if (nest == NULL)
4033aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy		goto nla_put_failure;
404175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	NLA_PUT(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts);
405175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	nla_nest_end(skb, nest);
406175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
407175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return skb->len;
408175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
409175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnanla_put_failure:
410175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return -1;
411175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
412175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
413175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_calculate_pkt_len(struct sk_buff *skb, struct qdisc_size_table *stab)
414175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
415175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int pkt_len, slot;
416175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
417175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	pkt_len = skb->len + stab->szopts.overhead;
418175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(!stab->szopts.tsize))
419175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		goto out;
420175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
421175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	slot = pkt_len + stab->szopts.cell_align;
422175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(slot < 0))
423175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		slot = 0;
424175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
425175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	slot >>= stab->szopts.cell_log;
426175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (likely(slot < stab->szopts.tsize))
427175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = stab->data[slot];
428175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	else
429175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = stab->data[stab->szopts.tsize - 1] *
430175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				(slot / stab->szopts.tsize) +
431175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				stab->data[slot % stab->szopts.tsize];
432175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
433175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	pkt_len <<= stab->szopts.size_log;
434175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnaout:
435175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(pkt_len < 1))
436175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = 1;
437175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	qdisc_skb_cb(skb)->pkt_len = pkt_len;
438175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
439175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_calculate_pkt_len);
440175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
441b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawskivoid qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc)
442b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski{
443b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski	if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {
444b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski		printk(KERN_WARNING
445b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski		       "%s: %s qdisc %X: is non-work-conserving?\n",
446b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski		       txt, qdisc->ops->id, qdisc->handle >> 16);
447b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski		qdisc->flags |= TCQ_F_WARN_NONWC;
448b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski	}
449b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski}
450b00355db3f88d96810a60011a30cfb2c3469409dJarek PoplawskiEXPORT_SYMBOL(qdisc_warn_nonwc);
451b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski
4524179477f637caa730626bd597fdf28c5bad73565Patrick McHardystatic enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
4534179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4544179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,
4552fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller						 timer);
4564179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4574179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc->flags &= ~TCQ_F_THROTTLED;
4588608db031b4d2932d645709e2cfe8fbcd91a7305David S. Miller	__netif_schedule(qdisc_root(wd->qdisc));
4591936502d00ae6c2aa3931c42f6cf54afaba094f2Stephen Hemminger
4604179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	return HRTIMER_NORESTART;
4614179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4624179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4634179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc)
4644179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4652fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
4662fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	wd->timer.function = qdisc_watchdog;
4674179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc = qdisc;
4684179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4694179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_init);
4704179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4714179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires)
4724179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4734179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	ktime_t time;
4744179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4752540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski	if (test_bit(__QDISC_STATE_DEACTIVATED,
4762540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski		     &qdisc_root_sleeping(wd->qdisc)->state))
4772540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski		return;
4782540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski
4794179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc->flags |= TCQ_F_THROTTLED;
4804179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	time = ktime_set(0, 0);
481ca44d6e60f9de26281fda203f58b570e1748c015Jarek Poplawski	time = ktime_add_ns(time, PSCHED_TICKS2NS(expires));
4822fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS);
4834179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4844179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_schedule);
4854179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4864179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_cancel(struct qdisc_watchdog *wd)
4874179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4882fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	hrtimer_cancel(&wd->timer);
4894179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc->flags &= ~TCQ_F_THROTTLED;
4904179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4914179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_cancel);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
493a94f779f9d82eb2d758a8715eaae5df98e8dcb21Adrian Bunkstatic struct hlist_head *qdisc_class_hash_alloc(unsigned int n)
4946fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
4956fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = n * sizeof(struct hlist_head), i;
4966fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_head *h;
4976fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
4986fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (size <= PAGE_SIZE)
4996fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		h = kmalloc(size, GFP_KERNEL);
5006fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	else
5016fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		h = (struct hlist_head *)
5026fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			__get_free_pages(GFP_KERNEL, get_order(size));
5036fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5046fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (h != NULL) {
5056fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		for (i = 0; i < n; i++)
5066fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			INIT_HLIST_HEAD(&h[i]);
5076fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	}
5086fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	return h;
5096fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5106fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5116fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardystatic void qdisc_class_hash_free(struct hlist_head *h, unsigned int n)
5126fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5136fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = n * sizeof(struct hlist_head);
5146fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5156fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (size <= PAGE_SIZE)
5166fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		kfree(h);
5176fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	else
5186fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		free_pages((unsigned long)h, get_order(size));
5196fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5206fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5216fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_grow(struct Qdisc *sch, struct Qdisc_class_hash *clhash)
5226fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5236fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct Qdisc_class_common *cl;
5246fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_node *n, *next;
5256fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_head *nhash, *ohash;
5266fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int nsize, nmask, osize;
5276fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int i, h;
5286fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5296fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	/* Rehash when load factor exceeds 0.75 */
5306fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (clhash->hashelems * 4 <= clhash->hashsize * 3)
5316fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return;
5326fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nsize = clhash->hashsize * 2;
5336fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nmask = nsize - 1;
5346fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nhash = qdisc_class_hash_alloc(nsize);
5356fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (nhash == NULL)
5366fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return;
5376fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5386fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	ohash = clhash->hash;
5396fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	osize = clhash->hashsize;
5406fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5416fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	sch_tree_lock(sch);
5426fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	for (i = 0; i < osize; i++) {
5436fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		hlist_for_each_entry_safe(cl, n, next, &ohash[i], hnode) {
5446fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			h = qdisc_class_hash(cl->classid, nmask);
5456fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			hlist_add_head(&cl->hnode, &nhash[h]);
5466fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		}
5476fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	}
5486fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hash     = nhash;
5496fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashsize = nsize;
5506fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashmask = nmask;
5516fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	sch_tree_unlock(sch);
5526fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5536fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	qdisc_class_hash_free(ohash, osize);
5546fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5556fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_grow);
5566fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5576fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyint qdisc_class_hash_init(struct Qdisc_class_hash *clhash)
5586fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5596fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = 4;
5606fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5616fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hash = qdisc_class_hash_alloc(size);
5626fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (clhash->hash == NULL)
5636fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return -ENOMEM;
5646fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashsize  = size;
5656fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashmask  = size - 1;
5666fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems = 0;
5676fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	return 0;
5686fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5696fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_init);
5706fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5716fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_destroy(struct Qdisc_class_hash *clhash)
5726fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5736fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	qdisc_class_hash_free(clhash->hash, clhash->hashsize);
5746fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5756fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_destroy);
5766fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5776fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_insert(struct Qdisc_class_hash *clhash,
5786fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			     struct Qdisc_class_common *cl)
5796fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5806fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int h;
5816fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5826fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	INIT_HLIST_NODE(&cl->hnode);
5836fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	h = qdisc_class_hash(cl->classid, clhash->hashmask);
5846fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	hlist_add_head(&cl->hnode, &clhash->hash[h]);
5856fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems++;
5866fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5876fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_insert);
5886fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5896fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_remove(struct Qdisc_class_hash *clhash,
5906fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			     struct Qdisc_class_common *cl)
5916fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5926fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	hlist_del(&cl->hnode);
5936fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems--;
5946fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5956fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_remove);
5966fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Allocate an unique handle from space managed by kernel */
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 qdisc_alloc_handle(struct net_device *dev)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0x10000;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u32 autohandle = TC_H_MAKE(0x80000000U, 0);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		autohandle += TC_H_MAKE(0x10000U, 0);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (autohandle == TC_H_MAKE(TC_H_ROOT, 0))
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			autohandle = TC_H_MAKE(0x80000000U, 0);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while	(qdisc_lookup(dev, autohandle) && --i > 0);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i>0 ? autohandle : 0;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyvoid qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
61443effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy{
61520fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops;
61643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	unsigned long cl;
61743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	u32 parentid;
61843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy
61943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	if (n == 0)
62043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		return;
62143effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	while ((parentid = sch->parent)) {
622066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski		if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
623066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski			return;
624066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski
6255ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller		sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid));
626ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy		if (sch == NULL) {
627ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy			WARN_ON(parentid != TC_H_ROOT);
628ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy			return;
629ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy		}
63043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		cops = sch->ops->cl_ops;
63143effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		if (cops->qlen_notify) {
63243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cl = cops->get(sch, parentid);
63343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cops->qlen_notify(sch, cl);
63443effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cops->put(sch, cl);
63543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		}
63643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		sch->q.qlen -= n;
63743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	}
63843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy}
63943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyEXPORT_SYMBOL(qdisc_tree_decrease_qlen);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64199194cff398d056e5ee469647c294466c246c88aDavid S. Millerstatic void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid,
64299194cff398d056e5ee469647c294466c246c88aDavid S. Miller			       struct Qdisc *old, struct Qdisc *new)
64399194cff398d056e5ee469647c294466c246c88aDavid S. Miller{
64499194cff398d056e5ee469647c294466c246c88aDavid S. Miller	if (new || old)
64599194cff398d056e5ee469647c294466c246c88aDavid S. Miller		qdisc_notify(skb, n, clid, old, new);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6474d8863a29c4755a0461cd31b6865026187d6c43aDavid S. Miller	if (old)
64899194cff398d056e5ee469647c294466c246c88aDavid S. Miller		qdisc_destroy(old);
64999194cff398d056e5ee469647c294466c246c88aDavid S. Miller}
65099194cff398d056e5ee469647c294466c246c88aDavid S. Miller
65199194cff398d056e5ee469647c294466c246c88aDavid S. Miller/* Graft qdisc "new" to class "classid" of qdisc "parent" or
65299194cff398d056e5ee469647c294466c246c88aDavid S. Miller * to device "dev".
65399194cff398d056e5ee469647c294466c246c88aDavid S. Miller *
65499194cff398d056e5ee469647c294466c246c88aDavid S. Miller * When appropriate send a netlink notification using 'skb'
65599194cff398d056e5ee469647c294466c246c88aDavid S. Miller * and "n".
65699194cff398d056e5ee469647c294466c246c88aDavid S. Miller *
65799194cff398d056e5ee469647c294466c246c88aDavid S. Miller * On success, destroy old qdisc.
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
66199194cff398d056e5ee469647c294466c246c88aDavid S. Miller		       struct sk_buff *skb, struct nlmsghdr *n, u32 classid,
66299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		       struct Qdisc *new, struct Qdisc *old)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
66499194cff398d056e5ee469647c294466c246c88aDavid S. Miller	struct Qdisc *q = old;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66710297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki	if (parent == NULL) {
66899194cff398d056e5ee469647c294466c246c88aDavid S. Miller		unsigned int i, num_q, ingress;
66999194cff398d056e5ee469647c294466c246c88aDavid S. Miller
67099194cff398d056e5ee469647c294466c246c88aDavid S. Miller		ingress = 0;
67199194cff398d056e5ee469647c294466c246c88aDavid S. Miller		num_q = dev->num_tx_queues;
6728d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		if ((q && q->flags & TCQ_F_INGRESS) ||
6738d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		    (new && new->flags & TCQ_F_INGRESS)) {
67499194cff398d056e5ee469647c294466c246c88aDavid S. Miller			num_q = 1;
67599194cff398d056e5ee469647c294466c246c88aDavid S. Miller			ingress = 1;
67699194cff398d056e5ee469647c294466c246c88aDavid S. Miller		}
67799194cff398d056e5ee469647c294466c246c88aDavid S. Miller
67899194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (dev->flags & IFF_UP)
67999194cff398d056e5ee469647c294466c246c88aDavid S. Miller			dev_deactivate(dev);
68099194cff398d056e5ee469647c294466c246c88aDavid S. Miller
6816ec1c69a8f6492fd25722f4762721921da074c12David S. Miller		if (new && new->ops->attach) {
6826ec1c69a8f6492fd25722f4762721921da074c12David S. Miller			new->ops->attach(new);
6836ec1c69a8f6492fd25722f4762721921da074c12David S. Miller			num_q = 0;
6846ec1c69a8f6492fd25722f4762721921da074c12David S. Miller		}
6856ec1c69a8f6492fd25722f4762721921da074c12David S. Miller
68699194cff398d056e5ee469647c294466c246c88aDavid S. Miller		for (i = 0; i < num_q; i++) {
68799194cff398d056e5ee469647c294466c246c88aDavid S. Miller			struct netdev_queue *dev_queue = &dev->rx_queue;
68899194cff398d056e5ee469647c294466c246c88aDavid S. Miller
68999194cff398d056e5ee469647c294466c246c88aDavid S. Miller			if (!ingress)
69099194cff398d056e5ee469647c294466c246c88aDavid S. Miller				dev_queue = netdev_get_tx_queue(dev, i);
69199194cff398d056e5ee469647c294466c246c88aDavid S. Miller
6928d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller			old = dev_graft_qdisc(dev_queue, new);
6938d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller			if (new && i > 0)
6948d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller				atomic_inc(&new->refcnt);
6958d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller
696036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			if (!ingress)
697036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski				qdisc_destroy(old);
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
69999194cff398d056e5ee469647c294466c246c88aDavid S. Miller
700036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski		if (!ingress) {
701036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			notify_and_destroy(skb, n, classid, dev->qdisc, new);
702036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			if (new && !new->ops->attach)
703036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski				atomic_inc(&new->refcnt);
704036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			dev->qdisc = new ? : &noop_qdisc;
705036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski		} else {
706036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			notify_and_destroy(skb, n, classid, old, new);
707036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski		}
708af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy
70999194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (dev->flags & IFF_UP)
71099194cff398d056e5ee469647c294466c246c88aDavid S. Miller			dev_activate(dev);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
71220fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet		const struct Qdisc_class_ops *cops = parent->ops->cl_ops;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
714c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy		err = -EOPNOTSUPP;
715c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy		if (cops && cops->graft) {
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long cl = cops->get(parent, classid);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cl) {
71899194cff398d056e5ee469647c294466c246c88aDavid S. Miller				err = cops->graft(parent, cl, new, &old);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cops->put(parent, cl);
720c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy			} else
721c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy				err = -ENOENT;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
72399194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (!err)
72499194cff398d056e5ee469647c294466c246c88aDavid S. Miller			notify_and_destroy(skb, n, classid, old, new);
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
72925bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski/* lockdep annotation is needed for ingress; egress gets it only for name */
73025bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_tx_lock;
73125bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_rx_lock;
73225bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Allocate and initialize new qdisc.
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Parameters are passed via opt.
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *
740bb949fbd1878973c3539d9aecff52f284482a937David S. Millerqdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
74123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	     struct Qdisc *p, u32 parent, u32 handle,
74223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	     struct nlattr **tca, int *errp)
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
7451e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *kind = tca[TCA_KIND];
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *sch;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *ops;
748175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ops = qdisc_lookup_ops(kind);
75195a5afca4a8d2e1cb77e1d4bc6ff9f718dc32f7aJohannes Berg#ifdef CONFIG_MODULES
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL && kind != NULL) {
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char name[IFNAMSIZ];
7541e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		if (nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* We dropped the RTNL semaphore in order to
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * perform the module load.  So, even if we
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * succeeded in loading the module we have to
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * tell the caller to replay the request.  We
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * indicate this using -EAGAIN.
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * We replay the request because the device may
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * go away in the mean time.
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_unlock();
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			request_module("sch_%s", name);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_lock();
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ops = qdisc_lookup_ops(kind);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ops != NULL) {
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* We will try again qdisc_lookup_ops,
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * so don't keep a reference.
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				module_put(ops->owner);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = -EAGAIN;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_out;
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
779b9e2cc0f0e47ad351349156018ef8a365e9c6d25Jamal Hadi Salim	err = -ENOENT;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL)
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7835ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	sch = qdisc_alloc(dev_queue, ops);
7843d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (IS_ERR(sch)) {
7853d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		err = PTR_ERR(sch);
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out2;
7873d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	}
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
789ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy	sch->parent = parent;
790ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy
7913d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (handle == TC_H_INGRESS) {
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->flags |= TCQ_F_INGRESS;
7933d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		handle = TC_H_MAKE(TC_H_INGRESS, 0);
79425bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski		lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock);
795fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy	} else {
796fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy		if (handle == 0) {
797fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			handle = qdisc_alloc_handle(dev);
798fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			err = -ENOMEM;
799fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			if (handle == 0)
800fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy				goto err_out3;
801fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy		}
80225bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski		lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock);
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8053d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	sch->handle = handle;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) {
808175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (tca[TCA_STAB]) {
809175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			stab = qdisc_get_stab(tca[TCA_STAB]);
810175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			if (IS_ERR(stab)) {
811175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				err = PTR_ERR(stab);
8127c64b9f3f584008000cf3b960f25cd6a68fce191Jarek Poplawski				goto err_out4;
813175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			}
814175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			sch->stab = stab;
815175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		}
8161e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		if (tca[TCA_RATE]) {
817f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski			spinlock_t *root_lock;
818f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski
81923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			err = -EOPNOTSUPP;
82023bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			if (sch->flags & TCQ_F_MQROOT)
82123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy				goto err_out4;
82223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy
823f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski			if ((sch->parent != TC_H_ROOT) &&
82423bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			    !(sch->flags & TCQ_F_INGRESS) &&
82523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			    (!p || !(p->flags & TCQ_F_MQROOT)))
826f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski				root_lock = qdisc_root_sleeping_lock(sch);
827f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski			else
828f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski				root_lock = qdisc_lock(sch);
829f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski
830023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf			err = gen_new_estimator(&sch->bstats, &sch->rate_est,
831f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski						root_lock, tca[TCA_RATE]);
83223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			if (err)
83323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy				goto err_out4;
834023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf		}
835f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
836f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski		qdisc_list_add(sch);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sch;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out3:
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
8423d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	kfree((char *) sch - sch->padded);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out2:
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	module_put(ops->owner);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*errp = err;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
84823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy
84923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyerr_out4:
85023bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	/*
85123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	 * Any broken qdiscs that would require a ops->reset() here?
85223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	 * The qdisc was never in action so it shouldn't be necessary.
85323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	 */
8547c64b9f3f584008000cf3b960f25cd6a68fce191Jarek Poplawski	qdisc_put_stab(sch->stab);
85523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	if (ops->destroy)
85623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy		ops->destroy(sch);
85723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	goto err_out3;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
862175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab = NULL;
863175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int err = 0;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
865175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tca[TCA_OPTIONS]) {
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sch->ops->change == NULL)
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
8681e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		err = sch->ops->change(sch, tca[TCA_OPTIONS]);
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
872175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
873175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tca[TCA_STAB]) {
874175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		stab = qdisc_get_stab(tca[TCA_STAB]);
875175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (IS_ERR(stab))
876175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			return PTR_ERR(stab);
877175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
878175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
879175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	qdisc_put_stab(sch->stab);
880175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	sch->stab = stab;
881175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
88223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	if (tca[TCA_RATE]) {
88371bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		/* NB: ignores errors from replace_estimator
88471bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		   because change can't be undone. */
88523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy		if (sch->flags & TCQ_F_MQROOT)
88623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			goto out;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gen_replace_estimator(&sch->bstats, &sch->rate_est,
88871bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger					    qdisc_root_sleeping_lock(sch),
88971bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger					    tca[TCA_RATE]);
89023bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	}
89123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyout:
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct check_loop_arg
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_walker 	w;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc		*p;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			depth;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w);
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop(struct Qdisc *q, struct Qdisc *p, int depth)
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg	arg;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->cl_ops == NULL)
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.stop = arg.w.skip = arg.w.count = 0;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.fn = check_loop_fn;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.depth = depth;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.p = p;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->ops->cl_ops->walk(q, &arg.w);
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return arg.w.stop ? -ELOOP : 0;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w)
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
92320fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops = q->ops->cl_ops;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg *arg = (struct check_loop_arg *)w;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(q, cl);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (leaf) {
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (leaf == arg->p || arg->depth > 7)
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ELOOP;
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return check_loop(leaf, arg->p, arg->depth + 1);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete/get qdisc.
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9413b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm = NLMSG_DATA(n);
9431e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid = tcm->tcm_parent;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *p = NULL;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95009ad9bc752519cc167d0a573e1acf69b5c707c67Octavian Purdila	if (!net_eq(net, &init_net))
951b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return -EINVAL;
952b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
953881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman	if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9561e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
9571e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
9581e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
9591e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) {
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL)
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else { /* ingress */
9678123b421e8ed944671d7241323ed3198cccb4041David S. Miller				q = dev->rx_queue.qdisc_sleeping;
96810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki			}
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
970af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			q = dev->qdisc;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q)
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tcm->tcm_handle && q->handle != tcm->tcm_handle)
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL)
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9821e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n->nlmsg_type == RTM_DELQDISC) {
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!clid)
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q->handle == 0)
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
99099194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0)
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_notify(skb, n, clid, NULL, q);
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Create/change qdisc.
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10043b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
10061e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q, *p;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101209ad9bc752519cc167d0a573e1acf69b5c707c67Octavian Purdila	if (!net_eq(net, &init_net))
1013b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return -EINVAL;
1014b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreplay:
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reinit, just in case something touches this. */
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(n);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clid = tcm->tcm_parent;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q = p = NULL;
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman	if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10241e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
10251e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
10261e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
10271e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (clid != TC_H_INGRESS) {
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL)
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else { /*ingress */
10358123b421e8ed944671d7241323ed3198cccb4041David S. Miller				q = dev->rx_queue.qdisc_sleeping;
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
1038af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			q = dev->qdisc;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* It may be default qdisc, ignore it */
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q && q->handle == 0)
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			q = NULL;
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) {
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tcm->tcm_handle) {
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q && !(n->nlmsg_flags&NLM_F_REPLACE))
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (TC_H_MIN(tcm->tcm_handle))
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL)
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (n->nlmsg_flags&NLM_F_EXCL)
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
10551e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q == p ||
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (p && check_loop(q, p, 0)))
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ELOOP;
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				atomic_inc(&q->refcnt);
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto graft;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q == NULL)
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* This magic test requires explanation.
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   We know, that some child q is already
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   attached to this parent and have choice:
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   either to change it or to create/graft new one.
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   1. We are allowed to create/graft only
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   if CREATE and REPLACE flags are set.
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   2. If EXCL is set, requestor wanted to say,
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   that qdisc tcm_handle is not expected
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   to exist, so that we choose create/graft too.
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   3. The last case is when no flags are set.
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   Alas, it is sort of hole in API, we
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   cannot decide what to do unambiguously.
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   For now we select create/graft, if
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   user gave KIND, which does not match existing.
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((n->nlmsg_flags&NLM_F_CREATE) &&
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (n->nlmsg_flags&NLM_F_REPLACE) &&
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    ((n->nlmsg_flags&NLM_F_EXCL) ||
10881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				     (tca[TCA_KIND] &&
10891e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				      nla_strcmp(tca[TCA_KIND], q->ops->id))))
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!tcm->tcm_handle)
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = qdisc_lookup(dev, tcm->tcm_handle);
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Change qdisc parameters */
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL)
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n->nlmsg_flags&NLM_F_EXCL)
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EEXIST;
11041e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = qdisc_change(q, tca);
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_notify(skb, n, clid, NULL, q);
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscreate_n_graft:
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(n->nlmsg_flags&NLM_F_CREATE))
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid == TC_H_INGRESS)
111523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy		q = qdisc_create(dev, &dev->rx_queue, p,
1116bb949fbd1878973c3539d9aecff52f284482a937David S. Miller				 tcm->tcm_parent, tcm->tcm_parent,
1117ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy				 tca, &err);
11186ec1c69a8f6492fd25722f4762721921da074c12David S. Miller	else {
1119926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		struct netdev_queue *dev_queue;
11206ec1c69a8f6492fd25722f4762721921da074c12David S. Miller
11216ec1c69a8f6492fd25722f4762721921da074c12David S. Miller		if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue)
1122926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski			dev_queue = p->ops->cl_ops->select_queue(p, tcm);
1123926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		else if (p)
1124926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski			dev_queue = p->dev_queue;
1125926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		else
1126926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski			dev_queue = netdev_get_tx_queue(dev, 0);
11276ec1c69a8f6492fd25722f4762721921da074c12David S. Miller
1128926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		q = qdisc_create(dev, dev_queue, p,
1129bb949fbd1878973c3539d9aecff52f284482a937David S. Miller				 tcm->tcm_parent, tcm->tcm_handle,
1130ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy				 tca, &err);
11316ec1c69a8f6492fd25722f4762721921da074c12David S. Miller	}
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL) {
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err == -EAGAIN)
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto replay;
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgraft:
1139e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen	err = qdisc_graft(dev, p, skb, n, clid, q, NULL);
1140e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen	if (err) {
1141e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen		if (q)
1142e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen			qdisc_destroy(q);
1143e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen		return err;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1145e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
1150e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim			 u32 pid, u32 seq, u16 flags, int event)
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
115427a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	unsigned char *b = skb_tail_pointer(skb);
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1157e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(nlh);
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
11609ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad1 = 0;
11619ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad2 = 0;
11625ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = clid;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = atomic_read(&q->refcnt);
116657e1c487a4f5754cb77abeb00adb21faa88c484fPatrick McHardy	NLA_PUT_STRING(skb, TCA_KIND, q->ops->id);
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump && q->ops->dump(q, skb) < 0)
11681e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->qstats.qlen = q->q.qlen;
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (q->stab && qdisc_dump_stab(skb, q->stab) < 0)
1172175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		goto nla_put_failure;
1173175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
1174102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
1175102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski					 qdisc_root_sleeping_lock(q), &d) < 0)
11761e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0)
11791e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
1182d250a5f90e53f5e150618186230795352d154c88Eric Dumazet	    gnet_stats_copy_rate_est(&d, &q->bstats, &q->rate_est) < 0 ||
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    gnet_stats_copy_queue(&d, &q->qstats) < 0)
11841e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
118510297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
11871e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
118810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
118927a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure:
11931e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
1194dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo	nlmsg_trim(skb, b);
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 clid, struct Qdisc *old, struct Qdisc *new)
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old && old->handle) {
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0)
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new) {
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb->len)
121897c53cacf00d1f5aa04adabfebcc806ca8b22b10Denis V. Lunev		return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12253072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic bool tc_qdisc_dump_ignore(struct Qdisc *q)
12263072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
12273072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return (q->flags & TCQ_F_BUILTIN) ? true : false;
12283072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
12293072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12303072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
12313072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			      struct netlink_callback *cb,
12323072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			      int *q_idx_p, int s_q_idx)
12333072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
12343072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	int ret = 0, q_idx = *q_idx_p;
12353072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct Qdisc *q;
12363072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12373072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (!root)
12383072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
12393072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12403072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	q = root;
12413072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (q_idx < s_q_idx) {
12423072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
12433072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	} else {
12443072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (!tc_qdisc_dump_ignore(q) &&
12453072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		    tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
12463072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
12473072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
12483072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
12493072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
12503072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	list_for_each_entry(q, &root->list, list) {
12513072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (q_idx < s_q_idx) {
12523072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			q_idx++;
12533072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			continue;
12543072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		}
12553072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (!tc_qdisc_dump_ignore(q) &&
12563072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		    tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
12573072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
12583072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
12593072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
12603072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
12613072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12623072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerout:
12633072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	*q_idx_p = q_idx;
12643072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return ret;
12653072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone:
12663072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	ret = -1;
12673072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	goto out;
12683072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
12693072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12723b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx, q_idx;
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int s_idx, s_q_idx;
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
127709ad9bc752519cc167d0a573e1acf69b5c707c67Octavian Purdila	if (!net_eq(net, &init_net))
1278b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return 0;
1279b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_idx = cb->args[0];
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_q_idx = q_idx = cb->args[1];
1282f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger
1283f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger	rcu_read_lock();
12847562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov	idx = 0;
1285f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger	for_each_netdev_rcu(&init_net, dev) {
12863072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		struct netdev_queue *dev_queue;
12873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx < s_idx)
12897562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov			goto cont;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx > s_idx)
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s_q_idx = 0;
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q_idx = 0;
12933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
1294af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy		if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0)
12953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
12963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		dev_queue = &dev->rx_queue;
1298827ebd6410005b05b3c930ef6a116666c6986886David S. Miller		if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0)
12993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
13003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
13017562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianovcont:
13027562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov		idx++;
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
1306f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger	rcu_read_unlock();
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = idx;
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[1] = q_idx;
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Traffic classes manipulation.		*
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13243b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm = NLMSG_DATA(n);
13261e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
132920fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops;
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl = 0;
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long new_cl;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = tcm->tcm_parent;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid = tcm->tcm_handle;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 qid = TC_H_MAJ(clid);
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
133709ad9bc752519cc167d0a573e1acf69b5c707c67Octavian Purdila	if (!net_eq(net, &init_net))
1338b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return -EINVAL;
1339b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
1340881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman	if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13431e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
13441e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
13451e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
13461e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_UNSPEC - unspecified parent.
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_ROOT   - class is root, which has no parent.
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:0	 - parent is root class.
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:Y	 - parent is a node in hierarchy.
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == 0:Y	 - parent is X:Y, where X:0 is qdisc.
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:0	 - generate handle from kernel pool.
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:Y	 - class is X:Y, where X:0 is qdisc.
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:Y	 - clear.
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:0	 - root class.
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Step 1. Determine qdisc handle X:0 */
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pid != TC_H_ROOT) {
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 qid1 = TC_H_MAJ(pid);
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid && qid1) {
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* If both majors are known, they must be identical. */
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (qid != qid1)
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EINVAL;
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid1) {
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qid = qid1;
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid == 0)
1372af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			qid = dev->qdisc->handle;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Now qid is genuine qdisc handle consistent
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   both with parent and child.
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   TC_H_MAJ(pid) still may be unspecified, complete it now.
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pid)
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pid = TC_H_MAKE(qid, pid);
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid == 0)
1383af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			qid = dev->qdisc->handle;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* OK. Locate qdisc */
138710297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki	if ((q = qdisc_lookup(dev, qid)) == NULL)
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* An check that it supports classes */
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops = q->ops->cl_ops;
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now try to get class */
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid == 0) {
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pid == TC_H_ROOT)
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clid = qid;
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clid = TC_H_MAKE(qid, clid);
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid)
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cl = cops->get(q, clid);
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0) {
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOENT;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (n->nlmsg_type != RTM_NEWTCLASS || !(n->nlmsg_flags&NLM_F_CREATE))
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (n->nlmsg_type) {
141110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki		case RTM_NEWTCLASS:
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EEXIST;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (n->nlmsg_flags&NLM_F_EXCL)
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_DELTCLASS:
1417de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy			err = -EOPNOTSUPP;
1418de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy			if (cops->delete)
1419de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy				err = cops->delete(q, cl);
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (err == 0)
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tclass_notify(skb, n, q, cl, RTM_DELTCLASS);
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_GETTCLASS:
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = tclass_notify(skb, n, q, cl, RTM_NEWTCLASS);
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EINVAL;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_cl = cl;
1433de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy	err = -EOPNOTSUPP;
1434de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy	if (cops->change)
1435de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy		err = cops->change(q, clid, pid, tca, &new_cl);
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS);
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl)
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cops->put(q, cl);
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  unsigned long cl,
1449e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim			  u32 pid, u32 seq, u16 flags, int event)
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
145327a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	unsigned char *b = skb_tail_pointer(skb);
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
145520fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops;
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1457e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm = NLMSG_DATA(nlh);
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
146016ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet	tcm->tcm__pad1 = 0;
146116ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet	tcm->tcm__pad2 = 0;
14625ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = q->handle;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = 0;
146657e1c487a4f5754cb77abeb00adb21faa88c484fPatrick McHardy	NLA_PUT_STRING(skb, TCA_KIND, q->ops->id);
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0)
14681e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1470102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
1471102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski					 qdisc_root_sleeping_lock(q), &d) < 0)
14721e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0)
14751e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
14781e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148027a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure:
14841e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
1485dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo	nlmsg_trim(skb, b);
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  struct Qdisc *q, unsigned long cl, int event)
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tc_fill_tclass(skb, q, cl, pid, n->nlmsg_seq, 0, event) < 0) {
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
150497c53cacf00d1f5aa04adabfebcc806ca8b22b10Denis V. Lunev	return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct qdisc_dump_args
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_walker w;
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netlink_callback *cb;
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg)
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_dump_args *a = (struct qdisc_dump_args *)arg;
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tc_fill_tclass(a->skb, q, cl, NETLINK_CB(a->cb->skb).pid,
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS);
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15223072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb,
15233072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				struct tcmsg *tcm, struct netlink_callback *cb,
15243072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				int *t_p, int s_t)
15253072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
15263072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct qdisc_dump_args arg;
15273072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15283072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (tc_qdisc_dump_ignore(q) ||
15293072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	    *t_p < s_t || !q->ops->cl_ops ||
15303072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	    (tcm->tcm_parent &&
15313072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	     TC_H_MAJ(tcm->tcm_parent) != q->handle)) {
15323072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		(*t_p)++;
15333072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
15343072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
15353072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (*t_p > s_t)
15363072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
15373072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.fn = qdisc_class_dump;
15383072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.skb = skb;
15393072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.cb = cb;
15403072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.stop  = 0;
15413072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.skip = cb->args[1];
15423072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.count = 0;
15433072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	q->ops->cl_ops->walk(q, &arg.w);
15443072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	cb->args[1] = arg.w.count;
15453072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (arg.w.stop)
15463072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return -1;
15473072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	(*t_p)++;
15483072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return 0;
15493072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
15503072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15513072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb,
15523072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			       struct tcmsg *tcm, struct netlink_callback *cb,
15533072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			       int *t_p, int s_t)
15543072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
15553072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct Qdisc *q;
15563072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15573072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (!root)
15583072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
15593072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15603072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0)
15613072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return -1;
15623072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15633072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	list_for_each_entry(q, &root->list, list) {
15643072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0)
15653072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			return -1;
15663072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
15673072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15683072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return 0;
15693072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
15703072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15733072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh);
15743b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
15753072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct netdev_queue *dev_queue;
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
15773072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	int t, s_t;
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
157909ad9bc752519cc167d0a573e1acf69b5c707c67Octavian Purdila	if (!net_eq(net, &init_net))
1580b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev		return 0;
1581b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1584881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman	if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_t = cb->args[0];
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t = 0;
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1590af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy	if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0)
15913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		goto done;
15923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	dev_queue = &dev->rx_queue;
15948123b421e8ed944671d7241323ed3198cccb4041David S. Miller	if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0)
15953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		goto done;
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone:
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = t;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Main classifier routine: scans classifier chain attached
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to this qdisc, (optionally) tests for protocol and asks
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   specific classifiers.
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
160873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyint tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp,
160973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		       struct tcf_result *res)
161073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy{
161173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	__be16 protocol = skb->protocol;
161273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	int err = 0;
161373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
161473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	for (; tp; tp = tp->next) {
161573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		if ((tp->protocol == protocol ||
161673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		     tp->protocol == htons(ETH_P_ALL)) &&
161773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		    (err = tp->classify(skb, tp, res)) >= 0) {
161873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#ifdef CONFIG_NET_CLS_ACT
161973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			if (err != TC_ACT_RECLASSIFY && skb->tc_verd)
162073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy				skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0);
162173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif
162273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			return err;
162373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		}
162473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	}
162573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	return -1;
162673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy}
162773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify_compat);
162873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
163073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		struct tcf_result *res)
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
163373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	__be16 protocol;
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcf_proto *otp = tp;
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreclassify:
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	protocol = skb->protocol;
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
164073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	err = tc_classify_compat(skb, tp, res);
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
164273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	if (err == TC_ACT_RECLASSIFY) {
164373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		u32 verd = G_TC_VERD(skb->tc_verd);
164473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		tp = otp;
164573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
164673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		if (verd++ >= MAX_REC_LOOP) {
164773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			printk("rule prio %u protocol %02x reclassify loop, "
164873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			       "packet dropped\n",
164973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			       tp->prio&0xffff, ntohs(tp->protocol));
165073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			return TC_ACT_SHOT;
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
165273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd);
165373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		goto reclassify;
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
165573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif
165673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	return err;
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
165873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify);
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1660a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyvoid tcf_destroy(struct tcf_proto *tp)
1661a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{
1662a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	tp->ops->destroy(tp);
1663a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	module_put(tp->ops->owner);
1664a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	kfree(tp);
1665a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy}
1666a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
1667ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardyvoid tcf_destroy_chain(struct tcf_proto **fl)
1668a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{
1669a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	struct tcf_proto *tp;
1670a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
1671ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy	while ((tp = *fl) != NULL) {
1672ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy		*fl = tp->next;
1673a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy		tcf_destroy(tp);
1674a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	}
1675a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy}
1676a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyEXPORT_SYMBOL(tcf_destroy_chain);
1677a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_show(struct seq_file *seq, void *v)
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16813c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy	struct timespec ts;
16823c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy
16833c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy	hrtimer_get_res(CLOCK_MONOTONIC, &ts);
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_printf(seq, "%08x %08x %08x %08x\n",
1685ca44d6e60f9de26281fda203f58b570e1748c015Jarek Poplawski		   (u32)NSEC_PER_USEC, (u32)PSCHED_TICKS2NS(1),
1686514bca322cb9220308d22691ac1e74038bfabac3Patrick McHardy		   1000000,
16873c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy		   (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts)));
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_open(struct inode *inode, struct file *file)
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return single_open(file, psched_show, PDE(inode)->data);
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1697da7071d7e32d15149cc513f096a3638097b66387Arjan van de Venstatic const struct file_operations psched_fops = {
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner = THIS_MODULE,
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = psched_open,
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read  = seq_read,
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek = seq_lseek,
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release = single_release,
170310297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki};
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pktsched_init(void)
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&pfifo_qdisc_ops);
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&bfifo_qdisc_ops);
171057dbb2d83d100ea601c54fe129bfde0678db5deeHagen Paul Pfeifer	register_qdisc(&pfifo_head_drop_qdisc_ops);
17116ec1c69a8f6492fd25722f4762721921da074c12David S. Miller	register_qdisc(&mq_qdisc_ops);
1712457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman	proc_net_fops_create(&init_net, "psched", 0, &psched_fops);
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1714be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL);
1715be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL);
1716be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc);
1717be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL);
1718be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL);
1719be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf	rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass);
1720be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(pktsched_init);
1725