在Linux中实现一个调度
在Linux中,针对QoS有一个良好的框架,并对Qdisc,Class和Filter都有良好的接口定义。要在Linux中添加一个自己的调度算法需要时自己的算法按照已定义的接口实现,这样就可以无缝地加入到Linux中,并可以利用现成的tc工具进行配置。对于Qdisc定义如下:
struct Qdisc
{
int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
struct sk_buff *(*dequeue)(struct Qdisc *dev);
unsigned flags;
int padded;
struct Qdisc_ops *ops;
struct qdisc_size_table *stab;
struct list_head list;
u32 handle;
u32 parent;
atomic_t refcnt;
struct gnet_stats_rate_est rate_est;
int (*reshape_fail)(struct sk_buff *skb, struct Qdisc *q);
void *u32_node;
/* This field is deprecated, but it is still used by CBQ
* and it will live until better solution will be invented.
*/
struct Qdisc *__parent;
struct netdev_queue *dev_queue;
struct Qdisc *next_sched;
struct sk_buff *gso_skb;
unsigned long state;
struct sk_buff_head q;
struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats;
}
|
其中对于实现QoS算法最重要的struct Qdisc_ops定义如下:
struct Qdisc_ops
{
struct Qdisc_ops *next;
const struct Qdisc_class_ops *cl_ops;
char id[IFNAMSIZ];
int priv_size;
int (*enqueue)(struct sk_buff *, struct Qdisc *);
struct sk_buff * (*dequeue)(struct Qdisc *);
struct sk_buff * (*peek)(struct Qdisc *);
unsigned int (*drop)(struct Qdisc *);
int (*init)(struct Qdisc *, struct nlattr *arg);
void (*reset)(struct Qdisc *);
void (*destroy)(struct Qdisc *);
int (*change)(struct Qdisc *, struct nlattr *arg);
…
struct module *owner;
};
|
在此结构中,enqueue和dequeue两个函数是整个QoS调度的入口函数。其中的Qdisc_class_ops用于对此Qdisc的filter list进行操作,添加删除等,通过对Qdisc添加fliter,而filter对enqueue到此Qdisc的pkt进行分类,从而归类到此Qdisc的子class中,而每个子class都有自己的Qdisc进行pkt queue的管理,因此实现一个树形的filter结构,当然可以多个filter将pkt分到同一个子class中,但对于根Qdisc和其下的子class的Qdisc来说还是一个树形的分层结构。
Qdisc_class_ops的定义如下:
struct Qdisc_class_ops
{
/* Child qdisc manipulation */
int (*graft)(struct Qdisc *, unsigned long cl, struct Qdisc *, struct Qdisc **);
struct Qdisc * (*leaf)(struct Qdisc *, unsigned long cl);
void (*qlen_notify)(struct Qdisc *, unsigned long);
/* Class manipulation routines */
unsigned long (*get)(struct Qdisc *, u32 classid);
void (*put)(struct Qdisc *, unsigned long);
int (*change)(struct Qdisc *, u32, u32, struct nlattr **, unsigned long *);
int (*delete)(struct Qdisc *, unsigned long);
void (*walk)(struct Qdisc *, struct qdisc_walker * arg);
/* Filter manipulation */
struct tcf_proto ** (*tcf_chain)(struct Qdisc *, unsigned long);
unsigned long (*bind_tcf)(struct Qdisc *, unsigned long, u32 classid);
void (*unbind_tcf)(struct Qdisc *, unsigned long);
。。。
};
|
对于filter由结构体tcf_proto定义,其函数tcf_proto_ops为:
struct tcf_proto_ops
{
struct tcf_proto_ops *next;
char kind[IFNAMSIZ];
int (*classify)(struct sk_buff*, struct tcf_proto*,
struct tcf_result *);
int (*init)(struct tcf_proto*);
void (*destroy)(struct tcf_proto*);
unsigned long (*get)(struct tcf_proto*, u32 handle);
void (*put)(struct tcf_proto*, unsigned long);
int (*change)(struct tcf_proto*, unsigned long,
u32 handle, struct nlattr **,unsigned long *);
int (*delete)(struct tcf_proto*, unsigned long);
void (*walk)(struct tcf_proto*, struct tcf_walker *arg);
…
}
|
要在Linux中实现一个QoS算法,其入口函数就是struct Qdisc_ops,并通过register_qdisc 将自己的实现注册到系统中即可。
通过TC可以将QoS应用到网络设备上,命令如下:
> tc qdisc add dev eth1 root handle 1: htb > tc class add dev eth1 parent 1:0 classid 1:10 htb rate 100Mbit > tc class add dev eth1 parent 1:10 classid 1:20 htb rate 1Mbit > tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 match ipdst 192.168.1.200 flowid 1:20
|
以上命令,首先为eth1定义root qdisc,handle为1:0,其对应class带宽为100Mbps,class ID为1:10,然后在此class下定义子class带宽为1Mbps,class ID为1:20,并为此子class定义filter,filter定义为目标ip地址192.168.1.200
下面介绍DRR和HTB在Linux中的实现.
待续
阅读(2322) | 评论(0) | 转发(0) |