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