ixp425上QoS开发

1、  流量控制的实现要求:路由器执行流量控制后,对每一个非特权IP都加以流量控制策略。实现对每一个IP地址的流量限制。

2、  实现思路:基于HTB方法。 通过c程序来执行的shell程序,来配置策略,创建类和分类器。然后在Netfilter中注册钩子函数,对数据包打标记,以便以分类器根据该标记来对数据包进行匹配。

3、  具体实现,分为两步:

1)用C语言来执行HTBshell命令(写入文件,最后执行该文件),文件中部分信息如下:

#!/bin/sh

tc qdisc del dev eth1 root 2>/dev/null   #删除以前的eth1qdisc

tc qdisc add dev eth1 root handle 1: htb   #eth1创建qdisc的根

tc class add dev eth1 parent 1:0 classid 1:1 htb rate 1024kbit ceil 1024kbit

#为创建子类1:1, 并限制该类的速率不超过1024

tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 1 fw flowid 1:1

#为该类创建分类器,标记为“1的数据包会被送往该类(handle 1:匹配标记为1的数据包)

tc qdisc add dev eth1 parent 1:1  handle 1 tbf rate 1024kbit burst 20k latency 10ms

在该类下创建tbf(令牌桶过滤器)队列队则

 

tc class add dev eth1 parent 1:0 classid 1:2 htb rate 1024kbit ceil 1024kbit

tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 2 fw flowid 1:2

tc qdisc add dev eth1 parent 1:2  handle 2 tbf rate 1024kbit burst 20k latency 10ms

tc class add dev eth1 parent 1:0 classid 1:89 htb rate 1024kbit ceil 1024kbit

tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 89 fw flowid 1:89

tc qdisc add dev eth1 parent 1:89  handle 89 tbf rate 1024kbit burst 20k latency 10ms

……

 

(2)在内核Netfilter中利用对数据包打标记,标记就对应以该数据包源或目的地址的C网段部分的数字,也就是分类器filter中handle对应的标记。这样,内核会根据打标记来匹配数据包,并根据标记来判断应有哪个分类器filter来处理。

以控制上行速率为例,在/linux/net/ipv4/netfilter/rate.c中编写针对上行数据包的HOOK(钩子)函数upload_hook,实现片段为:

unsigned int upload_rate_hook(unsigned int hooknum,

              struct sk_buff **pskb,

              const struct net_device *in,

              const struct net_device *out,

              int (*okfn)(struct sk_buff *))

{

       struct sk_buff *skb = *pskb;

       struct iphdr *iph;

       unsigned int n;

       iph = skb->nh.iph;

              if (skb->dev && skb->dev->name && strcmp(skb->dev->name, LAN_IFNAME) == 0)                //判断数据是否来自LAN口eth0

       {

              if (ip_counters_enable == 1)

              {

                     unsigned int subnet = iph->saddr & lan_ip_netmask;

                            if (subnet == lan_ip_subnet)  //判断是都否和LAN口在一个网段

                     {

                     struct tcphdr *tcph = (void *)iph + iph->ihl*4;

                     if (iph->daddr == lan_ip_addr && ntohs(tcph->dest) == 80)

                             return NF_ACCEPT;

                     add_uprate(iph->saddr, ntohs(iph->tot_len)); //用于流量统计(与这里的QoS实现没关系)

                     n = iph->saddr & (~lan_ip_netmask);  //得到IP地址的C网段部分

                     skb->nfmark = n;             //给该IP包打上标记

                     skb->nfcache |= NFC_ALTERED;   //告知内核(打了标记这个)变化,

                     }

              }    

       }

       return NF_ACCEPT;

}           

其中n = iph->saddr & (~lan_ip_netmask)的作用是提取IP地址和子网掩码做相与,得到IP地址的C网段部分的数字,再利用skb->nfmark = n;给来自该IP地址的数据包打上标记“n”, 这个“n”就与分类器filter中handle对应的标记项对应,filter会将匹配的数据包送到相应的tc的class中,从而实现了对IP数据包的流量控制。skb_buff中的nfcache原来打算是用来做netfilter的cache机制的。就是说,如果一个数据包被netfilter中的某个module动过了的话,动这个数据包的那个模块就应该给这个skb的nfcache字段打个标记。

 

设计好HOOK函数后,还需要向内核Netfilter注册该HOOK函数,注册的实现方式如下:
      
static int __init  sfitc_init(void)函数中,添加:

static struct nf_hook_ops upload_hook_ops;  //定义一个nf_hook_ops数据结构

upload_hook_ops.hook = upload_rate_hook;   //指定对应的HOOK函数

upload_hook_ops.hooknum = NF_IP_PRE_ROUTING; //挂在PREROUTING链

macfilter_ops.pf     = PF_INET;               //网络协议指定

macfilter_ops.priority = (NF_IP_PRI_FIRST + 3);   //设置优先级

nf_register_hook(&upload_hook_ops);  //向内核注册nf_hook_ops数据结构

(4)在net/ipv4/netfilter下的Makefile中,加上obj-y += rate.o,编译内核的时候会将该模块编译进内核。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值