mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 18:30:06 +00:00
![Florian Westphal](/assets/img/avatar_default.png)
The DRR scheduler requires that items on the active list are work
conserving, i.e. do not hold on to skbs for throttling purposes, etc.
Attaching e.g. tbf renders DRR useless because all other classes on the
active list are delayed as well.
So, warn users that this configuration won't work as expected; we
already do this in couple of other qdiscs, see e.g.
commit b00355db3f
('pkt_sched: sch_hfsc: sch_htb: Add non-work-conserving warning handler')
The 'const' change is needed to avoid compiler warning ("discards 'const'
qualifier from pointer target type").
tested with:
drr_hier() {
parent=$1
classes=$2
for i in $(seq 1 $classes); do
classid=$parent$(printf %x $i)
tc class add dev eth0 parent $parent classid $classid drr
tc qdisc add dev eth0 parent $classid tbf rate 64kbit burst 256kbit limit 64kbit
done
}
tc qdisc add dev eth0 root handle 1: drr
drr_hier 1: 32
tc filter add dev eth0 protocol all pref 1 parent 1: handle 1 flow hash keys dst perturb 1 divisor 32
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
125 lines
3.5 KiB
C
125 lines
3.5 KiB
C
#ifndef __NET_PKT_SCHED_H
|
|
#define __NET_PKT_SCHED_H
|
|
|
|
#include <linux/jiffies.h>
|
|
#include <linux/ktime.h>
|
|
#include <net/sch_generic.h>
|
|
|
|
struct qdisc_walker {
|
|
int stop;
|
|
int skip;
|
|
int count;
|
|
int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *);
|
|
};
|
|
|
|
#define QDISC_ALIGNTO 64
|
|
#define QDISC_ALIGN(len) (((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1))
|
|
|
|
static inline void *qdisc_priv(struct Qdisc *q)
|
|
{
|
|
return (char *) q + QDISC_ALIGN(sizeof(struct Qdisc));
|
|
}
|
|
|
|
/*
|
|
Timer resolution MUST BE < 10% of min_schedulable_packet_size/bandwidth
|
|
|
|
Normal IP packet size ~ 512byte, hence:
|
|
|
|
0.5Kbyte/1Mbyte/sec = 0.5msec, so that we need 50usec timer for
|
|
10Mbit ethernet.
|
|
|
|
10msec resolution -> <50Kbit/sec.
|
|
|
|
The result: [34]86 is not good choice for QoS router :-(
|
|
|
|
The things are not so bad, because we may use artificial
|
|
clock evaluated by integration of network data flow
|
|
in the most critical places.
|
|
*/
|
|
|
|
typedef u64 psched_time_t;
|
|
typedef long psched_tdiff_t;
|
|
|
|
/* Avoid doing 64 bit divide */
|
|
#define PSCHED_SHIFT 6
|
|
#define PSCHED_TICKS2NS(x) ((s64)(x) << PSCHED_SHIFT)
|
|
#define PSCHED_NS2TICKS(x) ((x) >> PSCHED_SHIFT)
|
|
|
|
#define PSCHED_TICKS_PER_SEC PSCHED_NS2TICKS(NSEC_PER_SEC)
|
|
#define PSCHED_PASTPERFECT 0
|
|
|
|
static inline psched_time_t psched_get_time(void)
|
|
{
|
|
return PSCHED_NS2TICKS(ktime_to_ns(ktime_get()));
|
|
}
|
|
|
|
static inline psched_tdiff_t
|
|
psched_tdiff_bounded(psched_time_t tv1, psched_time_t tv2, psched_time_t bound)
|
|
{
|
|
return min(tv1 - tv2, bound);
|
|
}
|
|
|
|
struct qdisc_watchdog {
|
|
struct hrtimer timer;
|
|
struct Qdisc *qdisc;
|
|
};
|
|
|
|
void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc);
|
|
void qdisc_watchdog_schedule_ns(struct qdisc_watchdog *wd, u64 expires);
|
|
|
|
static inline void qdisc_watchdog_schedule(struct qdisc_watchdog *wd,
|
|
psched_time_t expires)
|
|
{
|
|
qdisc_watchdog_schedule_ns(wd, PSCHED_TICKS2NS(expires));
|
|
}
|
|
|
|
void qdisc_watchdog_cancel(struct qdisc_watchdog *wd);
|
|
|
|
extern struct Qdisc_ops pfifo_qdisc_ops;
|
|
extern struct Qdisc_ops bfifo_qdisc_ops;
|
|
extern struct Qdisc_ops pfifo_head_drop_qdisc_ops;
|
|
|
|
int fifo_set_limit(struct Qdisc *q, unsigned int limit);
|
|
struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
|
|
unsigned int limit);
|
|
|
|
int register_qdisc(struct Qdisc_ops *qops);
|
|
int unregister_qdisc(struct Qdisc_ops *qops);
|
|
void qdisc_get_default(char *id, size_t len);
|
|
int qdisc_set_default(const char *id);
|
|
|
|
void qdisc_list_add(struct Qdisc *q);
|
|
void qdisc_list_del(struct Qdisc *q);
|
|
struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
|
|
struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
|
|
struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
|
|
struct nlattr *tab);
|
|
void qdisc_put_rtab(struct qdisc_rate_table *tab);
|
|
void qdisc_put_stab(struct qdisc_size_table *tab);
|
|
void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc);
|
|
int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
|
|
struct net_device *dev, struct netdev_queue *txq,
|
|
spinlock_t *root_lock);
|
|
|
|
void __qdisc_run(struct Qdisc *q);
|
|
|
|
static inline void qdisc_run(struct Qdisc *q)
|
|
{
|
|
if (qdisc_run_begin(q))
|
|
__qdisc_run(q);
|
|
}
|
|
|
|
int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp,
|
|
struct tcf_result *res);
|
|
int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
|
|
struct tcf_result *res);
|
|
|
|
/* Calculate maximal size of packet seen by hard_start_xmit
|
|
routine of this device.
|
|
*/
|
|
static inline unsigned int psched_mtu(const struct net_device *dev)
|
|
{
|
|
return dev->mtu + dev->hard_header_len;
|
|
}
|
|
|
|
#endif
|