sch_api.c revision 1b34ec43c9b3de44a5420841ab293d1b2035a94c
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> 315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h> 34b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev#include <net/sock.h> 35dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo#include <net/netlink.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 387316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int qdisc_notify(struct net *net, struct sk_buff *oskb, 397316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct nlmsghdr *n, u32 clid, 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *old, struct Qdisc *new); 417316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int tclass_notify(struct net *net, struct sk_buff *oskb, 427316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct nlmsghdr *n, struct Qdisc *q, 437316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff unsigned long cl, int event); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Short review. 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ------------- 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This file consists of two interrelated parts: 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1. queueing disciplines manager frontend. 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2. traffic classes manager frontend. 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Generally, queueing discipline ("qdisc") is a black box, 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds which is able to enqueue packets and to dequeue them (when 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device is ready to send something) in order and at times 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds determined by algorithm hidden in it. 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qdisc's are divided to two categories: 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - "queues", which have no internal structure visible from outside. 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - "schedulers", which split all the packets to "traffic classes", 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds using "packet classifiers" (look at cls_api.c) 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds In turn, classes may have child qdiscs (as rule, queues) 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds attached to them etc. etc. etc. 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The goal of the routines in this file is to translate 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds information supplied by user in the form of handles 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to more intelligible for kernel form, to make some sanity 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checks and part of work, which is common to all qdiscs 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and to provide rtnetlink notifications. 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds All real intelligent work is done inside qdisc modules. 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Every discipline has two major routines: enqueue and dequeue. 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---dequeue 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dequeue usually returns a skb to send. It is allowed to return NULL, 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but it does not mean that queue is empty, it just means that 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds discipline does not want to send anything this time. 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Queue is really empty if q->q.qlen == 0. 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds For complicated disciplines with multiple queues q->q is not 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds real packet queue, but however q->q.qlen must be valid. 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---enqueue 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enqueue returns 0, if packet was enqueued successfully. 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds If packet (this one or another one) was dropped, it returns 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds not zero error code. 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NET_XMIT_DROP - this packet dropped 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Expected action: do not backoff, but wait until queue will clear. 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NET_XMIT_CN - probably this packet enqueued, but another one dropped. 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Expected action: backoff or ignore 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NET_XMIT_POLICED - dropped by police. 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Expected action: backoff or error to real-time apps. 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Auxiliary routines: 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10399c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski ---peek 10499c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski 10599c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski like dequeue but without removing a packet from the queue 10699c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---reset 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds returns qdisc to initial state: purge all buffers, clear all 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timers, counters (except for statistics) etc. 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---init 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initializes newly created qdisc. 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---destroy 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds destroys resources allocated by init and during lifetime of qdisc. 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---change 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds changes qdisc parameters. 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protects list of registered TC modules. It is pure SMP lock. */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_RWLOCK(qdisc_mod_lock); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Queueing disciplines manipulation. * 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/ 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The list of all installed queueing disciplines. */ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_ops *qdisc_base; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register/uregister queueing discipline */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint register_qdisc(struct Qdisc_ops *qops) 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc_ops *q, **qp; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EEXIST; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_lock(&qdisc_mod_lock); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!strcmp(qops->id, q->id)) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qops->enqueue == NULL) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qops->enqueue = noop_qdisc_ops.enqueue; 15299c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski if (qops->peek == NULL) { 15368fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski if (qops->dequeue == NULL) 15499c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski qops->peek = noop_qdisc_ops.peek; 15568fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski else 15668fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski goto out_einval; 15799c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski } 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qops->dequeue == NULL) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qops->dequeue = noop_qdisc_ops.dequeue; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16168fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski if (qops->cl_ops) { 16268fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski const struct Qdisc_class_ops *cops = qops->cl_ops; 16368fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski 1643e9e5a5921f4b7dc098a01d01e5972bebb36491eJarek Poplawski if (!(cops->get && cops->put && cops->walk && cops->leaf)) 16568fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski goto out_einval; 16668fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski 16768fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf)) 16868fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski goto out_einval; 16968fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski } 17068fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qops->next = NULL; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *qp = qops; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_unlock(&qdisc_mod_lock); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 17768fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski 17868fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawskiout_einval: 17968fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski rc = -EINVAL; 18068fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski goto out; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18262e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(register_qdisc); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint unregister_qdisc(struct Qdisc_ops *qops) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc_ops *q, **qp; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -ENOENT; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_lock(&qdisc_mod_lock); 190cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next) 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == qops) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q) { 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *qp = q->next; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->next = NULL; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = 0; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_unlock(&qdisc_mod_lock); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20162e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(unregister_qdisc); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We know handle. Find qdisc among all qdisc's attached to device 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (root qdisc, all its children, children of children etc.) 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2076113b748fb9935399ec2bbca3a3dc82008f6167fHannes Ederstatic struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) 2088123b421e8ed944671d7241323ed3198cccb4041David S. Miller{ 2098123b421e8ed944671d7241323ed3198cccb4041David S. Miller struct Qdisc *q; 2108123b421e8ed944671d7241323ed3198cccb4041David S. Miller 2118123b421e8ed944671d7241323ed3198cccb4041David S. Miller if (!(root->flags & TCQ_F_BUILTIN) && 2128123b421e8ed944671d7241323ed3198cccb4041David S. Miller root->handle == handle) 2138123b421e8ed944671d7241323ed3198cccb4041David S. Miller return root; 2148123b421e8ed944671d7241323ed3198cccb4041David S. Miller 2158123b421e8ed944671d7241323ed3198cccb4041David S. Miller list_for_each_entry(q, &root->list, list) { 2168123b421e8ed944671d7241323ed3198cccb4041David S. Miller if (q->handle == handle) 2178123b421e8ed944671d7241323ed3198cccb4041David S. Miller return q; 2188123b421e8ed944671d7241323ed3198cccb4041David S. Miller } 2198123b421e8ed944671d7241323ed3198cccb4041David S. Miller return NULL; 2208123b421e8ed944671d7241323ed3198cccb4041David S. Miller} 2218123b421e8ed944671d7241323ed3198cccb4041David S. Miller 222f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawskistatic void qdisc_list_add(struct Qdisc *q) 223f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski{ 224f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawski if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) 225af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy list_add_tail(&q->list, &qdisc_dev(q)->qdisc->list); 226f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski} 227f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski 228f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawskivoid qdisc_list_del(struct Qdisc *q) 229f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski{ 230f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawski if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) 231f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski list_del(&q->list); 232f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski} 233f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek PoplawskiEXPORT_SYMBOL(qdisc_list_del); 234f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski 235ead81cc5fc6d996db6afb20f211241612610a07aDavid S. Millerstruct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 237f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski struct Qdisc *q; 238f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski 239af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy q = qdisc_match_from_root(dev->qdisc, handle); 240af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy if (q) 241af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy goto out; 242f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski 24324824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (dev_ingress_queue(dev)) 24424824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet q = qdisc_match_from_root( 24524824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet dev_ingress_queue(dev)->qdisc_sleeping, 24624824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet handle); 247f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawskiout: 248f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski return q; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid) 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *leaf; 25520fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops = p->ops->cl_ops; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cops == NULL) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cl = cops->get(p, classid); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl == 0) 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds leaf = cops->leaf(p, cl); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops->put(p, cl); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return leaf; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find queueing discipline by name */ 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic struct Qdisc_ops *qdisc_lookup_ops(struct nlattr *kind) 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc_ops *q = NULL; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind) { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock(&qdisc_mod_lock); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (q = qdisc_base; q; q = q->next) { 2771e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (nla_strcmp(kind, q->id) == 0) { 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!try_module_get(q->owner)) 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = NULL; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&qdisc_mod_lock); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return q; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct qdisc_rate_table *qdisc_rtab_list; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystruct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab) 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_rate_table *rtab; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) { 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) == 0) { 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->refcnt++; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rtab; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3015feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy if (tab == NULL || r->rate == 0 || r->cell_log == 0 || 3025feb5e1aaa887f6427b8290bce48bfb6b7010fc6Patrick McHardy nla_len(tab) != TC_RTAB_SIZE) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab = kmalloc(sizeof(*rtab), GFP_KERNEL); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rtab) { 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->rate = *r; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->refcnt = 1; 3091e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy memcpy(rtab->data, nla_data(tab), 1024); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->next = qdisc_rtab_list; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qdisc_rtab_list = rtab; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rtab; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 31562e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_get_rtab); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qdisc_put_rtab(struct qdisc_rate_table *tab) 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_rate_table *rtab, **rtabp; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tab || --tab->refcnt) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 324cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet for (rtabp = &qdisc_rtab_list; 325cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet (rtab = *rtabp) != NULL; 326cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet rtabp = &rtab->next) { 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rtab == tab) { 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *rtabp = rtab->next; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(rtab); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33462e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_put_rtab); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 336175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic LIST_HEAD(qdisc_stab_list); 337175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic DEFINE_SPINLOCK(qdisc_stab_lock); 338175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 339175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = { 340175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna [TCA_STAB_BASE] = { .len = sizeof(struct tc_sizespec) }, 341175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna [TCA_STAB_DATA] = { .type = NLA_BINARY }, 342175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}; 343175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 344175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) 345175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 346175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct nlattr *tb[TCA_STAB_MAX + 1]; 347175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct qdisc_size_table *stab; 348175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct tc_sizespec *s; 349175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna unsigned int tsize = 0; 350175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna u16 *tab = NULL; 351175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna int err; 352175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 353175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy); 354175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (err < 0) 355175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(err); 356175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!tb[TCA_STAB_BASE]) 357175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-EINVAL); 358175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 359175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna s = nla_data(tb[TCA_STAB_BASE]); 360175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 361175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (s->tsize > 0) { 362175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!tb[TCA_STAB_DATA]) 363175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-EINVAL); 364175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna tab = nla_data(tb[TCA_STAB_DATA]); 365175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); 366175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 367175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 36800093fab980d0a8950a64bdf9e346d0497b9a7e4Dan Carpenter if (tsize != s->tsize || (!tab && tsize > 0)) 369175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-EINVAL); 370175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 371f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_lock(&qdisc_stab_lock); 372175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 373175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna list_for_each_entry(stab, &qdisc_stab_list, list) { 374175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (memcmp(&stab->szopts, s, sizeof(*s))) 375175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna continue; 376175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16))) 377175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna continue; 378175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->refcnt++; 379f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_unlock(&qdisc_stab_lock); 380175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return stab; 381175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 382175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 383f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_unlock(&qdisc_stab_lock); 384175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 385175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL); 386175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!stab) 387175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-ENOMEM); 388175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 389175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->refcnt = 1; 390175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->szopts = *s; 391175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tsize > 0) 392175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna memcpy(stab->data, tab, tsize * sizeof(u16)); 393175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 394f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_lock(&qdisc_stab_lock); 395175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna list_add_tail(&stab->list, &qdisc_stab_list); 396f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_unlock(&qdisc_stab_lock); 397175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 398175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return stab; 399175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 400175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 401a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazetstatic void stab_kfree_rcu(struct rcu_head *head) 402a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet{ 403a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet kfree(container_of(head, struct qdisc_size_table, rcu)); 404a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet} 405a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet 406175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_put_stab(struct qdisc_size_table *tab) 407175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 408175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!tab) 409175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return; 410175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 411f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_lock(&qdisc_stab_lock); 412175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 413175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (--tab->refcnt == 0) { 414175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna list_del(&tab->list); 415a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet call_rcu_bh(&tab->rcu, stab_kfree_rcu); 416175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 417175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 418f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_unlock(&qdisc_stab_lock); 419175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 420175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_put_stab); 421175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 422175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab) 423175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 424175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct nlattr *nest; 425175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 426175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna nest = nla_nest_start(skb, TCA_STAB); 4273aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy if (nest == NULL) 4283aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy goto nla_put_failure; 4291b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts)) 4301b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 431175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna nla_nest_end(skb, nest); 432175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 433175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return skb->len; 434175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 435175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnanla_put_failure: 436175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return -1; 437175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 438175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 439a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazetvoid __qdisc_calculate_pkt_len(struct sk_buff *skb, const struct qdisc_size_table *stab) 440175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 441175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna int pkt_len, slot; 442175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 443175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = skb->len + stab->szopts.overhead; 444175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (unlikely(!stab->szopts.tsize)) 445175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna goto out; 446175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 447175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna slot = pkt_len + stab->szopts.cell_align; 448175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (unlikely(slot < 0)) 449175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna slot = 0; 450175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 451175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna slot >>= stab->szopts.cell_log; 452175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (likely(slot < stab->szopts.tsize)) 453175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = stab->data[slot]; 454175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna else 455175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = stab->data[stab->szopts.tsize - 1] * 456175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna (slot / stab->szopts.tsize) + 457175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->data[slot % stab->szopts.tsize]; 458175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 459175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len <<= stab->szopts.size_log; 460175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnaout: 461175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (unlikely(pkt_len < 1)) 462175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = 1; 463175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna qdisc_skb_cb(skb)->pkt_len = pkt_len; 464175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 465a2da570d62fcb9e8816f6920e1ec02c706b289faEric DumazetEXPORT_SYMBOL(__qdisc_calculate_pkt_len); 466175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 467b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawskivoid qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc) 468b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski{ 469b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski if (!(qdisc->flags & TCQ_F_WARN_NONWC)) { 470cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet pr_warn("%s: %s qdisc %X: is non-work-conserving?\n", 471cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet txt, qdisc->ops->id, qdisc->handle >> 16); 472b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski qdisc->flags |= TCQ_F_WARN_NONWC; 473b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski } 474b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski} 475b00355db3f88d96810a60011a30cfb2c3469409dJarek PoplawskiEXPORT_SYMBOL(qdisc_warn_nonwc); 476b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski 4774179477f637caa730626bd597fdf28c5bad73565Patrick McHardystatic enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) 4784179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4794179477f637caa730626bd597fdf28c5bad73565Patrick McHardy struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, 4802fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller timer); 4814179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 482fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet qdisc_unthrottled(wd->qdisc); 4838608db031b4d2932d645709e2cfe8fbcd91a7305David S. Miller __netif_schedule(qdisc_root(wd->qdisc)); 4841936502d00ae6c2aa3931c42f6cf54afaba094f2Stephen Hemminger 4854179477f637caa730626bd597fdf28c5bad73565Patrick McHardy return HRTIMER_NORESTART; 4864179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 4874179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 4884179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc) 4894179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4902fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 4912fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller wd->timer.function = qdisc_watchdog; 4924179477f637caa730626bd597fdf28c5bad73565Patrick McHardy wd->qdisc = qdisc; 4934179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 4944179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_init); 4954179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 4964179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires) 4974179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4984179477f637caa730626bd597fdf28c5bad73565Patrick McHardy ktime_t time; 4994179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 5002540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski if (test_bit(__QDISC_STATE_DEACTIVATED, 5012540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski &qdisc_root_sleeping(wd->qdisc)->state)) 5022540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski return; 5032540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski 504fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet qdisc_throttled(wd->qdisc); 5054179477f637caa730626bd597fdf28c5bad73565Patrick McHardy time = ktime_set(0, 0); 506ca44d6e60f9de26281fda203f58b570e1748c015Jarek Poplawski time = ktime_add_ns(time, PSCHED_TICKS2NS(expires)); 5072fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS); 5084179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 5094179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_schedule); 5104179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 5114179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_cancel(struct qdisc_watchdog *wd) 5124179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 5132fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller hrtimer_cancel(&wd->timer); 514fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet qdisc_unthrottled(wd->qdisc); 5154179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 5164179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_cancel); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 518a94f779f9d82eb2d758a8715eaae5df98e8dcb21Adrian Bunkstatic struct hlist_head *qdisc_class_hash_alloc(unsigned int n) 5196fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 5206fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int size = n * sizeof(struct hlist_head), i; 5216fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct hlist_head *h; 5226fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5236fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (size <= PAGE_SIZE) 5246fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy h = kmalloc(size, GFP_KERNEL); 5256fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy else 5266fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy h = (struct hlist_head *) 5276fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy __get_free_pages(GFP_KERNEL, get_order(size)); 5286fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5296fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (h != NULL) { 5306fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy for (i = 0; i < n; i++) 5316fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy INIT_HLIST_HEAD(&h[i]); 5326fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy } 5336fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return h; 5346fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 5356fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5366fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardystatic void qdisc_class_hash_free(struct hlist_head *h, unsigned int n) 5376fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 5386fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int size = n * sizeof(struct hlist_head); 5396fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5406fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (size <= PAGE_SIZE) 5416fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy kfree(h); 5426fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy else 5436fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy free_pages((unsigned long)h, get_order(size)); 5446fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 5456fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5466fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_grow(struct Qdisc *sch, struct Qdisc_class_hash *clhash) 5476fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 5486fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct Qdisc_class_common *cl; 5496fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct hlist_node *n, *next; 5506fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct hlist_head *nhash, *ohash; 5516fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int nsize, nmask, osize; 5526fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int i, h; 5536fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5546fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy /* Rehash when load factor exceeds 0.75 */ 5556fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (clhash->hashelems * 4 <= clhash->hashsize * 3) 5566fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return; 5576fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy nsize = clhash->hashsize * 2; 5586fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy nmask = nsize - 1; 5596fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy nhash = qdisc_class_hash_alloc(nsize); 5606fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (nhash == NULL) 5616fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return; 5626fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5636fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy ohash = clhash->hash; 5646fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy osize = clhash->hashsize; 5656fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5666fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy sch_tree_lock(sch); 5676fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy for (i = 0; i < osize; i++) { 5686fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy hlist_for_each_entry_safe(cl, n, next, &ohash[i], hnode) { 5696fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy h = qdisc_class_hash(cl->classid, nmask); 5706fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy hlist_add_head(&cl->hnode, &nhash[h]); 5716fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy } 5726fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy } 5736fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hash = nhash; 5746fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashsize = nsize; 5756fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashmask = nmask; 5766fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy sch_tree_unlock(sch); 5776fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5786fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy qdisc_class_hash_free(ohash, osize); 5796fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 5806fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_grow); 5816fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5826fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyint qdisc_class_hash_init(struct Qdisc_class_hash *clhash) 5836fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 5846fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int size = 4; 5856fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5866fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hash = qdisc_class_hash_alloc(size); 5876fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy if (clhash->hash == NULL) 5886fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return -ENOMEM; 5896fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashsize = size; 5906fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashmask = size - 1; 5916fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashelems = 0; 5926fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy return 0; 5936fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 5946fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_init); 5956fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 5966fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_destroy(struct Qdisc_class_hash *clhash) 5976fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 5986fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy qdisc_class_hash_free(clhash->hash, clhash->hashsize); 5996fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 6006fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_destroy); 6016fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 6026fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_insert(struct Qdisc_class_hash *clhash, 6036fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct Qdisc_class_common *cl) 6046fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 6056fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy unsigned int h; 6066fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 6076fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy INIT_HLIST_NODE(&cl->hnode); 6086fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy h = qdisc_class_hash(cl->classid, clhash->hashmask); 6096fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy hlist_add_head(&cl->hnode, &clhash->hash[h]); 6106fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashelems++; 6116fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 6126fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_insert); 6136fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 6146fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_remove(struct Qdisc_class_hash *clhash, 6156fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy struct Qdisc_class_common *cl) 6166fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{ 6176fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy hlist_del(&cl->hnode); 6186fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy clhash->hashelems--; 6196fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy} 6206fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_remove); 6216fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy 622fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet/* Allocate an unique handle from space managed by kernel 623fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet * Possible range is [8000-FFFF]:0000 (0x8000 values) 624fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet */ 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 qdisc_alloc_handle(struct net_device *dev) 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 627fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet int i = 0x8000; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static u32 autohandle = TC_H_MAKE(0x80000000U, 0); 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds autohandle += TC_H_MAKE(0x10000U, 0); 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (autohandle == TC_H_MAKE(TC_H_ROOT, 0)) 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds autohandle = TC_H_MAKE(0x80000000U, 0); 634fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet if (!qdisc_lookup(dev, autohandle)) 635fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet return autohandle; 636fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet cond_resched(); 637fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet } while (--i > 0); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 639fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet return 0; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyvoid qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) 64343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy{ 64420fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops; 64543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy unsigned long cl; 64643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy u32 parentid; 64743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy 64843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy if (n == 0) 64943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy return; 65043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy while ((parentid = sch->parent)) { 651066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS)) 652066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski return; 653066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski 6545ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid)); 655ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy if (sch == NULL) { 656ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy WARN_ON(parentid != TC_H_ROOT); 657ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy return; 658ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy } 65943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy cops = sch->ops->cl_ops; 66043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy if (cops->qlen_notify) { 66143effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy cl = cops->get(sch, parentid); 66243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy cops->qlen_notify(sch, cl); 66343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy cops->put(sch, cl); 66443effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy } 66543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy sch->q.qlen -= n; 66643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy } 66743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy} 66843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyEXPORT_SYMBOL(qdisc_tree_decrease_qlen); 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6707316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void notify_and_destroy(struct net *net, struct sk_buff *skb, 6717316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct nlmsghdr *n, u32 clid, 67299194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct Qdisc *old, struct Qdisc *new) 67399194cff398d056e5ee469647c294466c246c88aDavid S. Miller{ 67499194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (new || old) 6757316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff qdisc_notify(net, skb, n, clid, old, new); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6774d8863a29c4755a0461cd31b6865026187d6c43aDavid S. Miller if (old) 67899194cff398d056e5ee469647c294466c246c88aDavid S. Miller qdisc_destroy(old); 67999194cff398d056e5ee469647c294466c246c88aDavid S. Miller} 68099194cff398d056e5ee469647c294466c246c88aDavid S. Miller 68199194cff398d056e5ee469647c294466c246c88aDavid S. Miller/* Graft qdisc "new" to class "classid" of qdisc "parent" or 68299194cff398d056e5ee469647c294466c246c88aDavid S. Miller * to device "dev". 68399194cff398d056e5ee469647c294466c246c88aDavid S. Miller * 68499194cff398d056e5ee469647c294466c246c88aDavid S. Miller * When appropriate send a netlink notification using 'skb' 68599194cff398d056e5ee469647c294466c246c88aDavid S. Miller * and "n". 68699194cff398d056e5ee469647c294466c246c88aDavid S. Miller * 68799194cff398d056e5ee469647c294466c246c88aDavid S. Miller * On success, destroy old qdisc. 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_graft(struct net_device *dev, struct Qdisc *parent, 69199194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct sk_buff *skb, struct nlmsghdr *n, u32 classid, 69299194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct Qdisc *new, struct Qdisc *old) 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 69499194cff398d056e5ee469647c294466c246c88aDavid S. Miller struct Qdisc *q = old; 6957316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct net *net = dev_net(dev); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki if (parent == NULL) { 69999194cff398d056e5ee469647c294466c246c88aDavid S. Miller unsigned int i, num_q, ingress; 70099194cff398d056e5ee469647c294466c246c88aDavid S. Miller 70199194cff398d056e5ee469647c294466c246c88aDavid S. Miller ingress = 0; 70299194cff398d056e5ee469647c294466c246c88aDavid S. Miller num_q = dev->num_tx_queues; 7038d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller if ((q && q->flags & TCQ_F_INGRESS) || 7048d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller (new && new->flags & TCQ_F_INGRESS)) { 70599194cff398d056e5ee469647c294466c246c88aDavid S. Miller num_q = 1; 70699194cff398d056e5ee469647c294466c246c88aDavid S. Miller ingress = 1; 70724824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (!dev_ingress_queue(dev)) 70824824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet return -ENOENT; 70999194cff398d056e5ee469647c294466c246c88aDavid S. Miller } 71099194cff398d056e5ee469647c294466c246c88aDavid S. Miller 71199194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (dev->flags & IFF_UP) 71299194cff398d056e5ee469647c294466c246c88aDavid S. Miller dev_deactivate(dev); 71399194cff398d056e5ee469647c294466c246c88aDavid S. Miller 7146ec1c69a8f6492fd25722f4762721921da074c12David S. Miller if (new && new->ops->attach) { 7156ec1c69a8f6492fd25722f4762721921da074c12David S. Miller new->ops->attach(new); 7166ec1c69a8f6492fd25722f4762721921da074c12David S. Miller num_q = 0; 7176ec1c69a8f6492fd25722f4762721921da074c12David S. Miller } 7186ec1c69a8f6492fd25722f4762721921da074c12David S. Miller 71999194cff398d056e5ee469647c294466c246c88aDavid S. Miller for (i = 0; i < num_q; i++) { 72024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet struct netdev_queue *dev_queue = dev_ingress_queue(dev); 72199194cff398d056e5ee469647c294466c246c88aDavid S. Miller 72299194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (!ingress) 72399194cff398d056e5ee469647c294466c246c88aDavid S. Miller dev_queue = netdev_get_tx_queue(dev, i); 72499194cff398d056e5ee469647c294466c246c88aDavid S. Miller 7258d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller old = dev_graft_qdisc(dev_queue, new); 7268d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller if (new && i > 0) 7278d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller atomic_inc(&new->refcnt); 7288d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller 729036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski if (!ingress) 730036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski qdisc_destroy(old); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 73299194cff398d056e5ee469647c294466c246c88aDavid S. Miller 733036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski if (!ingress) { 7347316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff notify_and_destroy(net, skb, n, classid, 7357316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff dev->qdisc, new); 736036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski if (new && !new->ops->attach) 737036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski atomic_inc(&new->refcnt); 738036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski dev->qdisc = new ? : &noop_qdisc; 739036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski } else { 7407316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff notify_and_destroy(net, skb, n, classid, old, new); 741036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski } 742af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy 74399194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (dev->flags & IFF_UP) 74499194cff398d056e5ee469647c294466c246c88aDavid S. Miller dev_activate(dev); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 74620fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops = parent->ops->cl_ops; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 748c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy err = -EOPNOTSUPP; 749c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy if (cops && cops->graft) { 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl = cops->get(parent, classid); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl) { 75299194cff398d056e5ee469647c294466c246c88aDavid S. Miller err = cops->graft(parent, cl, new, &old); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops->put(parent, cl); 754c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy } else 755c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy err = -ENOENT; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 75799194cff398d056e5ee469647c294466c246c88aDavid S. Miller if (!err) 7587316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff notify_and_destroy(net, skb, n, classid, old, new); 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76325bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski/* lockdep annotation is needed for ingress; egress gets it only for name */ 76425bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_tx_lock; 76525bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_rx_lock; 76625bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Allocate and initialize new qdisc. 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Parameters are passed via opt. 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc * 774bb949fbd1878973c3539d9aecff52f284482a937David S. Millerqdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, 77523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy struct Qdisc *p, u32 parent, u32 handle, 77623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy struct nlattr **tca, int *errp) 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 7791e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *kind = tca[TCA_KIND]; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *sch; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc_ops *ops; 782175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct qdisc_size_table *stab; 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ops = qdisc_lookup_ops(kind); 78595a5afca4a8d2e1cb77e1d4bc6ff9f718dc32f7aJohannes Berg#ifdef CONFIG_MODULES 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ops == NULL && kind != NULL) { 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char name[IFNAMSIZ]; 7881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We dropped the RTNL semaphore in order to 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * perform the module load. So, even if we 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * succeeded in loading the module we have to 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tell the caller to replay the request. We 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * indicate this using -EAGAIN. 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We replay the request because the device may 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * go away in the mean time. 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtnl_unlock(); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_module("sch_%s", name); 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtnl_lock(); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ops = qdisc_lookup_ops(kind); 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ops != NULL) { 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We will try again qdisc_lookup_ops, 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so don't keep a reference. 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds module_put(ops->owner); 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EAGAIN; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 813b9e2cc0f0e47ad351349156018ef8a365e9c6d25Jamal Hadi Salim err = -ENOENT; 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ops == NULL) 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8175ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller sch = qdisc_alloc(dev_queue, ops); 8183d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf if (IS_ERR(sch)) { 8193d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf err = PTR_ERR(sch); 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out2; 8213d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf } 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 823ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy sch->parent = parent; 824ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy 8253d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf if (handle == TC_H_INGRESS) { 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sch->flags |= TCQ_F_INGRESS; 8273d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf handle = TC_H_MAKE(TC_H_INGRESS, 0); 82825bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock); 829fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy } else { 830fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy if (handle == 0) { 831fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy handle = qdisc_alloc_handle(dev); 832fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy err = -ENOMEM; 833fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy if (handle == 0) 834fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy goto err_out3; 835fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy } 83625bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock); 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8393d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf sch->handle = handle; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8411e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) { 842175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tca[TCA_STAB]) { 843175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab = qdisc_get_stab(tca[TCA_STAB]); 844175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (IS_ERR(stab)) { 845175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna err = PTR_ERR(stab); 8467c64b9f3f584008000cf3b960f25cd6a68fce191Jarek Poplawski goto err_out4; 847175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 848a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet rcu_assign_pointer(sch->stab, stab); 849175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 8501e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_RATE]) { 851f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski spinlock_t *root_lock; 852f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski 85323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy err = -EOPNOTSUPP; 85423bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (sch->flags & TCQ_F_MQROOT) 85523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy goto err_out4; 85623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy 857f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski if ((sch->parent != TC_H_ROOT) && 85823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy !(sch->flags & TCQ_F_INGRESS) && 85923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy (!p || !(p->flags & TCQ_F_MQROOT))) 860f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski root_lock = qdisc_root_sleeping_lock(sch); 861f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski else 862f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski root_lock = qdisc_lock(sch); 863f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski 864023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf err = gen_new_estimator(&sch->bstats, &sch->rate_est, 865f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski root_lock, tca[TCA_RATE]); 86623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (err) 86723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy goto err_out4; 868023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf } 869f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski 870f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski qdisc_list_add(sch); 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sch; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out3: 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(dev); 8763d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf kfree((char *) sch - sch->padded); 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out2: 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds module_put(ops->owner); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out: 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *errp = err; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 88223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy 88323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyerr_out4: 88423bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy /* 88523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy * Any broken qdiscs that would require a ops->reset() here? 88623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy * The qdisc was never in action so it shouldn't be necessary. 88723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy */ 888a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet qdisc_put_stab(rtnl_dereference(sch->stab)); 88923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (ops->destroy) 89023bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy ops->destroy(sch); 89123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy goto err_out3; 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int qdisc_change(struct Qdisc *sch, struct nlattr **tca) 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 896a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet struct qdisc_size_table *ostab, *stab = NULL; 897175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna int err = 0; 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 899175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tca[TCA_OPTIONS]) { 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sch->ops->change == NULL) 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9021e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = sch->ops->change(sch, tca[TCA_OPTIONS]); 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 906175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 907175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tca[TCA_STAB]) { 908175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab = qdisc_get_stab(tca[TCA_STAB]); 909175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (IS_ERR(stab)) 910175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return PTR_ERR(stab); 911175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 912175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 913a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet ostab = rtnl_dereference(sch->stab); 914a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet rcu_assign_pointer(sch->stab, stab); 915a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet qdisc_put_stab(ostab); 916175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 91723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (tca[TCA_RATE]) { 91871bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger /* NB: ignores errors from replace_estimator 91971bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger because change can't be undone. */ 92023bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (sch->flags & TCQ_F_MQROOT) 92123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy goto out; 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gen_replace_estimator(&sch->bstats, &sch->rate_est, 92371bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger qdisc_root_sleeping_lock(sch), 92471bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger tca[TCA_RATE]); 92523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy } 92623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyout: 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 930cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstruct check_loop_arg { 931cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet struct qdisc_walker w; 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *p; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int depth; 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w); 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop(struct Qdisc *q, struct Qdisc *p, int depth) 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct check_loop_arg arg; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->ops->cl_ops == NULL) 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.w.stop = arg.w.skip = arg.w.count = 0; 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.w.fn = check_loop_fn; 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.depth = depth; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.p = p; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->ops->cl_ops->walk(q, &arg.w); 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return arg.w.stop ? -ELOOP : 0; 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w) 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *leaf; 95720fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops = q->ops->cl_ops; 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct check_loop_arg *arg = (struct check_loop_arg *)w; 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds leaf = cops->leaf(q, cl); 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (leaf) { 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (leaf == arg->p || arg->depth > 7) 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ELOOP; 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return check_loop(leaf, arg->p, arg->depth + 1); 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete/get qdisc. 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9753b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm = NLMSG_DATA(n); 9771e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *tca[TCA_MAX + 1]; 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clid = tcm->tcm_parent; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q = NULL; 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *p = NULL; 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 984cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet dev = __dev_get_by_index(net, tcm->tcm_ifindex); 985cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!dev) 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 9891e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (err < 0) 9901e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy return err; 9911e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid) { 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid != TC_H_ROOT) { 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) { 995cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet p = qdisc_lookup(dev, TC_H_MAJ(clid)); 996cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!p) 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = qdisc_leaf(p, clid); 999cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet } else if (dev_ingress_queue(dev)) { 1000cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = dev_ingress_queue(dev)->qdisc_sleeping; 100110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki } 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1003af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy q = dev->qdisc; 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!q) 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tcm->tcm_handle && q->handle != tcm->tcm_handle) 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1011cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = qdisc_lookup(dev, tcm->tcm_handle); 1012cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!q) 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10161e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n->nlmsg_type == RTM_DELQDISC) { 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!clid) 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->handle == 0) 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 1024cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet err = qdisc_graft(dev, p, skb, n, clid, NULL, q); 1025cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (err != 0) 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10287316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff qdisc_notify(net, skb, n, clid, NULL, q); 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1034cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * Create/change qdisc. 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10393b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm; 10411e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *tca[TCA_MAX + 1]; 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clid; 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q, *p; 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreplay: 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reinit, just in case something touches this. */ 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm = NLMSG_DATA(n); 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clid = tcm->tcm_parent; 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = p = NULL; 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1053cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet dev = __dev_get_by_index(net, tcm->tcm_ifindex); 1054cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!dev) 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10571e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 10581e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (err < 0) 10591e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy return err; 10601e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid) { 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid != TC_H_ROOT) { 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid != TC_H_INGRESS) { 1064cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet p = qdisc_lookup(dev, TC_H_MAJ(clid)); 1065cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!p) 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = qdisc_leaf(p, clid); 1068cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet } else if (dev_ingress_queue_create(dev)) { 1069cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = dev_ingress_queue(dev)->qdisc_sleeping; 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1072af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy q = dev->qdisc; 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* It may be default qdisc, ignore it */ 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q && q->handle == 0) 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = NULL; 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) { 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tcm->tcm_handle) { 1081cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (q && !(n->nlmsg_flags & NLM_F_REPLACE)) 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (TC_H_MIN(tcm->tcm_handle)) 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1085cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = qdisc_lookup(dev, tcm->tcm_handle); 1086cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!q) 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto create_n_graft; 1088cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (n->nlmsg_flags & NLM_F_EXCL) 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 10901e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == p || 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (p && check_loop(q, p, 0))) 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ELOOP; 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&q->refcnt); 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto graft; 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1098cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!q) 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto create_n_graft; 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This magic test requires explanation. 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We know, that some child q is already 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attached to this parent and have choice: 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * either to change it or to create/graft new one. 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. We are allowed to create/graft only 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if CREATE and REPLACE flags are set. 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. If EXCL is set, requestor wanted to say, 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that qdisc tcm_handle is not expected 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to exist, so that we choose create/graft too. 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3. The last case is when no flags are set. 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alas, it is sort of hole in API, we 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cannot decide what to do unambiguously. 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For now we select create/graft, if 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * user gave KIND, which does not match existing. 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1120cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if ((n->nlmsg_flags & NLM_F_CREATE) && 1121cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet (n->nlmsg_flags & NLM_F_REPLACE) && 1122cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet ((n->nlmsg_flags & NLM_F_EXCL) || 11231e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy (tca[TCA_KIND] && 11241e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy nla_strcmp(tca[TCA_KIND], q->ops->id)))) 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto create_n_graft; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tcm->tcm_handle) 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = qdisc_lookup(dev, tcm->tcm_handle); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Change qdisc parameters */ 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == NULL) 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 1137cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (n->nlmsg_flags & NLM_F_EXCL) 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 11391e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = qdisc_change(q, tca); 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == 0) 11437316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff qdisc_notify(net, skb, n, clid, NULL, q); 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscreate_n_graft: 1147cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!(n->nlmsg_flags & NLM_F_CREATE)) 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 114924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (clid == TC_H_INGRESS) { 115024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (dev_ingress_queue(dev)) 115124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet q = qdisc_create(dev, dev_ingress_queue(dev), p, 115224824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet tcm->tcm_parent, tcm->tcm_parent, 115324824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet tca, &err); 115424824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet else 115524824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet err = -ENOENT; 115624824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet } else { 1157926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski struct netdev_queue *dev_queue; 11586ec1c69a8f6492fd25722f4762721921da074c12David S. Miller 11596ec1c69a8f6492fd25722f4762721921da074c12David S. Miller if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue) 1160926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski dev_queue = p->ops->cl_ops->select_queue(p, tcm); 1161926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski else if (p) 1162926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski dev_queue = p->dev_queue; 1163926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski else 1164926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski dev_queue = netdev_get_tx_queue(dev, 0); 11656ec1c69a8f6492fd25722f4762721921da074c12David S. Miller 1166926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski q = qdisc_create(dev, dev_queue, p, 1167bb949fbd1878973c3539d9aecff52f284482a937David S. Miller tcm->tcm_parent, tcm->tcm_handle, 1168ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy tca, &err); 11696ec1c69a8f6492fd25722f4762721921da074c12David S. Miller } 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == NULL) { 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == -EAGAIN) 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto replay; 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgraft: 1177e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen err = qdisc_graft(dev, p, skb, n, clid, q, NULL); 1178e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen if (err) { 1179e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen if (q) 1180e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen qdisc_destroy(q); 1181e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen return err; 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1183e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, 1188e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim u32 pid, u32 seq, u16 flags, int event) 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm; 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nlmsghdr *nlh; 119227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo unsigned char *b = skb_tail_pointer(skb); 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gnet_dump d; 1194a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet struct qdisc_size_table *stab; 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1196e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm = NLMSG_DATA(nlh); 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_family = AF_UNSPEC; 11999ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy tcm->tcm__pad1 = 0; 12009ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy tcm->tcm__pad2 = 0; 12015ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller tcm->tcm_ifindex = qdisc_dev(q)->ifindex; 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_parent = clid; 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_handle = q->handle; 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_info = atomic_read(&q->refcnt); 12051b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put_string(skb, TCA_KIND, q->ops->id)) 12061b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->ops->dump && q->ops->dump(q, skb) < 0) 12081e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->qstats.qlen = q->q.qlen; 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet stab = rtnl_dereference(q->stab); 1212a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet if (stab && qdisc_dump_stab(skb, stab) < 0) 1213175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna goto nla_put_failure; 1214175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 1215102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, 1216102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski qdisc_root_sleeping_lock(q), &d) < 0) 12171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0) 12201e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_copy_basic(&d, &q->bstats) < 0 || 1223d250a5f90e53f5e150618186230795352d154c88Eric Dumazet gnet_stats_copy_rate_est(&d, &q->bstats, &q->rate_est) < 0 || 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gnet_stats_copy_queue(&d, &q->qstats) < 0) 12251e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 122610297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_finish_copy(&d) < 0) 12281e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 122910297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 123027a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo nlh->nlmsg_len = skb_tail_pointer(skb) - b; 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure: 12341e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure: 1235dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo nlmsg_trim(skb, b); 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 123953b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazetstatic bool tc_qdisc_dump_ignore(struct Qdisc *q) 124053b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet{ 124153b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet return (q->flags & TCQ_F_BUILTIN) ? true : false; 124253b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet} 124353b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet 12447316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int qdisc_notify(struct net *net, struct sk_buff *oskb, 12457316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct nlmsghdr *n, u32 clid, 12467316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct Qdisc *old, struct Qdisc *new) 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 125553b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet if (old && !tc_qdisc_dump_ignore(old)) { 1256cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 1257cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet 0, RTM_DELQDISC) < 0) 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 126053b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet if (new && !tc_qdisc_dump_ignore(new)) { 1261cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, 1262cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0) 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb->len) 1267cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet return rtnetlink_send(skb, net, pid, RTNLGRP_TC, 1268cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet n->nlmsg_flags & NLM_F_ECHO); 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out: 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12753072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, 12763072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netlink_callback *cb, 12773072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int *q_idx_p, int s_q_idx) 12783072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 12793072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int ret = 0, q_idx = *q_idx_p; 12803072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct Qdisc *q; 12813072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12823072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!root) 12833072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 12843072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12853072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q = root; 12863072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (q_idx < s_q_idx) { 12873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 12883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } else { 12893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!tc_qdisc_dump_ignore(q) && 12903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, 12913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) 12923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 12933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 12943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 12953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller list_for_each_entry(q, &root->list, list) { 12963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (q_idx < s_q_idx) { 12973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 12983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller continue; 12993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 1300cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!tc_qdisc_dump_ignore(q) && 13013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, 13023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) 13033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 13043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 13053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 13063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 13073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerout: 13083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller *q_idx_p = q_idx; 13093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return ret; 13103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone: 13113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller ret = -1; 13123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto out; 13133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 13143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13173b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx, q_idx; 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int s_idx, s_q_idx; 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_idx = cb->args[0]; 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_q_idx = q_idx = cb->args[1]; 1324f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger 1325f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger rcu_read_lock(); 13267562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov idx = 0; 13277316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff for_each_netdev_rcu(net, dev) { 13283072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netdev_queue *dev_queue; 13293072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx < s_idx) 13317562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov goto cont; 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx > s_idx) 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_q_idx = 0; 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q_idx = 0; 13353072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 1336af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0) 13373072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 13383072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 133924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet dev_queue = dev_ingress_queue(dev); 134024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (dev_queue && 134124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, 134224824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet &q_idx, s_q_idx) < 0) 13433072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 13443072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 13457562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianovcont: 13467562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov idx++; 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 1350f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger rcu_read_unlock(); 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb->args[0] = idx; 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb->args[1] = q_idx; 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************ 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Traffic classes manipulation. * 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/ 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13683b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm = NLMSG_DATA(n); 13701e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *tca[TCA_MAX + 1]; 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q = NULL; 137320fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops; 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl = 0; 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long new_cl; 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pid = tcm->tcm_parent; 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clid = tcm->tcm_handle; 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 qid = TC_H_MAJ(clid); 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet dev = __dev_get_by_index(net, tcm->tcm_ifindex); 1382cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!dev) 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13851e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 13861e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (err < 0) 13871e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy return err; 13881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == TC_H_UNSPEC - unspecified parent. 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == TC_H_ROOT - class is root, which has no parent. 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == X:0 - parent is root class. 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == X:Y - parent is a node in hierarchy. 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == 0:Y - parent is X:Y, where X:0 is qdisc. 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == 0:0 - generate handle from kernel pool. 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == 0:Y - class is X:Y, where X:0 is qdisc. 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == X:Y - clear. 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == X:0 - root class. 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Step 1. Determine qdisc handle X:0 */ 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pid != TC_H_ROOT) { 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 qid1 = TC_H_MAJ(pid); 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qid && qid1) { 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If both majors are known, they must be identical. */ 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qid != qid1) 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (qid1) { 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qid = qid1; 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (qid == 0) 1414af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy qid = dev->qdisc->handle; 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now qid is genuine qdisc handle consistent 1417cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * both with parent and child. 1418cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * 1419cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * TC_H_MAJ(pid) still may be unspecified, complete it now. 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pid) 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pid = TC_H_MAKE(qid, pid); 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qid == 0) 1425af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy qid = dev->qdisc->handle; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK. Locate qdisc */ 1429cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = qdisc_lookup(dev, qid); 1430cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!q) 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* An check that it supports classes */ 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops = q->ops->cl_ops; 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cops == NULL) 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now try to get class */ 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid == 0) { 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pid == TC_H_ROOT) 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clid = qid; 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clid = TC_H_MAKE(qid, clid); 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid) 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cl = cops->get(q, clid); 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl == 0) { 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENOENT; 1450cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (n->nlmsg_type != RTM_NEWTCLASS || 1451cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet !(n->nlmsg_flags & NLM_F_CREATE)) 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (n->nlmsg_type) { 145510297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki case RTM_NEWTCLASS: 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EEXIST; 1457cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (n->nlmsg_flags & NLM_F_EXCL) 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case RTM_DELTCLASS: 1461de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy err = -EOPNOTSUPP; 1462de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy if (cops->delete) 1463de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy err = cops->delete(q, cl); 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == 0) 14657316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff tclass_notify(net, skb, n, q, cl, RTM_DELTCLASS); 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case RTM_GETTCLASS: 14687316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS); 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_cl = cl; 1477de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy err = -EOPNOTSUPP; 1478de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy if (cops->change) 1479de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy err = cops->change(q, clid, pid, tca, &new_cl); 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == 0) 14817316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS); 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl) 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops->put(q, cl); 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl, 1493e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim u32 pid, u32 seq, u16 flags, int event) 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm; 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nlmsghdr *nlh; 149727a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo unsigned char *b = skb_tail_pointer(skb); 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gnet_dump d; 149920fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501e431b8c004af6be03783dddea31b6e514118051dJamal Hadi Salim nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm = NLMSG_DATA(nlh); 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_family = AF_UNSPEC; 150416ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet tcm->tcm__pad1 = 0; 150516ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet tcm->tcm__pad2 = 0; 15065ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller tcm->tcm_ifindex = qdisc_dev(q)->ifindex; 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_parent = q->handle; 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_handle = q->handle; 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_info = 0; 15101b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put_string(skb, TCA_KIND, q->ops->id)) 15111b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0) 15131e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1515102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, 1516102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski qdisc_root_sleeping_lock(q), &d) < 0) 15171e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0) 15201e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_finish_copy(&d) < 0) 15231e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 152527a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo nlh->nlmsg_len = skb_tail_pointer(skb) - b; 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnlmsg_failure: 15291e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure: 1530dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo nlmsg_trim(skb, b); 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15347316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int tclass_notify(struct net *net, struct sk_buff *oskb, 15357316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct nlmsghdr *n, struct Qdisc *q, 15367316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff unsigned long cl, int event) 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tc_fill_tclass(skb, q, cl, pid, n->nlmsg_seq, 0, event) < 0) { 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1550cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet return rtnetlink_send(skb, net, pid, RTNLGRP_TC, 1551cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet n->nlmsg_flags & NLM_F_ECHO); 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1554cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstruct qdisc_dump_args { 1555cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet struct qdisc_walker w; 1556cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet struct sk_buff *skb; 1557cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet struct netlink_callback *cb; 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg) 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_dump_args *a = (struct qdisc_dump_args *)arg; 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tc_fill_tclass(a->skb, q, cl, NETLINK_CB(a->cb->skb).pid, 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS); 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15683072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb, 15693072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct tcmsg *tcm, struct netlink_callback *cb, 15703072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int *t_p, int s_t) 15713072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 15723072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct qdisc_dump_args arg; 15733072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15743072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (tc_qdisc_dump_ignore(q) || 15753072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller *t_p < s_t || !q->ops->cl_ops || 15763072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller (tcm->tcm_parent && 15773072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller TC_H_MAJ(tcm->tcm_parent) != q->handle)) { 15783072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller (*t_p)++; 15793072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 15803072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 15813072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (*t_p > s_t) 15823072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); 15833072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.fn = qdisc_class_dump; 15843072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.skb = skb; 15853072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.cb = cb; 15863072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.stop = 0; 15873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.skip = cb->args[1]; 15883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.count = 0; 15893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q->ops->cl_ops->walk(q, &arg.w); 15903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller cb->args[1] = arg.w.count; 15913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (arg.w.stop) 15923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return -1; 15933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller (*t_p)++; 15943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 15953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 15963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb, 15983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct tcmsg *tcm, struct netlink_callback *cb, 15993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int *t_p, int s_t) 16003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 16013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct Qdisc *q; 16023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!root) 16043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 16053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0) 16073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return -1; 16083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller list_for_each_entry(q, &root->list, list) { 16103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0) 16113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return -1; 16123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 16133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 16153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 16163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1619cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet struct tcmsg *tcm = (struct tcmsg *)NLMSG_DATA(cb->nlh); 16203b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 16213072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netdev_queue *dev_queue; 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 16233072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int t, s_t; 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1627cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet dev = dev_get_by_index(net, tcm->tcm_ifindex); 1628cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!dev) 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_t = cb->args[0]; 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = 0; 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1634af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0) 16353072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 16363072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 163724824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet dev_queue = dev_ingress_queue(dev); 163824824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (dev_queue && 163924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, 164024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet &t, s_t) < 0) 16413072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16433072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone: 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb->args[0] = t; 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(dev); 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Main classifier routine: scans classifier chain attached 1651cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * to this qdisc, (optionally) tests for protocol and asks 1652cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * specific classifiers. 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1654dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazetint tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp, 165573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy struct tcf_result *res) 165673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy{ 165773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy __be16 protocol = skb->protocol; 1658cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet int err; 165973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy 166073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy for (; tp; tp = tp->next) { 1661cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (tp->protocol != protocol && 1662cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet tp->protocol != htons(ETH_P_ALL)) 1663cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet continue; 1664cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet err = tp->classify(skb, tp, res); 1665cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet 1666cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (err >= 0) { 166773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#ifdef CONFIG_NET_CLS_ACT 166873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if (err != TC_ACT_RECLASSIFY && skb->tc_verd) 166973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0); 167073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif 167173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return err; 167273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy } 167373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy } 167473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return -1; 167573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy} 167673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify_compat); 167773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy 1678dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazetint tc_classify(struct sk_buff *skb, const struct tcf_proto *tp, 167973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy struct tcf_result *res) 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT 1683dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazet const struct tcf_proto *otp = tp; 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreclassify: 168552bc97470e22e67f11b054e51a31eee100ef6867Hagen Paul Pfeifer#endif 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 168773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy err = tc_classify_compat(skb, tp, res); 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT 168973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if (err == TC_ACT_RECLASSIFY) { 169073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy u32 verd = G_TC_VERD(skb->tc_verd); 169173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy tp = otp; 169273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy 169373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if (verd++ >= MAX_REC_LOOP) { 1694b60b6592baa69c43a5a0f55d6300a7feaab15338stephen hemminger if (net_ratelimit()) 1695cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet pr_notice("%s: packet reclassify loop" 1696b60b6592baa69c43a5a0f55d6300a7feaab15338stephen hemminger " rule prio %u protocol %02x\n", 1697cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet tp->q->ops->id, 1698cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet tp->prio & 0xffff, 1699cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet ntohs(tp->protocol)); 170073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return TC_ACT_SHOT; 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 170273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd); 170373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy goto reclassify; 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 170573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif 170673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return err; 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 170873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify); 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1710a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyvoid tcf_destroy(struct tcf_proto *tp) 1711a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{ 1712a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy tp->ops->destroy(tp); 1713a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy module_put(tp->ops->owner); 1714a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy kfree(tp); 1715a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy} 1716a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy 1717ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardyvoid tcf_destroy_chain(struct tcf_proto **fl) 1718a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{ 1719a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy struct tcf_proto *tp; 1720a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy 1721ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy while ((tp = *fl) != NULL) { 1722ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy *fl = tp->next; 1723a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy tcf_destroy(tp); 1724a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy } 1725a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy} 1726a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyEXPORT_SYMBOL(tcf_destroy_chain); 1727a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_show(struct seq_file *seq, void *v) 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17313c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy struct timespec ts; 17323c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy 17333c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy hrtimer_get_res(CLOCK_MONOTONIC, &ts); 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(seq, "%08x %08x %08x %08x\n", 1735ca44d6e60f9de26281fda203f58b570e1748c015Jarek Poplawski (u32)NSEC_PER_USEC, (u32)PSCHED_TICKS2NS(1), 1736514bca322cb9220308d22691ac1e74038bfabac3Patrick McHardy 1000000, 17373c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts))); 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_open(struct inode *inode, struct file *file) 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17447e5ab157813993356f021757d0b0dcbdca7c55a1Tom Goff return single_open(file, psched_show, NULL); 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1747da7071d7e32d15149cc513f096a3638097b66387Arjan van de Venstatic const struct file_operations psched_fops = { 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = psched_open, 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = seq_read, 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .llseek = seq_lseek, 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = single_release, 175310297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki}; 17547316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17557316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int __net_init psched_net_init(struct net *net) 17567316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{ 17577316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct proc_dir_entry *e; 17587316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17597316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff e = proc_net_fops_create(net, "psched", 0, &psched_fops); 17607316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff if (e == NULL) 17617316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff return -ENOMEM; 17627316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17637316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff return 0; 17647316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff} 17657316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17667316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void __net_exit psched_net_exit(struct net *net) 17677316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{ 17687316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff proc_net_remove(net, "psched"); 17697316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff} 17707316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff#else 17717316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int __net_init psched_net_init(struct net *net) 17727316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{ 17737316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff return 0; 17747316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff} 17757316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17767316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void __net_exit psched_net_exit(struct net *net) 17777316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{ 17787316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff} 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17817316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic struct pernet_operations psched_net_ops = { 17827316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff .init = psched_net_init, 17837316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff .exit = psched_net_exit, 17847316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}; 17857316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pktsched_init(void) 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17887316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff int err; 17897316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17907316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff err = register_pernet_subsys(&psched_net_ops); 17917316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff if (err) { 1792cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet pr_err("pktsched_init: " 17937316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff "cannot initialize per netns operations\n"); 17947316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff return err; 17957316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff } 17967316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_qdisc(&pfifo_qdisc_ops); 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_qdisc(&bfifo_qdisc_ops); 179957dbb2d83d100ea601c54fe129bfde0678db5deeHagen Paul Pfeifer register_qdisc(&pfifo_head_drop_qdisc_ops); 18006ec1c69a8f6492fd25722f4762721921da074c12David S. Miller register_qdisc(&mq_qdisc_ops); 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1802c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL, NULL); 1803c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL, NULL); 1804c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc, NULL); 1805c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL, NULL); 1806c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL, NULL); 1807c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass, NULL); 1808be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(pktsched_init); 1813