我的负载均衡模块:simpLB

本文介绍了一个名为simpLB的简单负载均衡模块,该模块能够实现基本的负载均衡功能,支持ICMP、UDP及特定条件下HTTP协议的数据包调度,并提供源地址和目的地址转换功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2010年03月01日 星期一 13时30分44秒
捣鼓了好几天,终于做出了一个负载均衡模块的雏形:simpLB。具体功能就是把发送到LoadBalaner上数据包“无条件”调度到Server_1上。
目前经测试,可以支持ICMP(ping)、UDP,但是如果是TCP包,当前只支持80端口的应用(Http)。
下面要作的是
 把所用到ip_vs.h中的两个函数自定义一下,以“解耦合”;
 支持TCP协议的全部端口; 
 进一步完善对UDP协议的支持;
 进行连接跟踪;
 并加入一个简单的调度算法,使其不再“无条件”;
 再逐步完善调度算法... ...

贴上代码。
1、simpLB.c
#include <linux/kernel.h>
#include <linux/tcp.h>                  /* for tcphdr */
#include <net/ip.h>
#include <net/tcp.h>                    /* for csum_tcpudp_magic */
#include <net/udp.h>
#include <net/icmp.h>                   /* for icmp_send */
#include <net/route.h>                  /* for ip_route_output */
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <linux/icmpv6.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <net/ip_vs.h>     /*for ip_vs_check_diff ip_vs_check_diff4*/
#include "tools.h"

MODULE_LICENSE("GPL");
/* This is the structure we shall use to register our function */
/* IP address we want to Nat*/
static unsigned char *vmLB_ip = "/xc0/xa8/x7a/x01";   /* 192.168.122.1*/
static unsigned char *vm01_ip = "/xc0/xa8/x63/x65";   /* 192.168.99.101 */
//static unsigned char *vm02_ip = "/xc0/xa8/x63/x66";   /* 192.168.99.102 */


/* This is the hook function itself */
unsigned int sahu_pre_routing(unsigned int hooknum,
                           struct sk_buff *skb,
                           const struct net_device *in,
                           const struct net_device *out,
                           int (*okfn)(struct sk_buff *))
{
  char daddr_str[16];
  struct sk_buff *sb = skb;
  struct iphdr *iph;
  struct tcphdr *tcph;
  unsigned int tcphoff;
  int oldlen;

  if(!sb) return NF_ACCEPT;
  iph = ip_hdr(sb);
  if(!iph) return NF_ACCEPT;

  if (iph->daddr == *(unsigned int *)vmLB_ip){
   if(iph->protocol == IPPROTO_TCP){
   tcphoff = ip_hdrlen(skb);
   oldlen = skb->len - tcphoff; 
   tcph = (void *)skb_network_header(skb) + tcphoff;
  // tcph->dest = 80;
   tcph->check=
    csum_fold(ip_vs_check_diff4(*(unsigned int *)vmLB_ip, *(unsigned int *)vm01_ip,
      ip_vs_check_diff2(80, 80,
       ~csum_unfold(tcph->check))));
   if(skb->ip_summed==CHECKSUM_COMPLETE)
    skb->ip_summed=CHECKSUM_NONE;
  }

    iph->daddr= *(unsigned int *)vm01_ip;
    ip_send_check(iph);
  //  skb->local_df = 1;

    printk("DNat: %d.%d.%d.%d To:%d.%d.%d.%d/n",
                *vmLB_ip, *(vmLB_ip + 1), *(vmLB_ip + 2),*(vmLB_ip + 3),
                *vm01_ip, *(vm01_ip + 1), *(vm01_ip + 2),*(vm01_ip + 3));
    return NF_ACCEPT;
  }else{
    inet_i2str(iph->daddr,daddr_str);
    printk("No DNat for %s/n",daddr_str);
    return NF_ACCEPT;
  }
}
unsigned int sahu_post_routing(unsigned int hooknum,
                           struct sk_buff *skb,
                           const struct net_device *in,
                           const struct net_device *out,
                           int (*okfn)(struct sk_buff *))
{
  char saddr_str[16];
  struct sk_buff *sb = skb;
  struct iphdr *iph;
  struct tcphdr *tcph;
  unsigned int tcphoff;
  int oldlen;

  if(!sb) return NF_ACCEPT;
  iph = ip_hdr(sb);
  if(!iph) return NF_ACCEPT;

  if (iph->saddr == *(unsigned int *)vm01_ip){
   if(iph->protocol == IPPROTO_TCP){
   tcphoff = ip_hdrlen(skb);
   oldlen = skb->len - tcphoff; 
   tcph = (void *)skb_network_header(skb) + tcphoff;
  // tcph->source = 80;
   tcph->check=
    csum_fold(ip_vs_check_diff4(*(unsigned int *)vm01_ip, *(unsigned int *)vmLB_ip,
      ip_vs_check_diff2(80, 80,
       ~csum_unfold(tcph->check))));
   if(skb->ip_summed==CHECKSUM_COMPLETE)
    skb->ip_summed=CHECKSUM_NONE;
  }
    iph->saddr= *(unsigned int *)vmLB_ip;
    ip_send_check(iph);
//    skb->local_df = 1;

    printk("SNat: %d.%d.%d.%d To:%d.%d.%d.%d/n",
                *vm01_ip, *(vm01_ip + 1), *(vm01_ip + 2),*(vm01_ip + 3),
                *vmLB_ip, *(vmLB_ip + 1), *(vmLB_ip + 2),*(vmLB_ip + 3));
    return NF_ACCEPT;
  }else{
    inet_i2str(iph->saddr,saddr_str);
    printk("No SNat for %s/n",saddr_str);
    return NF_ACCEPT;
  }
}
/* netfilter hooks in this kernel module*/
static struct nf_hook_ops sahu_ops[] __read_mostly = {

  {
    .hook = sahu_pre_routing,
    .owner = THIS_MODULE,
    .pf = PF_INET,
    .hooknum = NF_INET_PRE_ROUTING,
    .priority = 100,
  },

  {
    .hook = sahu_post_routing,
    .owner = THIS_MODULE,
    .pf = PF_INET,
    .hooknum = NF_INET_POST_ROUTING,
    .priority = 100,
  }

};
/* Initialisation routine */
int init_module()
{
  int ret;
  ret = nf_register_hooks(sahu_ops,ARRAY_SIZE(sahu_ops));
  if(ret<0){
    pr_info("can't install simpLB into kernel!/n");
  }else{
    pr_info("simpLB install into kernel!/n");
  }
  return 0;
}
/* Cleanup routine */
void cleanup_module()
{
  nf_unregister_hooks(sahu_ops,ARRAY_SIZE(sahu_ops));
  pr_info("simpLB removed from kernel!/n");
}

2、tools.h
//extern static char * inet_i2str(__be32 addr);
int inet_i2str(unsigned int addr,char *addr_str){
  unsigned char *p;
  int i;
  p=(unsigned char *)(&addr);
  for(i=0;i<4;i++){
     addr_str[i*4+0]=*(p+i)/100+'0';
     addr_str[i*4+1]=*(p+i)/10-(*(p+i)/100)*10+'0';
     addr_str[i*4+2]=*(p+i)%10+'0';
     addr_str[i*4+3]='.';
  }
  addr_str[15]='/0';
  return 0;
}

3、Makefile
obj-m +=simpLB.o
all:
 make -C /lib/modules/`uname -r`/build M=`pwd`
clean:
 make -C /lib/modules/`uname -r`/build M=`pwd` clean
install:
 /sbin/insmod simpLB.ko
remove:
 /sbin/rmmod simpLB
4、测试
4.1、测试环境
网络拓扑:
Clinet(192.168.122.101)<---->LoadBalancer(192.168.122.1--192.168.99.1)<---->Server_1(192.168.99.101)
LoadBalancer是192.168.122.0和192.168.99.0两个网络的网关。运行:
 echo 1 > /proc/sys/net/ipv4/ip_forward
打开网关的转发功能。
4.2、于LoadBalancer上:
编译(make)、安装(make install)simpLB内核模块,以启动简单的负载均衡。
运行:service apache2 start,以启动web服务器。
运行:vim /srv/www/htdocs/index.html,编辑主页内容为“It works!@vmLB”。
4.3、于Server_1上:
编译(make)、安装(make install)netMonitor内核模块,以监视Server_1上的各个hook点上的网络数据包。
运行:service apache2 start,以启动web服务器。
运行:vim /srv/www/htdocs/index.html,编辑主页内容为“It works!@vm01”。
4.4、于Client上:
运行:lyxn -dump 192.168.122.1
得到结果为:“It works!@vm01”而不是“It works!@vmLB”。
如果关心细节可以于LoadBalancer和Server_1上运行:dmesg | tail,查看。或是用WireShark进行查看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值