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