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