Chinaunix首页 | 论坛 | 博客
  • 博客访问: 372343
  • 博文数量: 64
  • 博客积分: 2975
  • 博客等级: 少校
  • 技术积分: 831
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-14 10:59
文章存档

2014年(2)

2012年(7)

2010年(40)

2009年(5)

2008年(8)

2007年(2)

分类: LINUX

2010-05-27 10:37:55

本次完成区分两个方向的包数和字节数统计功能,并记录最后一次跟新时间戳

1.修改include/linux/netfilter_ipv4/ip_conntrack.h
struct ipc_counters
{
    struct
    {
        u_int64_t pcnt, bcnt;            /*Packet and byte counters */
    }
    cnt[IP_CT_DIR_MAX];//两个方向
   
    unsigned long last; /*最后一次更新时的jiffies值*/
    spinlock_t lock;
};

2.修改net/ipv4/netfilter/ip_conntrack_standalone.c

print_conntrack函数
{
....
    //spin_lock(&conntrack->counters.lock);
   
    len += sprintf(buffer + len, "orig_pcnt=%Lu ",
               conntrack->counters.cnt[IP_CT_DIR_ORIGINAL].pcnt);

    len += sprintf(buffer + len, "orig_bcnt=%Lu ",
               conntrack->counters.cnt[IP_CT_DIR_ORIGINAL].bcnt);

    len += sprintf(buffer + len, "rply_pcnt=%Lu ",
               conntrack->counters.cnt[IP_CT_DIR_REPLY].pcnt);

    len += sprintf(buffer + len, "rply_bcnt=%Lu ",
               conntrack->counters.cnt[IP_CT_DIR_REPLY].bcnt);

    len += sprintf(buffer + len, "last=%u ",
               conntrack->counters.last);
              
    //spin_unlock(&conntrack->counters.lock);
....
}

3.修改tctable_filter.c
static void sum(struct sk_buff * skb,const char * msg)
{
    struct ip_conntrack *ct;
    enum ip_conntrack_info ctinfo;
       
    ct = ip_conntrack_get(skb, &ctinfo);
    if(ct)//有跟踪
    {              
        struct ipc_counters *cc=&(ct->counters);
        int dir=CTINFO2DIR(ctinfo);//取得方向
        spin_lock(&(cc->lock));
        cc->cnt[dir].pcnt++;
        cc->cnt[dir].bcnt+=ntohs(skb->nh.iph->tot_len);
        cc->last=jiffies;//取jiffies
        spin_unlock(&(cc->lock));       
    }
    else
    {   
        if (net_ratelimit())
            printk(KERN_DEBUG "%s:got untracked packet %p %u %u.%u.%u.%u -> %u.%u.%u.%u %u\n",
                   msg,
                   skb,
                   skb->nh.iph->protocol,
                   NIPQUAD(skb->nh.iph->saddr),
                   NIPQUAD(skb->nh.iph->daddr),
                   skb->nh.iph->protocol
                   );
    }
}


4.额外修改

tcp的established状态的超时时间在
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
被设成5天,太长,我们改成8分钟
static unsigned long tcp_timeouts[]
= { 30 MINS,     /*    TCP_CONNTRACK_NONE,    */
    //5 DAYS,    /*    TCP_CONNTRACK_ESTABLISHED,    */
    8 MINS,    /*    TCP_CONNTRACK_ESTABLISHED,    */
    2 MINS,    /*    TCP_CONNTRACK_SYN_SENT,    */
    60 SECS,    /*    TCP_CONNTRACK_SYN_RECV,    */
    2 MINS,    /*    TCP_CONNTRACK_FIN_WAIT,    */
    2 MINS,    /*    TCP_CONNTRACK_TIME_WAIT,    */
    10 SECS,    /*    TCP_CONNTRACK_CLOSE,    */
    60 SECS,    /*    TCP_CONNTRACK_CLOSE_WAIT,    */
    30 SECS,    /*    TCP_CONNTRACK_LAST_ACK,    */
    2 MINS,    /*    TCP_CONNTRACK_LISTEN,    */
};

5.编译并测试
make modules
make moduels_install

[root@localhost linux-2.4]# cat /proc/net/ip_conntrack
udp      17 0 src=10.1.9.30 dst=192.168.168.16 sport=32813 dport=53 src=192.168.168.16 dst=10.1.9.30 sport=53 dport=32813 use=1 orig_pcnt=1 orig_bcnt=68 rply_pcnt=1 rply_bcnt=118 last=666922
tcp      6 32 SYN_RECV src=192.168.199.1 dst=10.1.9.30 sport=1424 dport=139 src=10.1.9.30 dst=192.168.199.1 sport=139 dport=1424 use=1 orig_pcnt=1 orig_bcnt=48 rply_pcnt=5 rply_bcnt=240 last=667055

成功.


6.为何要增加last时间戳

为了计算连接的包速和字节速,第一时间能想到的方法是在内核中计算,使用类似于net/sched/estimator.c中的方法定时计算.经过仔细分析,有如下的缺点:
>连接数很多的情况下,将占用大量的cpu时间
>计算结果只对管理者要查询时有意义,绝大多数情况下无用
考虑到这两点,可以想办法把这个计算工作移交给监控的客户端,通过last时间戳,客户端可以定时获取连接信息,并根据前后两次的时间戳来计算包速和字节速.

7.如何获取连接信息

通过/proc/net/ip_conntrack方式获取连接信息的方法不可靠,因为通常不能一次就能读取/proc/net/ip_conntrack,proc文件系统的做法是,根据offset来决定下一次的读取位置.在conntrack中,offset是遍历ip_conntrack hash的每个conntrack的编号,list_conntracks是根据offset来定位到本次要读取的连接信息开始处读取信息
static int
list_conntracks(char *buffer, char **start, off_t offset, int length)
{
    unsigned int i;
    unsigned int len = 0;
    off_t upto = 0;
    struct list_head *e;

    READ_LOCK(&ip_conntrack_lock);
    /* Traverse hash; print originals then reply. */
    for (i = 0; i < ip_conntrack_htable_size; i++) {
        if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate,
                  struct ip_conntrack_tuple_hash *,
                  buffer, offset, &upto, &len, length))
            goto finished;
    }

但是conntrack变动是非常频繁的,可能在两次读取之间,offset之间插入或删除了大量的连接,这样看来
/proc/net/ip_conntrack有用,但不可靠。

8.如何保证信息的可靠性
最好的方法是给每个连接编上唯一号码id,然后根据id来取信息。先获取所有连接的id值,这通过很少的几次读取操作就能完成,然后根据id值取连接信息,例如每次取50个,直至读完,这样就能增加信息的可靠性。
经过几轮的循环,那些长连接的信息将能被可靠获取.




阅读(2714) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~