cgroup-net_cls子系统分析

28 篇文章 2 订阅
7 篇文章 2 订阅

1       Net_cls

1.1      原理

net_cls子系统是用来控制进程使用网络资源的,它并不直接控制网络读写,而是给网络包打上一个标记,具体的网络包控制由tc机制来处理。

net_cls实现的基本的思想就是将控制组和内核现有的网络包分类和调度的机制相关联。net_cls通过给控制组分配一个类标识符(classid)来指定该控制组的数据包将被分到哪个traffic class(net_cls只支持可分类的qdsic队列规则)。数据包在发送的时候会根据添加到设备qdisc上的cgroup filter将数据包分到与其classid相符的traffic class队列中,再由设备上设置的具体qdsic来控制数据包的发送,以达到控制网络资源使用的目的。

创建一个挂有net_cls的cgroup后,在其下会生有个名为net_cls.classid(默认初始值为0)的文件,通过这个文件指定该组进程相关的数据包进入哪个traffic class。通过向文件写入形如0xAAAABBBB的十六进制值(AAAA为主处理号,BBBB为次处理号,读取该值是以十进制显示),设置cgroup的classid后,再进行相应的tc配置,添加符合classid的traffic class,并使用cgroup filter。这样当cgroup中的进程需要使用网络接口发送数据包的时候,则会按照接口上classid相应的tc策略控制进程对网络资源的使用。

 

整体形式如下:

 

1.2      实现

net_cls中对应的核心数据结构为

structcgroup_cls_state{

       struct cgroup_subsys_state css;   //对应cgroup子系统状态描述符css

       u32 classid;   //用用于记录该cgroup的classid

};

cgroup_cls_state记录了该组设置的classid,对net_cls.classid读写时操作的就是这个值。在发送数据包过程中,内核会将进程所在的cgroup的classid存储在skb->sk->sk_classid中。

为了能和tc机制结合,net_cls模块添加了一个名为cgroup的filter,其相应的操作函数结构如下:

staticstruct tcf_proto_ops cls_cgroup_ops __read_mostly = {

       .kind             =     "cgroup",     //filter名称

       .init        =     cls_cgroup_init,   //初始化filter的id、root等相关信息

       .change         =     cls_cgroup_change,  //修改filter参数

       .classify =     cls_cgroup_classify,  //对数据包进行分类

       .destroy =     cls_cgroup_destroy,  //释放filter的root数据

       .get        =     cls_cgroup_get,   //获取引用

       .put        =     cls_cgroup_put,  //减少引用

       .delete          =     cls_cgroup_delete, //删除

       .walk            =     cls_cgroup_walk, //遍历filter参数

       .dump           =     cls_cgroup_dump, //用于输出信息

       .owner          =     THIS_MODULE,  //模块指针

};

其中定义了cgroup filter的相关的操作。在初始化net_cls模块时会注册cgroup filter,内核将其加入全局变量tcf_proto_base链表中:

register_tcf_proto_ops(&cls_cgroup_ops)。

tc命令是通过netlink与内核进行通信的,当使用tc filter add命令设置cgroup filter时,内核会调用已经注册的tc_ctl_tfilter函数进行处理。

static int __init tc_filter_init(void)

{

       rtnl_register(PF_UNSPEC,RTM_NEWTFILTER, tc_ctl_tfilter, NULL, NULL);

       rtnl_register(PF_UNSPEC,RTM_DELTFILTER, tc_ctl_tfilter, NULL, NULL);

       rtnl_register(PF_UNSPEC,RTM_GETTFILTER, tc_ctl_tfilter,

                    tc_dump_tfilter, NULL);

       return0;

}

tc_ctl_tfilter函数中遍历tcf_proto_base链表,根据tc命令中指定的cgroup过滤器,找到kind为cgroup的filter操做函数结构,并将其加入指定设备使用的qdsic的分类规则链表中。当发送一个数据的时候,在设备发送函数dev_queue_xmit中会根据设备上设置的qdisc,对数据包进行分类排队。分类时内核会遍历qdsic的分类规则链表,并调用相应的分类函数对数据包进行分类,这样之前添加的cgroup filter的分类函数就会被调用了。cgroup filter分类关键就是获取设置的classid,将该classid返回给qdisc进行数据包分类排队:

cgroupfilter先获取当前进程所在cgroup的classid:

rcu_read_lock();

       classid =task_cls_state(current)->classid;

       rcu_read_unlock();

如果是在软中断上下文中,为了确保结果的正确性,则直接获取存储在唉skb->sk中的classid:

if(in_serving_softirq()) {

              /* If there is an sk_classid we'lluse that. */

              if (!skb->sk)

                     return -1;

              classid =skb->sk->sk_classid;

       }

最终将结果保存,由cgroup filter绑定的qdisc根据获得的classid将数据包入队,进行具体的流量控制:

res->classid= classid;

res->class= 0;

1.3      使用 

使用net_cls子系统控制网络资源的使用,主要有以下三步:

1.   创建绑定net_cls的cgroup

2.   设置该cgroup的classid

3.   配置符合classid的tc策略配置(与tc流量控制紧密相关,可参考tc相关知识:http://www.netren.org/index.php/linux-tc.html)

例子:

1.创建net_cls子系统cgroup:

#mkdir /cgroup/net_cls

#mount –t cgroup –o net_cls net_cls/cgroup/net_cls

#mkdir /cgroup/net_cls/test

2.给cgroup test设置classid(1:1)

#echo 0x100001 >/cgroup/net_cls/cgroupa/net_cls.classid

#cat/cgroup/net_cls/cgroupa/net_cls.classid

65537

3.配置tc

#在设备eth0上创建添加队列规则qdisc,此处为htb流量控制

#tc qdisc add dev eth0 root handle 1:htb

# tc -s qdisc show dev eth0

qdischtb 1: root refcnt 2 r2q 10 default 0 direct_packets_stat 245

Sent27514 bytes 245 pkt (dropped 0, overlimits 0 requeues 0)

backlog0b 0p requeues 0

#在qdisc下建立一个类class,classid为1:1,与写入cgroup中的相对应

#tc class add dev eth0 parent 1:classid 1:1 htb rate 40mbit

# tc -s class  show dev eth0

classhtb 1:1 root prio 0 rate 40000Kbit ceil 40000Kbit burst 1600b cburst 1600b

Sent0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)

rate0bit 0pps backlog 0b 0p requeues 0

lended:0 borrowed: 0 giants: 0

tokens:5000 ctokens: 5000

#添加cgroup过滤器

#tc filter add dev eth0 parent 1:protocol ip prio 10 handle 1: cgroup

# tc -s filter show dev eth0

filterparent 1: protocol ip pref 10 cgroup handle 0x1

 

看看限制的效果:

# time scp iperf-2.0.4.tar.gz  128.5.130.21:/home/w00227741/

real 0m1.894s

user 0m0.020s

sys  0m0.004s

# time  cgexec -g net_cls:test scp iperf-2.0.4.tar.gz 128.5.130.21:/home/w00227741/  

real 0m2.429s

user 0m0.020s

sys  0m0.004s

#将可用带宽有4mbit改为1mbit

# tc class change dev br0 parent 10:classid 1:1 htb rate 1mbit

# time  cgexec -g net_cls:test scp iperf-2.0.4.tar.gz 128.5.130.21:/home/w00227741/

real 0m4.220s

user 0m0.020s

sys  0m0.000s

可见后两种情况比第一种要来的慢,且分配的带宽越少越慢。


  • 0
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马学

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值