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 29440edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet if (tab == NULL || r->rate == 0 || r->cell_log == 0 || 29540edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet nla_len(tab) != TC_RTAB_SIZE) 29640edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet return NULL; 29740edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) { 29940edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet if (!memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) && 30040edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet !memcmp(&rtab->data, nla_data(tab), 1024)) { 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->refcnt++; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rtab; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab = kmalloc(sizeof(*rtab), GFP_KERNEL); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rtab) { 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->rate = *r; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->refcnt = 1; 3101e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy memcpy(rtab->data, nla_data(tab), 1024); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtab->next = qdisc_rtab_list; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qdisc_rtab_list = rtab; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rtab; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 31662e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_get_rtab); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qdisc_put_rtab(struct qdisc_rate_table *tab) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_rate_table *rtab, **rtabp; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tab || --tab->refcnt) 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 325cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet for (rtabp = &qdisc_rtab_list; 326cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet (rtab = *rtabp) != NULL; 327cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet rtabp = &rtab->next) { 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rtab == tab) { 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *rtabp = rtab->next; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(rtab); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33562e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_put_rtab); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 337175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic LIST_HEAD(qdisc_stab_list); 338175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic DEFINE_SPINLOCK(qdisc_stab_lock); 339175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 340175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = { 341175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna [TCA_STAB_BASE] = { .len = sizeof(struct tc_sizespec) }, 342175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna [TCA_STAB_DATA] = { .type = NLA_BINARY }, 343175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}; 344175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 345175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) 346175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 347175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct nlattr *tb[TCA_STAB_MAX + 1]; 348175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct qdisc_size_table *stab; 349175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct tc_sizespec *s; 350175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna unsigned int tsize = 0; 351175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna u16 *tab = NULL; 352175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna int err; 353175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 354175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy); 355175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (err < 0) 356175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(err); 357175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!tb[TCA_STAB_BASE]) 358175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-EINVAL); 359175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 360175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna s = nla_data(tb[TCA_STAB_BASE]); 361175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 362175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (s->tsize > 0) { 363175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!tb[TCA_STAB_DATA]) 364175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-EINVAL); 365175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna tab = nla_data(tb[TCA_STAB_DATA]); 366175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); 367175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 368175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 36900093fab980d0a8950a64bdf9e346d0497b9a7e4Dan Carpenter if (tsize != s->tsize || (!tab && tsize > 0)) 370175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-EINVAL); 371175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 372f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_lock(&qdisc_stab_lock); 373175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 374175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna list_for_each_entry(stab, &qdisc_stab_list, list) { 375175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (memcmp(&stab->szopts, s, sizeof(*s))) 376175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna continue; 377175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16))) 378175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna continue; 379175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->refcnt++; 380f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_unlock(&qdisc_stab_lock); 381175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return stab; 382175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 383175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 384f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_unlock(&qdisc_stab_lock); 385175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 386175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL); 387175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!stab) 388175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return ERR_PTR(-ENOMEM); 389175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 390175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->refcnt = 1; 391175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->szopts = *s; 392175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tsize > 0) 393175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna memcpy(stab->data, tab, tsize * sizeof(u16)); 394175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 395f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_lock(&qdisc_stab_lock); 396175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna list_add_tail(&stab->list, &qdisc_stab_list); 397f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_unlock(&qdisc_stab_lock); 398175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 399175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return stab; 400175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 401175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 402a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazetstatic void stab_kfree_rcu(struct rcu_head *head) 403a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet{ 404a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet kfree(container_of(head, struct qdisc_size_table, rcu)); 405a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet} 406a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet 407175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_put_stab(struct qdisc_size_table *tab) 408175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 409175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (!tab) 410175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return; 411175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 412f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_lock(&qdisc_stab_lock); 413175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 414175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (--tab->refcnt == 0) { 415175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna list_del(&tab->list); 416a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet call_rcu_bh(&tab->rcu, stab_kfree_rcu); 417175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 418175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 419f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller spin_unlock(&qdisc_stab_lock); 420175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 421175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_put_stab); 422175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 423175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab) 424175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 425175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna struct nlattr *nest; 426175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 427175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna nest = nla_nest_start(skb, TCA_STAB); 4283aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy if (nest == NULL) 4293aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy goto nla_put_failure; 4301b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts)) 4311b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 432175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna nla_nest_end(skb, nest); 433175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 434175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return skb->len; 435175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 436175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnanla_put_failure: 437175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return -1; 438175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 439175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 440a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazetvoid __qdisc_calculate_pkt_len(struct sk_buff *skb, const struct qdisc_size_table *stab) 441175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{ 442175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna int pkt_len, slot; 443175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 444175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = skb->len + stab->szopts.overhead; 445175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (unlikely(!stab->szopts.tsize)) 446175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna goto out; 447175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 448175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna slot = pkt_len + stab->szopts.cell_align; 449175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (unlikely(slot < 0)) 450175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna slot = 0; 451175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 452175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna slot >>= stab->szopts.cell_log; 453175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (likely(slot < stab->szopts.tsize)) 454175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = stab->data[slot]; 455175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna else 456175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = stab->data[stab->szopts.tsize - 1] * 457175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna (slot / stab->szopts.tsize) + 458175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab->data[slot % stab->szopts.tsize]; 459175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 460175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len <<= stab->szopts.size_log; 461175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnaout: 462175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (unlikely(pkt_len < 1)) 463175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna pkt_len = 1; 464175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna qdisc_skb_cb(skb)->pkt_len = pkt_len; 465175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna} 466a2da570d62fcb9e8816f6920e1ec02c706b289faEric DumazetEXPORT_SYMBOL(__qdisc_calculate_pkt_len); 467175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 468b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawskivoid qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc) 469b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski{ 470b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski if (!(qdisc->flags & TCQ_F_WARN_NONWC)) { 471cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet pr_warn("%s: %s qdisc %X: is non-work-conserving?\n", 472cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet txt, qdisc->ops->id, qdisc->handle >> 16); 473b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski qdisc->flags |= TCQ_F_WARN_NONWC; 474b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski } 475b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski} 476b00355db3f88d96810a60011a30cfb2c3469409dJarek PoplawskiEXPORT_SYMBOL(qdisc_warn_nonwc); 477b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski 4784179477f637caa730626bd597fdf28c5bad73565Patrick McHardystatic enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) 4794179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4804179477f637caa730626bd597fdf28c5bad73565Patrick McHardy struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, 4812fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller timer); 4824179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 483fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet qdisc_unthrottled(wd->qdisc); 4848608db031b4d2932d645709e2cfe8fbcd91a7305David S. Miller __netif_schedule(qdisc_root(wd->qdisc)); 4851936502d00ae6c2aa3931c42f6cf54afaba094f2Stephen Hemminger 4864179477f637caa730626bd597fdf28c5bad73565Patrick McHardy return HRTIMER_NORESTART; 4874179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 4884179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 4894179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc) 4904179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4912fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 4922fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller wd->timer.function = qdisc_watchdog; 4934179477f637caa730626bd597fdf28c5bad73565Patrick McHardy wd->qdisc = qdisc; 4944179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 4954179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_init); 4964179477f637caa730626bd597fdf28c5bad73565Patrick McHardy 49734c5d292ce05d2bf52e692c44292b0ababba2853Jiri Pirkovoid qdisc_watchdog_schedule_ns(struct qdisc_watchdog *wd, u64 expires) 4984179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{ 4992540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski if (test_bit(__QDISC_STATE_DEACTIVATED, 5002540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski &qdisc_root_sleeping(wd->qdisc)->state)) 5012540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski return; 5022540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski 503fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet qdisc_throttled(wd->qdisc); 50446baac38ef633b08168d27df7b02eb14578fb760Eric Dumazet 50546baac38ef633b08168d27df7b02eb14578fb760Eric Dumazet hrtimer_start(&wd->timer, 50634c5d292ce05d2bf52e692c44292b0ababba2853Jiri Pirko ns_to_ktime(expires), 50746baac38ef633b08168d27df7b02eb14578fb760Eric Dumazet HRTIMER_MODE_ABS); 5084179477f637caa730626bd597fdf28c5bad73565Patrick McHardy} 50934c5d292ce05d2bf52e692c44292b0ababba2853Jiri PirkoEXPORT_SYMBOL(qdisc_watchdog_schedule_ns); 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; 549b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin struct hlist_node *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++) { 568b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin hlist_for_each_entry_safe(cl, 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); 8371abbe1394a84c10919e32242318e715b04d7e33bEric Dumazet if (!netif_is_multiqueue(dev)) 8381abbe1394a84c10919e32242318e715b04d7e33bEric Dumazet sch->flags |= TCQ_F_ONETXQUEUE; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8413d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf sch->handle = handle; 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8431e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) { 844175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tca[TCA_STAB]) { 845175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab = qdisc_get_stab(tca[TCA_STAB]); 846175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (IS_ERR(stab)) { 847175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna err = PTR_ERR(stab); 8487c64b9f3f584008000cf3b960f25cd6a68fce191Jarek Poplawski goto err_out4; 849175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 850a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet rcu_assign_pointer(sch->stab, stab); 851175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 8521e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_RATE]) { 853f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski spinlock_t *root_lock; 854f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski 85523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy err = -EOPNOTSUPP; 85623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (sch->flags & TCQ_F_MQROOT) 85723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy goto err_out4; 85823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy 859f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski if ((sch->parent != TC_H_ROOT) && 86023bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy !(sch->flags & TCQ_F_INGRESS) && 86123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy (!p || !(p->flags & TCQ_F_MQROOT))) 862f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski root_lock = qdisc_root_sleeping_lock(sch); 863f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski else 864f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski root_lock = qdisc_lock(sch); 865f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski 866023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf err = gen_new_estimator(&sch->bstats, &sch->rate_est, 867f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski root_lock, tca[TCA_RATE]); 86823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (err) 86923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy goto err_out4; 870023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf } 871f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski 872f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski qdisc_list_add(sch); 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sch; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out3: 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(dev); 8783d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf kfree((char *) sch - sch->padded); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out2: 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds module_put(ops->owner); 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out: 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *errp = err; 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 88423bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy 88523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyerr_out4: 88623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy /* 88723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy * Any broken qdiscs that would require a ops->reset() here? 88823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy * The qdisc was never in action so it shouldn't be necessary. 88923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy */ 890a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet qdisc_put_stab(rtnl_dereference(sch->stab)); 89123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (ops->destroy) 89223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy ops->destroy(sch); 89323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy goto err_out3; 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8961e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int qdisc_change(struct Qdisc *sch, struct nlattr **tca) 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 898a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet struct qdisc_size_table *ostab, *stab = NULL; 899175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna int err = 0; 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tca[TCA_OPTIONS]) { 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sch->ops->change == NULL) 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9041e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = sch->ops->change(sch, tca[TCA_OPTIONS]); 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 908175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 909175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (tca[TCA_STAB]) { 910175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna stab = qdisc_get_stab(tca[TCA_STAB]); 911175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna if (IS_ERR(stab)) 912175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return PTR_ERR(stab); 913175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna } 914175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 915a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet ostab = rtnl_dereference(sch->stab); 916a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet rcu_assign_pointer(sch->stab, stab); 917a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet qdisc_put_stab(ostab); 918175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 91923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (tca[TCA_RATE]) { 92071bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger /* NB: ignores errors from replace_estimator 92171bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger because change can't be undone. */ 92223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy if (sch->flags & TCQ_F_MQROOT) 92323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy goto out; 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gen_replace_estimator(&sch->bstats, &sch->rate_est, 92571bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger qdisc_root_sleeping_lock(sch), 92671bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger tca[TCA_RATE]); 92723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy } 92823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyout: 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 932cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstruct check_loop_arg { 933cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet struct qdisc_walker w; 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *p; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int depth; 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w); 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop(struct Qdisc *q, struct Qdisc *p, int depth) 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct check_loop_arg arg; 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->ops->cl_ops == NULL) 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.w.stop = arg.w.skip = arg.w.count = 0; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.w.fn = check_loop_fn; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.depth = depth; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg.p = p; 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->ops->cl_ops->walk(q, &arg.w); 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return arg.w.stop ? -ELOOP : 0; 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w) 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *leaf; 95920fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops = q->ops->cl_ops; 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct check_loop_arg *arg = (struct check_loop_arg *)w; 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds leaf = cops->leaf(q, cl); 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (leaf) { 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (leaf == arg->p || arg->depth > 7) 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ELOOP; 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return check_loop(leaf, arg->p, arg->depth + 1); 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete/get qdisc. 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 975661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59Thomas Grafstatic int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n) 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9773b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 97802ef22ca4044fe90867f77cba720e4a442122826David S. Miller struct tcmsg *tcm = nlmsg_data(n); 9791e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *tca[TCA_MAX + 1]; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 981de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo u32 clid; 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q = NULL; 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *p = NULL; 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 986dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman if ((n->nlmsg_type != RTM_GETQDISC) && !capable(CAP_NET_ADMIN)) 987dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman return -EPERM; 988dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman 9891e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 9901e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (err < 0) 9911e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy return err; 9921e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy 993de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo dev = __dev_get_by_index(net, tcm->tcm_ifindex); 994de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo if (!dev) 995de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo return -ENODEV; 996de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo 997de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo clid = tcm->tcm_parent; 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid) { 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid != TC_H_ROOT) { 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) { 1001cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet p = qdisc_lookup(dev, TC_H_MAJ(clid)); 1002cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!p) 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = qdisc_leaf(p, clid); 1005cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet } else if (dev_ingress_queue(dev)) { 1006cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = dev_ingress_queue(dev)->qdisc_sleeping; 100710297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki } 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1009af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy q = dev->qdisc; 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!q) 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tcm->tcm_handle && q->handle != tcm->tcm_handle) 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1017cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = qdisc_lookup(dev, tcm->tcm_handle); 1018cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!q) 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10221e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n->nlmsg_type == RTM_DELQDISC) { 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!clid) 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->handle == 0) 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 1030cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet err = qdisc_graft(dev, p, skb, n, clid, NULL, q); 1031cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (err != 0) 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10347316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff qdisc_notify(net, skb, n, clid, NULL, q); 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1040cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * Create/change qdisc. 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1043661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59Thomas Grafstatic int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n) 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10453b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm; 10471e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *tca[TCA_MAX + 1]; 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clid; 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q, *p; 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1053dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman if (!capable(CAP_NET_ADMIN)) 1054dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman return -EPERM; 1055dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreplay: 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reinit, just in case something touches this. */ 1058de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 1059de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo if (err < 0) 1060de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo return err; 1061de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo 106202ef22ca4044fe90867f77cba720e4a442122826David S. Miller tcm = nlmsg_data(n); 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clid = tcm->tcm_parent; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = p = NULL; 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1066cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet dev = __dev_get_by_index(net, tcm->tcm_ifindex); 1067cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!dev) 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10701e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid) { 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid != TC_H_ROOT) { 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid != TC_H_INGRESS) { 1074cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet p = qdisc_lookup(dev, TC_H_MAJ(clid)); 1075cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!p) 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = qdisc_leaf(p, clid); 1078cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet } else if (dev_ingress_queue_create(dev)) { 1079cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = dev_ingress_queue(dev)->qdisc_sleeping; 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1082af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy q = dev->qdisc; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* It may be default qdisc, ignore it */ 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q && q->handle == 0) 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = NULL; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) { 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tcm->tcm_handle) { 1091cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (q && !(n->nlmsg_flags & NLM_F_REPLACE)) 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (TC_H_MIN(tcm->tcm_handle)) 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1095cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = qdisc_lookup(dev, tcm->tcm_handle); 1096cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!q) 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto create_n_graft; 1098cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (n->nlmsg_flags & NLM_F_EXCL) 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 11001e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == p || 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (p && check_loop(q, p, 0))) 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ELOOP; 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&q->refcnt); 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto graft; 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1108cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!q) 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto create_n_graft; 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This magic test requires explanation. 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We know, that some child q is already 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attached to this parent and have choice: 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * either to change it or to create/graft new one. 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. We are allowed to create/graft only 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if CREATE and REPLACE flags are set. 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. If EXCL is set, requestor wanted to say, 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that qdisc tcm_handle is not expected 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to exist, so that we choose create/graft too. 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3. The last case is when no flags are set. 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alas, it is sort of hole in API, we 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cannot decide what to do unambiguously. 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For now we select create/graft, if 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * user gave KIND, which does not match existing. 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1130cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if ((n->nlmsg_flags & NLM_F_CREATE) && 1131cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet (n->nlmsg_flags & NLM_F_REPLACE) && 1132cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet ((n->nlmsg_flags & NLM_F_EXCL) || 11331e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy (tca[TCA_KIND] && 11341e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy nla_strcmp(tca[TCA_KIND], q->ops->id)))) 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto create_n_graft; 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tcm->tcm_handle) 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = qdisc_lookup(dev, tcm->tcm_handle); 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Change qdisc parameters */ 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == NULL) 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 1147cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (n->nlmsg_flags & NLM_F_EXCL) 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 11491e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = qdisc_change(q, tca); 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == 0) 11537316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff qdisc_notify(net, skb, n, clid, NULL, q); 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscreate_n_graft: 1157cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!(n->nlmsg_flags & NLM_F_CREATE)) 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 115924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (clid == TC_H_INGRESS) { 116024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (dev_ingress_queue(dev)) 116124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet q = qdisc_create(dev, dev_ingress_queue(dev), p, 116224824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet tcm->tcm_parent, tcm->tcm_parent, 116324824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet tca, &err); 116424824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet else 116524824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet err = -ENOENT; 116624824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet } else { 1167926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski struct netdev_queue *dev_queue; 11686ec1c69a8f6492fd25722f4762721921da074c12David S. Miller 11696ec1c69a8f6492fd25722f4762721921da074c12David S. Miller if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue) 1170926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski dev_queue = p->ops->cl_ops->select_queue(p, tcm); 1171926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski else if (p) 1172926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski dev_queue = p->dev_queue; 1173926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski else 1174926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski dev_queue = netdev_get_tx_queue(dev, 0); 11756ec1c69a8f6492fd25722f4762721921da074c12David S. Miller 1176926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski q = qdisc_create(dev, dev_queue, p, 1177bb949fbd1878973c3539d9aecff52f284482a937David S. Miller tcm->tcm_parent, tcm->tcm_handle, 1178ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy tca, &err); 11796ec1c69a8f6492fd25722f4762721921da074c12David S. Miller } 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == NULL) { 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == -EAGAIN) 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto replay; 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgraft: 1187e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen err = qdisc_graft(dev, p, skb, n, clid, q, NULL); 1188e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen if (err) { 1189e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen if (q) 1190e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen qdisc_destroy(q); 1191e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen return err; 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1193e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, 119815e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman u32 portid, u32 seq, u16 flags, int event) 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm; 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nlmsghdr *nlh; 120227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo unsigned char *b = skb_tail_pointer(skb); 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gnet_dump d; 1204a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet struct qdisc_size_table *stab; 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 120615e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags); 120702ef22ca4044fe90867f77cba720e4a442122826David S. Miller if (!nlh) 120802ef22ca4044fe90867f77cba720e4a442122826David S. Miller goto out_nlmsg_trim; 120902ef22ca4044fe90867f77cba720e4a442122826David S. Miller tcm = nlmsg_data(nlh); 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_family = AF_UNSPEC; 12119ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy tcm->tcm__pad1 = 0; 12129ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy tcm->tcm__pad2 = 0; 12135ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller tcm->tcm_ifindex = qdisc_dev(q)->ifindex; 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_parent = clid; 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_handle = q->handle; 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_info = atomic_read(&q->refcnt); 12171b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put_string(skb, TCA_KIND, q->ops->id)) 12181b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->ops->dump && q->ops->dump(q, skb) < 0) 12201e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->qstats.qlen = q->q.qlen; 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1223a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet stab = rtnl_dereference(q->stab); 1224a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet if (stab && qdisc_dump_stab(skb, stab) < 0) 1225175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna goto nla_put_failure; 1226175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna 1227102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, 1228102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski qdisc_root_sleeping_lock(q), &d) < 0) 12291e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0) 12321e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_copy_basic(&d, &q->bstats) < 0 || 1235d250a5f90e53f5e150618186230795352d154c88Eric Dumazet gnet_stats_copy_rate_est(&d, &q->bstats, &q->rate_est) < 0 || 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gnet_stats_copy_queue(&d, &q->qstats) < 0) 12371e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 123810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_finish_copy(&d) < 0) 12401e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 124110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 124227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo nlh->nlmsg_len = skb_tail_pointer(skb) - b; 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 124502ef22ca4044fe90867f77cba720e4a442122826David S. Millerout_nlmsg_trim: 12461e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure: 1247dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo nlmsg_trim(skb, b); 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 125153b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazetstatic bool tc_qdisc_dump_ignore(struct Qdisc *q) 125253b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet{ 125353b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet return (q->flags & TCQ_F_BUILTIN) ? true : false; 125453b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet} 125553b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet 12567316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int qdisc_notify(struct net *net, struct sk_buff *oskb, 12577316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct nlmsghdr *n, u32 clid, 12587316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct Qdisc *old, struct Qdisc *new) 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 126115e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 126753b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet if (old && !tc_qdisc_dump_ignore(old)) { 126815e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman if (tc_fill_qdisc(skb, old, clid, portid, n->nlmsg_seq, 1269cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet 0, RTM_DELQDISC) < 0) 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 127253b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet if (new && !tc_qdisc_dump_ignore(new)) { 127315e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman if (tc_fill_qdisc(skb, new, clid, portid, n->nlmsg_seq, 1274cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0) 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb->len) 127915e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman return rtnetlink_send(skb, net, portid, RTNLGRP_TC, 1280cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet n->nlmsg_flags & NLM_F_ECHO); 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out: 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, 12883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netlink_callback *cb, 12893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int *q_idx_p, int s_q_idx) 12903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 12913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int ret = 0, q_idx = *q_idx_p; 12923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct Qdisc *q; 12933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!root) 12953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 12963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 12973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q = root; 12983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (q_idx < s_q_idx) { 12993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 13003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } else { 13013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!tc_qdisc_dump_ignore(q) && 130215e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).portid, 13033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) 13043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 13053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 13063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 13073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller list_for_each_entry(q, &root->list, list) { 13083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (q_idx < s_q_idx) { 13093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 13103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller continue; 13113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 1312cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!tc_qdisc_dump_ignore(q) && 131315e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).portid, 13143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) 13153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 13163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q_idx++; 13173072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 13183072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 13193072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerout: 13203072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller *q_idx_p = q_idx; 13213072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return ret; 13223072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone: 13233072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller ret = -1; 13243072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto out; 13253072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 13263072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13293b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx, q_idx; 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int s_idx, s_q_idx; 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_idx = cb->args[0]; 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_q_idx = q_idx = cb->args[1]; 1336f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger 1337f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger rcu_read_lock(); 13387562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov idx = 0; 13397316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff for_each_netdev_rcu(net, dev) { 13403072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netdev_queue *dev_queue; 13413072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx < s_idx) 13437562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov goto cont; 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx > s_idx) 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_q_idx = 0; 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q_idx = 0; 13473072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 1348af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0) 13493072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 13503072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 135124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet dev_queue = dev_ingress_queue(dev); 135224824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (dev_queue && 135324824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, 135424824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet &q_idx, s_q_idx) < 0) 13553072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 13563072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 13577562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianovcont: 13587562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov idx++; 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 1362f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger rcu_read_unlock(); 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb->args[0] = idx; 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb->args[1] = q_idx; 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************ 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Traffic classes manipulation. * 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/ 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1378661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59Thomas Grafstatic int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n) 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13803b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 138102ef22ca4044fe90867f77cba720e4a442122826David S. Miller struct tcmsg *tcm = nlmsg_data(n); 13821e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy struct nlattr *tca[TCA_MAX + 1]; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *q = NULL; 138520fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cops; 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl = 0; 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long new_cl; 1388de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo u32 portid; 1389de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo u32 clid; 1390de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo u32 qid; 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1393dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman if ((n->nlmsg_type != RTM_GETTCLASS) && !capable(CAP_NET_ADMIN)) 1394dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman return -EPERM; 1395dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman 13961e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 13971e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy if (err < 0) 13981e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy return err; 13991e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy 1400de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo dev = __dev_get_by_index(net, tcm->tcm_ifindex); 1401de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo if (!dev) 1402de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo return -ENODEV; 1403de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == TC_H_UNSPEC - unspecified parent. 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == TC_H_ROOT - class is root, which has no parent. 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == X:0 - parent is root class. 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == X:Y - parent is a node in hierarchy. 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent == 0:Y - parent is X:Y, where X:0 is qdisc. 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == 0:0 - generate handle from kernel pool. 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == 0:Y - class is X:Y, where X:0 is qdisc. 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == X:Y - clear. 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle == X:0 - root class. 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Step 1. Determine qdisc handle X:0 */ 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1419de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo portid = tcm->tcm_parent; 1420de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo clid = tcm->tcm_handle; 1421de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo qid = TC_H_MAJ(clid); 1422de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo 142315e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman if (portid != TC_H_ROOT) { 142415e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman u32 qid1 = TC_H_MAJ(portid); 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qid && qid1) { 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If both majors are known, they must be identical. */ 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qid != qid1) 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (qid1) { 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qid = qid1; 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (qid == 0) 1433af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy qid = dev->qdisc->handle; 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now qid is genuine qdisc handle consistent 1436cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * both with parent and child. 1437cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * 143815e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman * TC_H_MAJ(portid) still may be unspecified, complete it now. 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 144015e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman if (portid) 144115e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman portid = TC_H_MAKE(qid, portid); 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qid == 0) 1444af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy qid = dev->qdisc->handle; 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK. Locate qdisc */ 1448cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet q = qdisc_lookup(dev, qid); 1449cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!q) 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* An check that it supports classes */ 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops = q->ops->cl_ops; 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cops == NULL) 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now try to get class */ 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid == 0) { 145915e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman if (portid == TC_H_ROOT) 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clid = qid; 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clid = TC_H_MAKE(qid, clid); 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clid) 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cl = cops->get(q, clid); 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl == 0) { 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENOENT; 1469cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (n->nlmsg_type != RTM_NEWTCLASS || 1470cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet !(n->nlmsg_flags & NLM_F_CREATE)) 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (n->nlmsg_type) { 147410297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki case RTM_NEWTCLASS: 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EEXIST; 1476cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (n->nlmsg_flags & NLM_F_EXCL) 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case RTM_DELTCLASS: 1480de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy err = -EOPNOTSUPP; 1481de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy if (cops->delete) 1482de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy err = cops->delete(q, cl); 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == 0) 14847316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff tclass_notify(net, skb, n, q, cl, RTM_DELTCLASS); 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case RTM_GETTCLASS: 14877316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS); 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_cl = cl; 1496de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy err = -EOPNOTSUPP; 1497de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy if (cops->change) 149815e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman err = cops->change(q, clid, portid, tca, &new_cl); 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err == 0) 15007316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS); 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl) 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cops->put(q, cl); 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cl, 151215e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman u32 portid, u32 seq, u16 flags, int event) 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcmsg *tcm; 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nlmsghdr *nlh; 151627a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo unsigned char *b = skb_tail_pointer(skb); 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gnet_dump d; 151820fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 152015e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags); 152102ef22ca4044fe90867f77cba720e4a442122826David S. Miller if (!nlh) 152202ef22ca4044fe90867f77cba720e4a442122826David S. Miller goto out_nlmsg_trim; 152302ef22ca4044fe90867f77cba720e4a442122826David S. Miller tcm = nlmsg_data(nlh); 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_family = AF_UNSPEC; 152516ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet tcm->tcm__pad1 = 0; 152616ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet tcm->tcm__pad2 = 0; 15275ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller tcm->tcm_ifindex = qdisc_dev(q)->ifindex; 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_parent = q->handle; 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_handle = q->handle; 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcm->tcm_info = 0; 15311b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put_string(skb, TCA_KIND, q->ops->id)) 15321b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0) 15341e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1536102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, 1537102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski qdisc_root_sleeping_lock(q), &d) < 0) 15381e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0) 15411e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gnet_stats_finish_copy(&d) < 0) 15441e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy goto nla_put_failure; 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 154627a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo nlh->nlmsg_len = skb_tail_pointer(skb) - b; 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 154902ef22ca4044fe90867f77cba720e4a442122826David S. Millerout_nlmsg_trim: 15501e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure: 1551dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo nlmsg_trim(skb, b); 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15557316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int tclass_notify(struct net *net, struct sk_buff *oskb, 15567316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct nlmsghdr *n, struct Qdisc *q, 15577316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff unsigned long cl, int event) 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 156015e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 156615e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman if (tc_fill_tclass(skb, q, cl, portid, n->nlmsg_seq, 0, event) < 0) { 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 157115e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman return rtnetlink_send(skb, net, portid, RTNLGRP_TC, 1572cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet n->nlmsg_flags & NLM_F_ECHO); 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1575cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstruct qdisc_dump_args { 1576cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet struct qdisc_walker w; 1577cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet struct sk_buff *skb; 1578cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet struct netlink_callback *cb; 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg) 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qdisc_dump_args *a = (struct qdisc_dump_args *)arg; 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 158515e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman return tc_fill_tclass(a->skb, q, cl, NETLINK_CB(a->cb->skb).portid, 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS); 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb, 15903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct tcmsg *tcm, struct netlink_callback *cb, 15913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int *t_p, int s_t) 15923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 15933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct qdisc_dump_args arg; 15943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 15953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (tc_qdisc_dump_ignore(q) || 15963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller *t_p < s_t || !q->ops->cl_ops || 15973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller (tcm->tcm_parent && 15983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller TC_H_MAJ(tcm->tcm_parent) != q->handle)) { 15993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller (*t_p)++; 16003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 16013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 16023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (*t_p > s_t) 16033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); 16043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.fn = qdisc_class_dump; 16053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.skb = skb; 16063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.cb = cb; 16073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.stop = 0; 16083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.skip = cb->args[1]; 16093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller arg.w.count = 0; 16103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller q->ops->cl_ops->walk(q, &arg.w); 16113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller cb->args[1] = arg.w.count; 16123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (arg.w.stop) 16133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return -1; 16143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller (*t_p)++; 16153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 16163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 16173072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16183072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb, 16193072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct tcmsg *tcm, struct netlink_callback *cb, 16203072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int *t_p, int s_t) 16213072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{ 16223072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct Qdisc *q; 16233072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16243072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (!root) 16253072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 16263072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16273072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0) 16283072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return -1; 16293072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16303072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller list_for_each_entry(q, &root->list, list) { 16313072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0) 16323072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return -1; 16333072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller } 16343072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16353072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller return 0; 16363072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller} 16373072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 164002ef22ca4044fe90867f77cba720e4a442122826David S. Miller struct tcmsg *tcm = nlmsg_data(cb->nlh); 16413b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 16423072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller struct netdev_queue *dev_queue; 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 16443072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller int t, s_t; 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1646573ce260b385a4d14a1ef046558fad9f1daeee42Hong zhi guo if (nlmsg_len(cb->nlh) < sizeof(*tcm)) 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1648cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet dev = dev_get_by_index(net, tcm->tcm_ifindex); 1649cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (!dev) 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_t = cb->args[0]; 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = 0; 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1655af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0) 16563072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 16573072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller 165824824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet dev_queue = dev_ingress_queue(dev); 165924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet if (dev_queue && 166024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, 166124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet &t, s_t) < 0) 16623072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller goto done; 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16643072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone: 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb->args[0] = t; 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(dev); 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Main classifier routine: scans classifier chain attached 1672cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * to this qdisc, (optionally) tests for protocol and asks 1673cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * specific classifiers. 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1675dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazetint tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp, 167673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy struct tcf_result *res) 167773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy{ 167873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy __be16 protocol = skb->protocol; 1679cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet int err; 168073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy 168173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy for (; tp; tp = tp->next) { 1682cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (tp->protocol != protocol && 1683cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet tp->protocol != htons(ETH_P_ALL)) 1684cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet continue; 1685cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet err = tp->classify(skb, tp, res); 1686cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet 1687cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (err >= 0) { 168873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#ifdef CONFIG_NET_CLS_ACT 168973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if (err != TC_ACT_RECLASSIFY && skb->tc_verd) 169073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0); 169173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif 169273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return err; 169373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy } 169473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy } 169573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return -1; 169673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy} 169773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify_compat); 169873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy 1699dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazetint tc_classify(struct sk_buff *skb, const struct tcf_proto *tp, 170073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy struct tcf_result *res) 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT 1704dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazet const struct tcf_proto *otp = tp; 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreclassify: 170652bc97470e22e67f11b054e51a31eee100ef6867Hagen Paul Pfeifer#endif 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 170873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy err = tc_classify_compat(skb, tp, res); 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT 171073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if (err == TC_ACT_RECLASSIFY) { 171173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy u32 verd = G_TC_VERD(skb->tc_verd); 171273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy tp = otp; 171373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy 171473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy if (verd++ >= MAX_REC_LOOP) { 1715e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches net_notice_ratelimited("%s: packet reclassify loop rule prio %u protocol %02x\n", 1716e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches tp->q->ops->id, 1717e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches tp->prio & 0xffff, 1718e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches ntohs(tp->protocol)); 171973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return TC_ACT_SHOT; 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 172173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd); 172273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy goto reclassify; 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 172473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif 172573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy return err; 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 172773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify); 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1729a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyvoid tcf_destroy(struct tcf_proto *tp) 1730a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{ 1731a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy tp->ops->destroy(tp); 1732a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy module_put(tp->ops->owner); 1733a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy kfree(tp); 1734a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy} 1735a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy 1736ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardyvoid tcf_destroy_chain(struct tcf_proto **fl) 1737a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{ 1738a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy struct tcf_proto *tp; 1739a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy 1740ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy while ((tp = *fl) != NULL) { 1741ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy *fl = tp->next; 1742a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy tcf_destroy(tp); 1743a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy } 1744a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy} 1745a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyEXPORT_SYMBOL(tcf_destroy_chain); 1746a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_show(struct seq_file *seq, void *v) 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17503c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy struct timespec ts; 17513c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy 17523c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy hrtimer_get_res(CLOCK_MONOTONIC, &ts); 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(seq, "%08x %08x %08x %08x\n", 1754ca44d6e60f9de26281fda203f58b570e1748c015Jarek Poplawski (u32)NSEC_PER_USEC, (u32)PSCHED_TICKS2NS(1), 1755514bca322cb9220308d22691ac1e74038bfabac3Patrick McHardy 1000000, 17563c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts))); 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_open(struct inode *inode, struct file *file) 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17637e5ab157813993356f021757d0b0dcbdca7c55a1Tom Goff return single_open(file, psched_show, NULL); 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1766da7071d7e32d15149cc513f096a3638097b66387Arjan van de Venstatic const struct file_operations psched_fops = { 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = psched_open, 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = seq_read, 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .llseek = seq_lseek, 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = single_release, 177210297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki}; 17737316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17747316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int __net_init psched_net_init(struct net *net) 17757316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{ 17767316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff struct proc_dir_entry *e; 17777316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 1778d4beaa66add8aebf83ab16d2fde4e4de8dac36dfGao feng e = proc_create("psched", 0, net->proc_net, &psched_fops); 17797316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff if (e == NULL) 17807316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff return -ENOMEM; 17817316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17827316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff return 0; 17837316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff} 17847316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17857316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void __net_exit psched_net_exit(struct net *net) 17867316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{ 1787ece31ffd539e8e2b586b1ca5f50bc4f4591e3893Gao feng remove_proc_entry("psched", net->proc_net); 17887316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff} 17897316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff#else 17907316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int __net_init psched_net_init(struct net *net) 17917316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{ 17927316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff return 0; 17937316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff} 17947316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 17957316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void __net_exit psched_net_exit(struct net *net) 17967316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{ 17977316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff} 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18007316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic struct pernet_operations psched_net_ops = { 18017316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff .init = psched_net_init, 18027316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff .exit = psched_net_exit, 18037316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}; 18047316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pktsched_init(void) 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18077316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff int err; 18087316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 18097316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff err = register_pernet_subsys(&psched_net_ops); 18107316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff if (err) { 1811cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet pr_err("pktsched_init: " 18127316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff "cannot initialize per netns operations\n"); 18137316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff return err; 18147316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff } 18157316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_qdisc(&pfifo_qdisc_ops); 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_qdisc(&bfifo_qdisc_ops); 181857dbb2d83d100ea601c54fe129bfde0678db5deeHagen Paul Pfeifer register_qdisc(&pfifo_head_drop_qdisc_ops); 18196ec1c69a8f6492fd25722f4762721921da074c12David S. Miller register_qdisc(&mq_qdisc_ops); 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL, NULL); 1822c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL, NULL); 1823c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc, NULL); 1824c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL, NULL); 1825c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL, NULL); 1826c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass, NULL); 1827be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(pktsched_init); 1832