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