sch_api.c revision 4d8863a29c4755a0461cd31b6865026187d6c43a
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * net/sched/sch_api.c Packet scheduler API. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes: 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Rani Assaf <rani@magic.metawire.com> :980802: JIFFIES and CPU clock sources are repaired. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Eduardo J. Blanco <ejbs@netlabs.com.uy> :990222: kmod support 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Jamal Hadi Salim <hadi@nortelnetworks.com>: 990601: ingress support 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kmod.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 294179477f637caa730626bd597fdf28c5bad73565Patrick McHardy#include <linux/hrtimer.h> 3025bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski#include <linux/lockdep.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h> 33b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev#include <net/sock.h> 34dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo#include <net/netlink.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *old, struct Qdisc *new); 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q, unsigned long cl, int event); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Short review. 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ------------- 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This file consists of two interrelated parts: 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1. queueing disciplines manager frontend. 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2. traffic classes manager frontend. 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Generally, queueing discipline ("qdisc") is a black box, 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds which is able to enqueue packets and to dequeue them (when 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device is ready to send something) in order and at times 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds determined by algorithm hidden in it. 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qdisc's are divided to two categories: 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - "queues", which have no internal structure visible from outside. 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - "schedulers", which split all the packets to "traffic classes", 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds using "packet classifiers" (look at cls_api.c) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds In turn, classes may have child qdiscs (as rule, queues) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds attached to them etc. etc. etc. 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The goal of the routines in this file is to translate 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds information supplied by user in the form of handles 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to more intelligible for kernel form, to make some sanity 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checks and part of work, which is common to all qdiscs 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and to provide rtnetlink notifications. 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds All real intelligent work is done inside qdisc modules. 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Every discipline has two major routines: enqueue and dequeue. 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---dequeue 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dequeue usually returns a skb to send. It is allowed to return NULL, 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but it does not mean that queue is empty, it just means that 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds discipline does not want to send anything this time. 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Queue is really empty if q->q.qlen == 0. 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds For complicated disciplines with multiple queues q->q is not 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds real packet queue, but however q->q.qlen must be valid. 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---enqueue 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enqueue returns 0, if packet was enqueued successfully. 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds If packet (this one or another one) was dropped, it returns 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds not zero error code. 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NET_XMIT_DROP - this packet dropped 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Expected action: do not backoff, but wait until queue will clear. 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NET_XMIT_CN - probably this packet enqueued, but another one dropped. 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Expected action: backoff or ignore 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NET_XMIT_POLICED - dropped by police. 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Expected action: backoff or error to real-time apps. 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Auxiliary routines: 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---requeue 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds requeues once dequeued packet. It is used for non-standard or 103e65d22e18038eed7307276e46810d884c402d57dDavid S. Miller just buggy devices, which can defer output even if netif_queue_stopped()=0. 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---reset 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds returns qdisc to initial state: purge all buffers, clear all 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timers, counters (except for statistics) etc. 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---init 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initializes newly created qdisc. 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---destroy 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds destroys resources allocated by init and during lifetime of qdisc. 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---change 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds changes qdisc parameters. 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protects list of registered TC modules. It is pure SMP lock. */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_RWLOCK(qdisc_mod_lock); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Queueing disciplines manipulation. * 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The list of all installed queueing disciplines. */ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_ops *qdisc_base; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register/uregister queueing discipline */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint register_qdisc(struct Qdisc_ops *qops) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc_ops *q, **qp; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EEXIST; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_lock(&qdisc_mod_lock); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!strcmp(qops->id, q->id)) 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qops->enqueue == NULL) 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qops->enqueue = noop_qdisc_ops.enqueue; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qops->requeue == NULL) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qops->requeue = noop_qdisc_ops.requeue; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qops->dequeue == NULL) 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qops->dequeue = noop_qdisc_ops.dequeue; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qops->next = NULL; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *qp = qops; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_unlock(&qdisc_mod_lock); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16262e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(register_qdisc); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint unregister_qdisc(struct Qdisc_ops *qops) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc_ops *q, **qp; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -ENOENT; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_lock(&qdisc_mod_lock); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == qops) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q) { 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *qp = q->next; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->next = NULL; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = 0; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_unlock(&qdisc_mod_lock); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18162e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(unregister_qdisc); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We know handle. Find qdisc among all qdisc's attached to device 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (root qdisc, all its children, children of children etc.) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1878123b421e8ed944671d7241323ed3198cccb4041David S. Millerstruct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) 1888123b421e8ed944671d7241323ed3198cccb4041David S. Miller{ 1898123b421e8ed944671d7241323ed3198cccb4041David S. Miller struct Qdisc *q; 1908123b421e8ed944671d7241323ed3198cccb4041David S. Miller 1918123b421e8ed944671d7241323ed3198cccb4041David S. Miller if (!(root->flags & TCQ_F_BUILTIN) && 1928123b421e8ed944671d7241323ed3198cccb4041David S. Miller root->handle == handle) 1938123b421e8ed944671d7241323ed3198cccb4041David S. Miller return root; 1948123b421e8ed944671d7241323ed3198cccb4041David S. Miller 1958123b421e8ed944671d7241323ed3198cccb4041David S. Miller list_for_each_entry(q, &root->list, list) { 1968123b421e8ed944671d7241323ed3198cccb4041David S. Miller if (q->handle == handle) 1978123b421e8ed944671d7241323ed3198cccb4041David S. Miller return q; 1988123b421e8ed944671d7241323ed3198cccb4041David S. Miller } 1998123b421e8ed944671d7241323ed3198cccb4041David S. Miller return NULL; 2008123b421e8ed944671d7241323ed3198cccb4041David S. Miller} 2018123b421e8ed944671d7241323ed3198cccb4041David S. Miller 202ead81cc5fc6d996db6afb20f211241612610a07aDavid S. Millerstruct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller unsigned int i; 2053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 2063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller for (i = 0; i < dev->num_tx_queues; i++) { 2073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netdev_queue *txq = netdev_get_tx_queue(dev, i); 208827ebd6410005b05b3c930ef6a116666c6986886David S. Miller struct Qdisc *q, *txq_root = txq->qdisc_sleeping; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2108123b421e8ed944671d7241323ed3198cccb4041David S. Miller q = qdisc_match_from_root(txq_root, handle); 2118123b421e8ed944671d7241323ed3198cccb4041David S. Miller if (q) 2128123b421e8ed944671d7241323ed3198cccb4041David S. Miller return q; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2148123b421e8ed944671d7241323ed3198cccb4041David S. Miller return qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *leaf; 22120fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops = p->ops->cl_ops; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cops == NULL) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cl = cops->get(p, classid); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl == 0) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds leaf = cops->leaf(p, cl); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops->put(p, cl); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return leaf; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find queueing discipline by name */ 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic struct Qdisc_ops *qdisc_lookup_ops(struct nlattr *kind) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc_ops *q = NULL; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind) { 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock(&qdisc_mod_lock); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (q = qdisc_base; q; q = q->next) { 2431e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (nla_strcmp(kind, q->id) == 0) { 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!try_module_get(q->owner)) 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = NULL; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&qdisc_mod_lock); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return q; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct qdisc_rate_table *qdisc_rtab_list; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystruct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab) 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_rate_table *rtab; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) == 0) { 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->refcnt++; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rtab; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2675feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy if (tab == NULL || r->rate == 0 || r->cell_log == 0 || 2685feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy nla_len(tab) != TC_RTAB_SIZE) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab = kmalloc(sizeof(*rtab), GFP_KERNEL); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rtab) { 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->rate = *r; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->refcnt = 1; 2751e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy memcpy(rtab->data, nla_data(tab), 1024); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->next = qdisc_rtab_list; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qdisc_rtab_list = rtab; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rtab; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28162e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_get_rtab); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qdisc_put_rtab(struct qdisc_rate_table *tab) 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_rate_table *rtab, **rtabp; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tab || --tab->refcnt) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (rtabp = &qdisc_rtab_list; (rtab=*rtabp) != NULL; rtabp = &rtab->next) { 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rtab == tab) { 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *rtabp = rtab->next; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(rtab); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29862e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_put_rtab); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 300175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic LIST_HEAD(qdisc_stab_list); 301175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic DEFINE_SPINLOCK(qdisc_stab_lock); 302175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 303175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = { 304175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna [TCA_STAB_BASE] = { .len = sizeof(struct tc_sizespec) }, 305175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna [TCA_STAB_DATA] = { .type = NLA_BINARY }, 306175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}; 307175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 308175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) 309175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 310175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct nlattr *tb[TCA_STAB_MAX + 1]; 311175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct qdisc_size_table *stab; 312175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct tc_sizespec *s; 313175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna unsigned int tsize = 0; 314175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna u16 *tab = NULL; 315175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna int err; 316175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 317175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy); 318175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (err < 0) 319175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(err); 320175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!tb[TCA_STAB_BASE]) 321175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-EINVAL); 322175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 323175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna s = nla_data(tb[TCA_STAB_BASE]); 324175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 325175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (s->tsize > 0) { 326175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!tb[TCA_STAB_DATA]) 327175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-EINVAL); 328175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna tab = nla_data(tb[TCA_STAB_DATA]); 329175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); 330175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 331175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 332175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!s || tsize != s->tsize || (!tab && tsize > 0)) 333175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-EINVAL); 334175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 3351cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski spin_lock_bh(&qdisc_stab_lock); 336175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 337175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna list_for_each_entry(stab, &qdisc_stab_list, list) { 338175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (memcmp(&stab->szopts, s, sizeof(*s))) 339175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna continue; 340175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16))) 341175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna continue; 342175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->refcnt++; 3431cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski spin_unlock_bh(&qdisc_stab_lock); 344175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return stab; 345175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 346175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 3471cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski spin_unlock_bh(&qdisc_stab_lock); 348175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 349175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL); 350175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!stab) 351175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-ENOMEM); 352175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 353175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->refcnt = 1; 354175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->szopts = *s; 355175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tsize > 0) 356175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna memcpy(stab->data, tab, tsize * sizeof(u16)); 357175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 3581cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski spin_lock_bh(&qdisc_stab_lock); 359175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna list_add_tail(&stab->list, &qdisc_stab_list); 3601cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski spin_unlock_bh(&qdisc_stab_lock); 361175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 362175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return stab; 363175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 364175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 365175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_put_stab(struct qdisc_size_table *tab) 366175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 367175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!tab) 368175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return; 369175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 3701cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski spin_lock_bh(&qdisc_stab_lock); 371175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 372175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (--tab->refcnt == 0) { 373175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna list_del(&tab->list); 374175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna kfree(tab); 375175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 376175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 3771cfa26661a85549063e369e2b40275eeaa7b923cJarek Poplawski spin_unlock_bh(&qdisc_stab_lock); 378175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 379175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_put_stab); 380175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 381175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab) 382175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 383175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct nlattr *nest; 384175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 385175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna nest = nla_nest_start(skb, TCA_STAB); 386175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna NLA_PUT(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts); 387175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna nla_nest_end(skb, nest); 388175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 389175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return skb->len; 390175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 391175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnanla_put_failure: 392175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return -1; 393175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 394175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 395175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_calculate_pkt_len(struct sk_buff *skb, struct qdisc_size_table *stab) 396175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 397175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna int pkt_len, slot; 398175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 399175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = skb->len + stab->szopts.overhead; 400175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (unlikely(!stab->szopts.tsize)) 401175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna goto out; 402175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 403175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna slot = pkt_len + stab->szopts.cell_align; 404175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (unlikely(slot < 0)) 405175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna slot = 0; 406175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 407175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna slot >>= stab->szopts.cell_log; 408175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (likely(slot < stab->szopts.tsize)) 409175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = stab->data[slot]; 410175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna else 411175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = stab->data[stab->szopts.tsize - 1] * 412175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna (slot / stab->szopts.tsize) + 413175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->data[slot % stab->szopts.tsize]; 414175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 415175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len <<= stab->szopts.size_log; 416175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnaout: 417175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (unlikely(pkt_len < 1)) 418175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = 1; 419175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna qdisc_skb_cb(skb)->pkt_len = pkt_len; 420175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 421175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_calculate_pkt_len); 422175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 4234179477f637caa730626bd597fdf28c5bad73565Patrick McHardystatic enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) 4244179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4254179477f637caa730626bd597fdf28c5bad73565Patrick McHardy struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, 4264179477f637caa730626bd597fdf28c5bad73565Patrick McHardy timer); 4274179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 4284179477f637caa730626bd597fdf28c5bad73565Patrick McHardy wd->qdisc->flags &= ~TCQ_F_THROTTLED; 42911274e5a43266d531140530adebead6903380cafStephen Hemminger smp_wmb(); 4308608db031b4d2932d645709e2cfe8fbcd91a7305David S. Miller __netif_schedule(qdisc_root(wd->qdisc)); 4311936502d00ae6c2aa3931c42f6cf54afaba094f2Stephen Hemminger 4324179477f637caa730626bd597fdf28c5bad73565Patrick McHardy return HRTIMER_NORESTART; 4334179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 4344179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 4354179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc) 4364179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4374179477f637caa730626bd597fdf28c5bad73565Patrick McHardy hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 4384179477f637caa730626bd597fdf28c5bad73565Patrick McHardy wd->timer.function = qdisc_watchdog; 4394179477f637caa730626bd597fdf28c5bad73565Patrick McHardy wd->qdisc = qdisc; 4404179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 4414179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_init); 4424179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 4434179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires) 4444179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4454179477f637caa730626bd597fdf28c5bad73565Patrick McHardy ktime_t time; 4464179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 4474179477f637caa730626bd597fdf28c5bad73565Patrick McHardy wd->qdisc->flags |= TCQ_F_THROTTLED; 4484179477f637caa730626bd597fdf28c5bad73565Patrick McHardy time = ktime_set(0, 0); 4494179477f637caa730626bd597fdf28c5bad73565Patrick McHardy time = ktime_add_ns(time, PSCHED_US2NS(expires)); 4504179477f637caa730626bd597fdf28c5bad73565Patrick McHardy hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS); 4514179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 4524179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_schedule); 4534179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 4544179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_cancel(struct qdisc_watchdog *wd) 4554179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4564179477f637caa730626bd597fdf28c5bad73565Patrick McHardy hrtimer_cancel(&wd->timer); 4574179477f637caa730626bd597fdf28c5bad73565Patrick McHardy wd->qdisc->flags &= ~TCQ_F_THROTTLED; 4584179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 4594179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_cancel); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461a94f779f9d82eb2d758a8715eaae5df98e8dcb21Adrian Bunkstatic struct hlist_head *qdisc_class_hash_alloc(unsigned int n) 4626fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 4636fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int size = n * sizeof(struct hlist_head), i; 4646fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct hlist_head *h; 4656fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 4666fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (size <= PAGE_SIZE) 4676fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy h = kmalloc(size, GFP_KERNEL); 4686fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy else 4696fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy h = (struct hlist_head *) 4706fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy __get_free_pages(GFP_KERNEL, get_order(size)); 4716fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 4726fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (h != NULL) { 4736fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy for (i = 0; i < n; i++) 4746fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy INIT_HLIST_HEAD(&h[i]); 4756fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy } 4766fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return h; 4776fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 4786fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 4796fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardystatic void qdisc_class_hash_free(struct hlist_head *h, unsigned int n) 4806fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 4816fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int size = n * sizeof(struct hlist_head); 4826fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 4836fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (size <= PAGE_SIZE) 4846fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy kfree(h); 4856fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy else 4866fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy free_pages((unsigned long)h, get_order(size)); 4876fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 4886fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 4896fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_grow(struct Qdisc *sch, struct Qdisc_class_hash *clhash) 4906fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 4916fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct Qdisc_class_common *cl; 4926fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct hlist_node *n, *next; 4936fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct hlist_head *nhash, *ohash; 4946fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int nsize, nmask, osize; 4956fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int i, h; 4966fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 4976fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy /* Rehash when load factor exceeds 0.75 */ 4986fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (clhash->hashelems * 4 <= clhash->hashsize * 3) 4996fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return; 5006fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy nsize = clhash->hashsize * 2; 5016fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy nmask = nsize - 1; 5026fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy nhash = qdisc_class_hash_alloc(nsize); 5036fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (nhash == NULL) 5046fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return; 5056fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5066fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy ohash = clhash->hash; 5076fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy osize = clhash->hashsize; 5086fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5096fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy sch_tree_lock(sch); 5106fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy for (i = 0; i < osize; i++) { 5116fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy hlist_for_each_entry_safe(cl, n, next, &ohash[i], hnode) { 5126fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy h = qdisc_class_hash(cl->classid, nmask); 5136fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy hlist_add_head(&cl->hnode, &nhash[h]); 5146fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy } 5156fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy } 5166fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hash = nhash; 5176fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashsize = nsize; 5186fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashmask = nmask; 5196fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy sch_tree_unlock(sch); 5206fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5216fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy qdisc_class_hash_free(ohash, osize); 5226fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 5236fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_grow); 5246fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5256fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyint qdisc_class_hash_init(struct Qdisc_class_hash *clhash) 5266fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 5276fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int size = 4; 5286fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5296fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hash = qdisc_class_hash_alloc(size); 5306fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (clhash->hash == NULL) 5316fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return -ENOMEM; 5326fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashsize = size; 5336fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashmask = size - 1; 5346fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashelems = 0; 5356fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return 0; 5366fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 5376fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_init); 5386fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5396fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_destroy(struct Qdisc_class_hash *clhash) 5406fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 5416fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy qdisc_class_hash_free(clhash->hash, clhash->hashsize); 5426fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 5436fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_destroy); 5446fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5456fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_insert(struct Qdisc_class_hash *clhash, 5466fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct Qdisc_class_common *cl) 5476fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 5486fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int h; 5496fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5506fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy INIT_HLIST_NODE(&cl->hnode); 5516fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy h = qdisc_class_hash(cl->classid, clhash->hashmask); 5526fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy hlist_add_head(&cl->hnode, &clhash->hash[h]); 5536fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashelems++; 5546fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 5556fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_insert); 5566fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5576fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_remove(struct Qdisc_class_hash *clhash, 5586fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct Qdisc_class_common *cl) 5596fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 5606fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy hlist_del(&cl->hnode); 5616fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashelems--; 5626fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 5636fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_remove); 5646fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Allocate an unique handle from space managed by kernel */ 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 qdisc_alloc_handle(struct net_device *dev) 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0x10000; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static u32 autohandle = TC_H_MAKE(0x80000000U, 0); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds autohandle += TC_H_MAKE(0x10000U, 0); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (autohandle == TC_H_MAKE(TC_H_ROOT, 0)) 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds autohandle = TC_H_MAKE(0x80000000U, 0); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (qdisc_lookup(dev, autohandle) && --i > 0); 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i>0 ? autohandle : 0; 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58199194cff398d056e5ee469647c294466c246c88aDavid S. Miller/* Attach toplevel qdisc to device queue. */ 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58399194cff398d056e5ee469647c294466c246c88aDavid S. Millerstatic struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, 58499194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct Qdisc *qdisc) 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5868d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller struct Qdisc *oqdisc = dev_queue->qdisc_sleeping; 58753049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller spinlock_t *root_lock; 58853049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller 58953049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller root_lock = qdisc_root_lock(oqdisc); 59053049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller spin_lock_bh(root_lock); 59153049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller 5928d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller /* Prune old scheduler */ 5938d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) 5948d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller qdisc_reset(oqdisc); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5968d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller /* ... and graft new one */ 5978d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller if (qdisc == NULL) 5988d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller qdisc = &noop_qdisc; 5998d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller dev_queue->qdisc_sleeping = qdisc; 6008d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller dev_queue->qdisc = &noop_qdisc; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60253049978df1d9ae55bf397c9879e6b33218352dbDavid S. Miller spin_unlock_bh(root_lock); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return oqdisc; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyvoid qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) 60843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy{ 60920fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops; 61043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy unsigned long cl; 61143effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy u32 parentid; 61243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy 61343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy if (n == 0) 61443effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy return; 61543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy while ((parentid = sch->parent)) { 616066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS)) 617066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski return; 618066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski 6195ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid)); 620ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy if (sch == NULL) { 621ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy WARN_ON(parentid != TC_H_ROOT); 622ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy return; 623ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy } 62443effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy cops = sch->ops->cl_ops; 62543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy if (cops->qlen_notify) { 62643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy cl = cops->get(sch, parentid); 62743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy cops->qlen_notify(sch, cl); 62843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy cops->put(sch, cl); 62943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy } 63043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy sch->q.qlen -= n; 63143effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy } 63243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy} 63343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyEXPORT_SYMBOL(qdisc_tree_decrease_qlen); 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63599194cff398d056e5ee469647c294466c246c88aDavid S. Millerstatic void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid, 63699194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct Qdisc *old, struct Qdisc *new) 63799194cff398d056e5ee469647c294466c246c88aDavid S. Miller{ 63899194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (new || old) 63999194cff398d056e5ee469647c294466c246c88aDavid S. Miller qdisc_notify(skb, n, clid, old, new); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6414d8863a29c4755a0461cd31b6865026187d6c43aDavid S. Miller if (old) 64299194cff398d056e5ee469647c294466c246c88aDavid S. Miller qdisc_destroy(old); 64399194cff398d056e5ee469647c294466c246c88aDavid S. Miller} 64499194cff398d056e5ee469647c294466c246c88aDavid S. Miller 64599194cff398d056e5ee469647c294466c246c88aDavid S. Miller/* Graft qdisc "new" to class "classid" of qdisc "parent" or 64699194cff398d056e5ee469647c294466c246c88aDavid S. Miller * to device "dev". 64799194cff398d056e5ee469647c294466c246c88aDavid S. Miller * 64899194cff398d056e5ee469647c294466c246c88aDavid S. Miller * When appropriate send a netlink notification using 'skb' 64999194cff398d056e5ee469647c294466c246c88aDavid S. Miller * and "n". 65099194cff398d056e5ee469647c294466c246c88aDavid S. Miller * 65199194cff398d056e5ee469647c294466c246c88aDavid S. Miller * On success, destroy old qdisc. 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_graft(struct net_device *dev, struct Qdisc *parent, 65599194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct sk_buff *skb, struct nlmsghdr *n, u32 classid, 65699194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct Qdisc *new, struct Qdisc *old) 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 65899194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct Qdisc *q = old; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki if (parent == NULL) { 66299194cff398d056e5ee469647c294466c246c88aDavid S. Miller unsigned int i, num_q, ingress; 66399194cff398d056e5ee469647c294466c246c88aDavid S. Miller 66499194cff398d056e5ee469647c294466c246c88aDavid S. Miller ingress = 0; 66599194cff398d056e5ee469647c294466c246c88aDavid S. Miller num_q = dev->num_tx_queues; 6668d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller if ((q && q->flags & TCQ_F_INGRESS) || 6678d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller (new && new->flags & TCQ_F_INGRESS)) { 66899194cff398d056e5ee469647c294466c246c88aDavid S. Miller num_q = 1; 66999194cff398d056e5ee469647c294466c246c88aDavid S. Miller ingress = 1; 67099194cff398d056e5ee469647c294466c246c88aDavid S. Miller } 67199194cff398d056e5ee469647c294466c246c88aDavid S. Miller 67299194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (dev->flags & IFF_UP) 67399194cff398d056e5ee469647c294466c246c88aDavid S. Miller dev_deactivate(dev); 67499194cff398d056e5ee469647c294466c246c88aDavid S. Miller 67599194cff398d056e5ee469647c294466c246c88aDavid S. Miller for (i = 0; i < num_q; i++) { 67699194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct netdev_queue *dev_queue = &dev->rx_queue; 67799194cff398d056e5ee469647c294466c246c88aDavid S. Miller 67899194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (!ingress) 67999194cff398d056e5ee469647c294466c246c88aDavid S. Miller dev_queue = netdev_get_tx_queue(dev, i); 68099194cff398d056e5ee469647c294466c246c88aDavid S. Miller 6818d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller old = dev_graft_qdisc(dev_queue, new); 6828d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller if (new && i > 0) 6838d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller atomic_inc(&new->refcnt); 6848d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller 68599194cff398d056e5ee469647c294466c246c88aDavid S. Miller notify_and_destroy(skb, n, classid, old, new); 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 68799194cff398d056e5ee469647c294466c246c88aDavid S. Miller 68899194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (dev->flags & IFF_UP) 68999194cff398d056e5ee469647c294466c246c88aDavid S. Miller dev_activate(dev); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 69120fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops = parent->ops->cl_ops; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cops) { 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl = cops->get(parent, classid); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl) { 69899194cff398d056e5ee469647c294466c246c88aDavid S. Miller err = cops->graft(parent, cl, new, &old); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops->put(parent, cl); 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 70299194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (!err) 70399194cff398d056e5ee469647c294466c246c88aDavid S. Miller notify_and_destroy(skb, n, classid, old, new); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70825bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski/* lockdep annotation is needed for ingress; egress gets it only for name */ 70925bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_tx_lock; 71025bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_rx_lock; 71125bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Allocate and initialize new qdisc. 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Parameters are passed via opt. 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc * 719bb949fbd1878973c3539d9aecff52f284482a937David S. Millerqdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, 720bb949fbd1878973c3539d9aecff52f284482a937David S. Miller u32 parent, u32 handle, struct nlattr **tca, int *errp) 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 7231e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *kind = tca[TCA_KIND]; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *sch; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc_ops *ops; 726175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct qdisc_size_table *stab; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ops = qdisc_lookup_ops(kind); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_KMOD 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ops == NULL && kind != NULL) { 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char name[IFNAMSIZ]; 7321e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We dropped the RTNL semaphore in order to 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * perform the module load. So, even if we 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * succeeded in loading the module we have to 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tell the caller to replay the request. We 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * indicate this using -EAGAIN. 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We replay the request because the device may 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * go away in the mean time. 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtnl_unlock(); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_module("sch_%s", name); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtnl_lock(); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ops = qdisc_lookup_ops(kind); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ops != NULL) { 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We will try again qdisc_lookup_ops, 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so don't keep a reference. 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds module_put(ops->owner); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EAGAIN; 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 757b9e2cc0f0e47ad351349156018ef8a365e9c6d25Jamal Hadi Salim err = -ENOENT; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ops == NULL) 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7615ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller sch = qdisc_alloc(dev_queue, ops); 7623d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf if (IS_ERR(sch)) { 7633d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf err = PTR_ERR(sch); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out2; 7653d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf } 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 767ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy sch->parent = parent; 768ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy 7693d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf if (handle == TC_H_INGRESS) { 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sch->flags |= TCQ_F_INGRESS; 7713d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf handle = TC_H_MAKE(TC_H_INGRESS, 0); 77225bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock); 773fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy } else { 774fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy if (handle == 0) { 775fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy handle = qdisc_alloc_handle(dev); 776fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy err = -ENOMEM; 777fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy if (handle == 0) 778fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy goto err_out3; 779fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy } 78025bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock); 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7833d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf sch->handle = handle; 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) { 786175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tca[TCA_STAB]) { 787175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab = qdisc_get_stab(tca[TCA_STAB]); 788175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (IS_ERR(stab)) { 789175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna err = PTR_ERR(stab); 790175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna goto err_out3; 791175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 792175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna sch->stab = stab; 793175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 7941e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_RATE]) { 795023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf err = gen_new_estimator(&sch->bstats, &sch->rate_est, 7967698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller qdisc_root_lock(sch), 7971e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy tca[TCA_RATE]); 798023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf if (err) { 799023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf /* 800023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf * Any broken qdiscs that would require 801023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf * a ops->reset() here? The qdisc was never 802023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf * in action so it shouldn't be necessary. 803023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf */ 804023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf if (ops->destroy) 805023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf ops->destroy(sch); 806023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf goto err_out3; 807023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf } 808023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf } 809ee7af8264dafa0c8c76a8dc596803966c2e29ebcDavid S. Miller if ((parent != TC_H_ROOT) && !(sch->flags & TCQ_F_INGRESS)) 810827ebd6410005b05b3c930ef6a116666c6986886David S. Miller list_add_tail(&sch->list, &dev_queue->qdisc_sleeping->list); 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sch; 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out3: 815175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna qdisc_put_stab(sch->stab); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(dev); 8173d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf kfree((char *) sch - sch->padded); 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out2: 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds module_put(ops->owner); 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out: 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *errp = err; 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8251e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int qdisc_change(struct Qdisc *sch, struct nlattr **tca) 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 827175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct qdisc_size_table *stab = NULL; 828175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna int err = 0; 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 830175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tca[TCA_OPTIONS]) { 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sch->ops->change == NULL) 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 8331e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = sch->ops->change(sch, tca[TCA_OPTIONS]); 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 837175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 838175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tca[TCA_STAB]) { 839175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab = qdisc_get_stab(tca[TCA_STAB]); 840175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (IS_ERR(stab)) 841175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return PTR_ERR(stab); 842175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 843175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 844175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna qdisc_put_stab(sch->stab); 845175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna sch->stab = stab; 846175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 8471e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_RATE]) 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gen_replace_estimator(&sch->bstats, &sch->rate_est, 8497698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller qdisc_root_lock(sch), tca[TCA_RATE]); 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct check_loop_arg 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_walker w; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *p; 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int depth; 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w); 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop(struct Qdisc *q, struct Qdisc *p, int depth) 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct check_loop_arg arg; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->ops->cl_ops == NULL) 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.w.stop = arg.w.skip = arg.w.count = 0; 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.w.fn = check_loop_fn; 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.depth = depth; 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.p = p; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->ops->cl_ops->walk(q, &arg.w); 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return arg.w.stop ? -ELOOP : 0; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w) 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *leaf; 88120fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops = q->ops->cl_ops; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct check_loop_arg *arg = (struct check_loop_arg *)w; 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds leaf = cops->leaf(q, cl); 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (leaf) { 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (leaf == arg->p || arg->depth > 7) 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ELOOP; 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return check_loop(leaf, arg->p, arg->depth + 1); 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete/get qdisc. 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8993b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm = NLMSG_DATA(n); 9011e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *tca[TCA_MAX + 1]; 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clid = tcm->tcm_parent; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q = NULL; 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *p = NULL; 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 908b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev if (net != &init_net) 909b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev return -EINVAL; 910b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev 911881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9141e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 9151e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (err < 0) 9161e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy return err; 9171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid) { 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid != TC_H_ROOT) { 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) { 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = qdisc_leaf(p, clid); 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* ingress */ 9258123b421e8ed944671d7241323ed3198cccb4041David S. Miller q = dev->rx_queue.qdisc_sleeping; 92610297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki } 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 928e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller struct netdev_queue *dev_queue; 929e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller dev_queue = netdev_get_tx_queue(dev, 0); 930b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller q = dev_queue->qdisc_sleeping; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!q) 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tcm->tcm_handle && q->handle != tcm->tcm_handle) 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL) 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9421e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n->nlmsg_type == RTM_DELQDISC) { 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!clid) 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->handle == 0) 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 95099194cff398d056e5ee469647c294466c246c88aDavid S. Miller if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0) 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qdisc_notify(skb, n, clid, NULL, q); 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Create/change qdisc. 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9643b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm; 9661e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *tca[TCA_MAX + 1]; 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clid; 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q, *p; 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 972b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev if (net != &init_net) 973b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev return -EINVAL; 974b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreplay: 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reinit, just in case something touches this. */ 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm = NLMSG_DATA(n); 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clid = tcm->tcm_parent; 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = p = NULL; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9841e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 9851e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (err < 0) 9861e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy return err; 9871e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid) { 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid != TC_H_ROOT) { 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid != TC_H_INGRESS) { 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = qdisc_leaf(p, clid); 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /*ingress */ 9958123b421e8ed944671d7241323ed3198cccb4041David S. Miller q = dev->rx_queue.qdisc_sleeping; 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 998e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller struct netdev_queue *dev_queue; 999e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller dev_queue = netdev_get_tx_queue(dev, 0); 1000b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller q = dev_queue->qdisc_sleeping; 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* It may be default qdisc, ignore it */ 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q && q->handle == 0) 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = NULL; 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) { 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tcm->tcm_handle) { 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q && !(n->nlmsg_flags&NLM_F_REPLACE)) 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (TC_H_MIN(tcm->tcm_handle)) 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL) 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto create_n_graft; 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n->nlmsg_flags&NLM_F_EXCL) 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 10171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == p || 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (p && check_loop(q, p, 0))) 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ELOOP; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&q->refcnt); 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto graft; 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == NULL) 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto create_n_graft; 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This magic test requires explanation. 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We know, that some child q is already 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attached to this parent and have choice: 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * either to change it or to create/graft new one. 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. We are allowed to create/graft only 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if CREATE and REPLACE flags are set. 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. If EXCL is set, requestor wanted to say, 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that qdisc tcm_handle is not expected 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to exist, so that we choose create/graft too. 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3. The last case is when no flags are set. 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alas, it is sort of hole in API, we 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cannot decide what to do unambiguously. 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For now we select create/graft, if 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * user gave KIND, which does not match existing. 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((n->nlmsg_flags&NLM_F_CREATE) && 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (n->nlmsg_flags&NLM_F_REPLACE) && 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((n->nlmsg_flags&NLM_F_EXCL) || 10501e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy (tca[TCA_KIND] && 10511e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy nla_strcmp(tca[TCA_KIND], q->ops->id)))) 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto create_n_graft; 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tcm->tcm_handle) 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = qdisc_lookup(dev, tcm->tcm_handle); 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Change qdisc parameters */ 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == NULL) 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n->nlmsg_flags&NLM_F_EXCL) 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 10661e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = qdisc_change(q, tca); 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == 0) 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qdisc_notify(skb, n, clid, NULL, q); 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscreate_n_graft: 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(n->nlmsg_flags&NLM_F_CREATE)) 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid == TC_H_INGRESS) 1077bb949fbd1878973c3539d9aecff52f284482a937David S. Miller q = qdisc_create(dev, &dev->rx_queue, 1078bb949fbd1878973c3539d9aecff52f284482a937David S. Miller tcm->tcm_parent, tcm->tcm_parent, 1079ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy tca, &err); 108010297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki else 1081e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller q = qdisc_create(dev, netdev_get_tx_queue(dev, 0), 1082bb949fbd1878973c3539d9aecff52f284482a937David S. Miller tcm->tcm_parent, tcm->tcm_handle, 1083ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy tca, &err); 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == NULL) { 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == -EAGAIN) 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto replay; 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgraft: 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (1) { 109299194cff398d056e5ee469647c294466c246c88aDavid S. Miller err = qdisc_graft(dev, p, skb, n, clid, q, NULL); 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 10944d8863a29c4755a0461cd31b6865026187d6c43aDavid S. Miller if (q) 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qdisc_destroy(q); 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, 1103e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim u32 pid, u32 seq, u16 flags, int event) 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm; 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nlmsghdr *nlh; 110727a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo unsigned char *b = skb_tail_pointer(skb); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gnet_dump d; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1110e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm = NLMSG_DATA(nlh); 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_family = AF_UNSPEC; 11139ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy tcm->tcm__pad1 = 0; 11149ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy tcm->tcm__pad2 = 0; 11155ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller tcm->tcm_ifindex = qdisc_dev(q)->ifindex; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_parent = clid; 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_handle = q->handle; 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_info = atomic_read(&q->refcnt); 111957e1c487a4f5754cb77abeb00adb21faa88c484fPatrick McHardy NLA_PUT_STRING(skb, TCA_KIND, q->ops->id); 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->ops->dump && q->ops->dump(q, skb) < 0) 11211e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->qstats.qlen = q->q.qlen; 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1124175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (q->stab && qdisc_dump_stab(skb, q->stab) < 0) 1125175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna goto nla_put_failure; 1126175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, 11287698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller TCA_XSTATS, qdisc_root_lock(q), &d) < 0) 11291e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0) 11321e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_copy_basic(&d, &q->bstats) < 0 || 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 || 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gnet_stats_copy_queue(&d, &q->qstats) < 0) 11371e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 113810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_finish_copy(&d) < 0) 11401e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 114110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 114227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo nlh->nlmsg_len = skb_tail_pointer(skb) - b; 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure: 11461e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure: 1147dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo nlmsg_trim(skb, b); 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clid, struct Qdisc *old, struct Qdisc *new) 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old && old->handle) { 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0) 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new) { 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0) 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb->len) 117197c53cacf00d1f5aa04adabfebcc806ca8b22b10Denis V. Lunev return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out: 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11783072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic bool tc_qdisc_dump_ignore(struct Qdisc *q) 11793072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 11803072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return (q->flags & TCQ_F_BUILTIN) ? true : false; 11813072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 11823072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 11833072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, 11843072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netlink_callback *cb, 11853072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int *q_idx_p, int s_q_idx) 11863072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 11873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int ret = 0, q_idx = *q_idx_p; 11883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct Qdisc *q; 11893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 11903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!root) 11913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 11923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 11933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q = root; 11943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (q_idx < s_q_idx) { 11953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 11963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } else { 11973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!tc_qdisc_dump_ignore(q) && 11983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, 11993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) 12003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 12013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 12023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 12033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller list_for_each_entry(q, &root->list, list) { 12043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (q_idx < s_q_idx) { 12053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 12063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller continue; 12073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 12083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!tc_qdisc_dump_ignore(q) && 12093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, 12103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) 12113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 12123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 12133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 12143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerout: 12163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller *q_idx_p = q_idx; 12173072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return ret; 12183072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone: 12193072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller ret = -1; 12203072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto out; 12213072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 12223072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12253b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx, q_idx; 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int s_idx, s_q_idx; 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1230b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev if (net != &init_net) 1231b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev return 0; 1232b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_idx = cb->args[0]; 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_q_idx = q_idx = cb->args[1]; 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock(&dev_base_lock); 12367562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov idx = 0; 1237881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman for_each_netdev(&init_net, dev) { 12383072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netdev_queue *dev_queue; 12393072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx < s_idx) 12417562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov goto cont; 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx > s_idx) 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_q_idx = 0; 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q_idx = 0; 12453072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12463072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller dev_queue = netdev_get_tx_queue(dev, 0); 1247827ebd6410005b05b3c930ef6a116666c6986886David S. Miller if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0) 12483072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 12493072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12503072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller dev_queue = &dev->rx_queue; 1251827ebd6410005b05b3c930ef6a116666c6986886David S. Miller if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0) 12523072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 12533072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12547562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianovcont: 12557562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov idx++; 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&dev_base_lock); 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb->args[0] = idx; 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb->args[1] = q_idx; 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************ 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Traffic classes manipulation. * 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/ 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12773b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 1278b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller struct netdev_queue *dev_queue; 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm = NLMSG_DATA(n); 12801e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *tca[TCA_MAX + 1]; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q = NULL; 128320fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops; 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl = 0; 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long new_cl; 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pid = tcm->tcm_parent; 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clid = tcm->tcm_handle; 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 qid = TC_H_MAJ(clid); 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev if (net != &init_net) 1292b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev return -EINVAL; 1293b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev 1294881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12971e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 12981e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (err < 0) 12991e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy return err; 13001e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == TC_H_UNSPEC - unspecified parent. 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == TC_H_ROOT - class is root, which has no parent. 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == X:0 - parent is root class. 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == X:Y - parent is a node in hierarchy. 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == 0:Y - parent is X:Y, where X:0 is qdisc. 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == 0:0 - generate handle from kernel pool. 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == 0:Y - class is X:Y, where X:0 is qdisc. 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == X:Y - clear. 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == X:0 - root class. 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Step 1. Determine qdisc handle X:0 */ 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1316e8a0464cc950972824e2e128028ae3db666ec1edDavid S. Miller dev_queue = netdev_get_tx_queue(dev, 0); 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pid != TC_H_ROOT) { 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 qid1 = TC_H_MAJ(pid); 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qid && qid1) { 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If both majors are known, they must be identical. */ 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qid != qid1) 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (qid1) { 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qid = qid1; 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (qid == 0) 1327b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller qid = dev_queue->qdisc_sleeping->handle; 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now qid is genuine qdisc handle consistent 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds both with parent and child. 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TC_H_MAJ(pid) still may be unspecified, complete it now. 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pid) 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pid = TC_H_MAKE(qid, pid); 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qid == 0) 1338b0e1e6462df3c5944010b3328a546d8fe5d932cdDavid S. Miller qid = dev_queue->qdisc_sleeping->handle; 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK. Locate qdisc */ 134210297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki if ((q = qdisc_lookup(dev, qid)) == NULL) 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* An check that it supports classes */ 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops = q->ops->cl_ops; 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cops == NULL) 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now try to get class */ 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid == 0) { 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pid == TC_H_ROOT) 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clid = qid; 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clid = TC_H_MAKE(qid, clid); 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid) 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cl = cops->get(q, clid); 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl == 0) { 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENOENT; 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n->nlmsg_type != RTM_NEWTCLASS || !(n->nlmsg_flags&NLM_F_CREATE)) 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (n->nlmsg_type) { 136610297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki case RTM_NEWTCLASS: 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EEXIST; 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n->nlmsg_flags&NLM_F_EXCL) 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case RTM_DELTCLASS: 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = cops->delete(q, cl); 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == 0) 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tclass_notify(skb, n, q, cl, RTM_DELTCLASS); 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case RTM_GETTCLASS: 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = tclass_notify(skb, n, q, cl, RTM_NEWTCLASS); 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_cl = cl; 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = cops->change(q, clid, pid, tca, &new_cl); 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == 0) 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS); 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl) 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops->put(q, cl); 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl, 1400e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim u32 pid, u32 seq, u16 flags, int event) 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm; 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nlmsghdr *nlh; 140427a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo unsigned char *b = skb_tail_pointer(skb); 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gnet_dump d; 140620fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1408e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm = NLMSG_DATA(nlh); 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_family = AF_UNSPEC; 14115ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller tcm->tcm_ifindex = qdisc_dev(q)->ifindex; 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_parent = q->handle; 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_handle = q->handle; 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_info = 0; 141557e1c487a4f5754cb77abeb00adb21faa88c484fPatrick McHardy NLA_PUT_STRING(skb, TCA_KIND, q->ops->id); 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0) 14171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, 14207698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller TCA_XSTATS, qdisc_root_lock(q), &d) < 0) 14211e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0) 14241e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_finish_copy(&d) < 0) 14271e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 142927a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo nlh->nlmsg_len = skb_tail_pointer(skb) - b; 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure: 14331e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure: 1434dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo nlmsg_trim(skb, b); 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q, unsigned long cl, int event) 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tc_fill_tclass(skb, q, cl, pid, n->nlmsg_seq, 0, event) < 0) { 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145397c53cacf00d1f5aa04adabfebcc806ca8b22b10Denis V. Lunev return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct qdisc_dump_args 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_walker w; 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netlink_callback *cb; 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg) 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_dump_args *a = (struct qdisc_dump_args *)arg; 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tc_fill_tclass(a->skb, q, cl, NETLINK_CB(a->cb->skb).pid, 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS); 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14713072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb, 14723072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct tcmsg *tcm, struct netlink_callback *cb, 14733072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int *t_p, int s_t) 14743072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 14753072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct qdisc_dump_args arg; 14763072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 14773072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (tc_qdisc_dump_ignore(q) || 14783072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller *t_p < s_t || !q->ops->cl_ops || 14793072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller (tcm->tcm_parent && 14803072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller TC_H_MAJ(tcm->tcm_parent) != q->handle)) { 14813072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller (*t_p)++; 14823072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 14833072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 14843072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (*t_p > s_t) 14853072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); 14863072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.fn = qdisc_class_dump; 14873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.skb = skb; 14883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.cb = cb; 14893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.stop = 0; 14903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.skip = cb->args[1]; 14913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.count = 0; 14923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q->ops->cl_ops->walk(q, &arg.w); 14933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller cb->args[1] = arg.w.count; 14943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (arg.w.stop) 14953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return -1; 14963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller (*t_p)++; 14973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 14983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 14993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb, 15013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct tcmsg *tcm, struct netlink_callback *cb, 15023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int *t_p, int s_t) 15033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 15043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct Qdisc *q; 15053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!root) 15073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 15083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0) 15103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return -1; 15113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller list_for_each_entry(q, &root->list, list) { 15133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0) 15143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return -1; 15153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 15163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15173072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 15183072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 15193072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15223072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh); 15233b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 15243072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netdev_queue *dev_queue; 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 15263072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int t, s_t; 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1528b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev if (net != &init_net) 1529b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev return 0; 1530b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1533881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_t = cb->args[0]; 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = 0; 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15393072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller dev_queue = netdev_get_tx_queue(dev, 0); 15408123b421e8ed944671d7241323ed3198cccb4041David S. Miller if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0) 15413072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 15423072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15433072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller dev_queue = &dev->rx_queue; 15448123b421e8ed944671d7241323ed3198cccb4041David S. Miller if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0) 15453072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15473072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone: 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb->args[0] = t; 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(dev); 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Main classifier routine: scans classifier chain attached 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to this qdisc, (optionally) tests for protocol and asks 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds specific classifiers. 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 155873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyint tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp, 155973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy struct tcf_result *res) 156073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy{ 156173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy __be16 protocol = skb->protocol; 156273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy int err = 0; 156373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy 156473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy for (; tp; tp = tp->next) { 156573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if ((tp->protocol == protocol || 156673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy tp->protocol == htons(ETH_P_ALL)) && 156773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy (err = tp->classify(skb, tp, res)) >= 0) { 156873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#ifdef CONFIG_NET_CLS_ACT 156973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if (err != TC_ACT_RECLASSIFY && skb->tc_verd) 157073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0); 157173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif 157273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return err; 157373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy } 157473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy } 157573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return -1; 157673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy} 157773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify_compat); 157873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tc_classify(struct sk_buff *skb, struct tcf_proto *tp, 158073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy struct tcf_result *res) 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 158373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy __be16 protocol; 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcf_proto *otp = tp; 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreclassify: 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds protocol = skb->protocol; 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 159073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy err = tc_classify_compat(skb, tp, res); 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT 159273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if (err == TC_ACT_RECLASSIFY) { 159373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy u32 verd = G_TC_VERD(skb->tc_verd); 159473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy tp = otp; 159573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy 159673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if (verd++ >= MAX_REC_LOOP) { 159773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy printk("rule prio %u protocol %02x reclassify loop, " 159873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy "packet dropped\n", 159973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy tp->prio&0xffff, ntohs(tp->protocol)); 160073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return TC_ACT_SHOT; 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 160273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd); 160373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy goto reclassify; 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 160573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif 160673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return err; 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 160873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify); 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1610a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyvoid tcf_destroy(struct tcf_proto *tp) 1611a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{ 1612a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy tp->ops->destroy(tp); 1613a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy module_put(tp->ops->owner); 1614a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy kfree(tp); 1615a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy} 1616a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy 1617ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardyvoid tcf_destroy_chain(struct tcf_proto **fl) 1618a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{ 1619a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy struct tcf_proto *tp; 1620a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy 1621ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy while ((tp = *fl) != NULL) { 1622ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy *fl = tp->next; 1623a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy tcf_destroy(tp); 1624a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy } 1625a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy} 1626a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyEXPORT_SYMBOL(tcf_destroy_chain); 1627a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_show(struct seq_file *seq, void *v) 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16313c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy struct timespec ts; 16323c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy 16333c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy hrtimer_get_res(CLOCK_MONOTONIC, &ts); 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(seq, "%08x %08x %08x %08x\n", 1635641b9e0e8b7f96425da6ce98f3361e3af0baee29Patrick McHardy (u32)NSEC_PER_USEC, (u32)PSCHED_US2NS(1), 1636514bca322cb9220308d22691ac1e74038bfabac3Patrick McHardy 1000000, 16373c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts))); 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_open(struct inode *inode, struct file *file) 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return single_open(file, psched_show, PDE(inode)->data); 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1647da7071d7e32d15149cc513f096a3638097b66387Arjan van de Venstatic const struct file_operations psched_fops = { 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = psched_open, 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = seq_read, 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .llseek = seq_lseek, 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = single_release, 165310297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki}; 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pktsched_init(void) 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_qdisc(&pfifo_qdisc_ops); 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_qdisc(&bfifo_qdisc_ops); 1660457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman proc_net_fops_create(&init_net, "psched", 0, &psched_fops); 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1662be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL); 1663be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL); 1664be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc); 1665be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL); 1666be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL); 1667be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass); 1668be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(pktsched_init); 1673