现在的位置: 首页 > 综合 > 正文

我的负载均衡模块:simpLB_2_6

2013年09月28日 ⁄ 综合 ⁄ 共 7233字 ⁄ 字号 评论关闭

2010年03月01日 星期一 19时57分02秒
在simpLB的基础上已加入了简单的轮询调度算法,因没有加入连接跟踪机制,目前只能用ping命令测试。
1、simpLB.c
/*简单的轮询调度算法,因没有连接跟踪,目前只能用ping测试*/
#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 "tools.h"
#define VPORT_TCP 80
#define DPORT_TCP 80
#define VPORT_UDP 4950
#define DPORT_UDP 4950

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 */
static unsigned char *srv_list[2];
static int sahu_id = 0;

/* 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 *))
{
 unsigned char *srv_addr;
  char daddr_str[16];
  struct sk_buff *sb = skb;
  struct iphdr *iph;

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

  if (iph->daddr == *(unsigned int *)vmLB_ip){
  srv_addr = srv_list[(sahu_id++)%2];
   if(iph->protocol == IPPROTO_TCP){
   tcp_dnat_base(skb,*(__be32 *)vmLB_ip,*(__be32 *)srv_addr,htons(VPORT_TCP),htons(DPORT_TCP));
  }else if(iph->protocol == IPPROTO_UDP){
   udp_dnat_base(skb,*(__be32 *)vmLB_ip,*(__be32 *)srv_addr,htons(VPORT_UDP),htons(DPORT_UDP));
  }else{
  }

    iph->daddr= *(unsigned int *)srv_addr;
    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),
                *srv_addr, *(srv_addr + 1), *(srv_addr + 2),*(srv_addr + 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 *))
{
 unsigned char *srv_addr;
  char saddr_str[16];
  struct sk_buff *sb = skb;
  struct iphdr *iph;

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

 srv_addr = srv_list[(sahu_id+1)%2];
  if (iph->saddr == *(unsigned int *)srv_addr){
   if(iph->protocol == IPPROTO_TCP){
   tcp_snat_base(skb,*(__be32 *)vmLB_ip,*(__be32 *)srv_addr,htons(VPORT_TCP),htons(DPORT_TCP));
  }else if(iph->protocol == IPPROTO_UDP){
   udp_snat_base(skb,*(__be32 *)vmLB_ip,*(__be32 *)srv_addr,htons(VPORT_UDP),htons(DPORT_UDP));
  }else{
  }
    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",
                *srv_addr, *(srv_addr + 1), *(srv_addr + 2),*(srv_addr + 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");
  }
 srv_list[0] = vm01_ip;
 srv_list[1] = vm02_ip;
  return 0;
}
/* Cleanup routine */
void cleanup_module()
{
  nf_unregister_hooks(sahu_ops,ARRAY_SIZE(sahu_ops));
  pr_info("simpLB removed from kernel!/n");
}

2、tool.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;
}
static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum)
{
 __be32 diff[2] = { ~old, new };

 return csum_partial(diff, sizeof(diff), oldsum);
}
static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
{
 __be16 diff[2] = { ~old, new };

 return csum_partial(diff, sizeof(diff), oldsum);
}
static int tcp_snat_base(struct sk_buff *skb,__be32 vaddr,__be32 daddr,__be16 vport,__be16 dport){
 
  struct tcphdr *tcph;
  unsigned int tcphoff;
  int oldlen;

 tcphoff = ip_hdrlen(skb);
 oldlen = skb->len - tcphoff; 
 tcph = (void *)skb_network_header(skb) + tcphoff;
 
 tcph->source = vport;
 tcph->check=
  csum_fold(ip_vs_check_diff4(daddr,vaddr,
   ip_vs_check_diff2(dport,vport,
    ~csum_unfold(tcph->check))));
 if(skb->ip_summed==CHECKSUM_COMPLETE)
  skb->ip_summed=CHECKSUM_NONE;
 return 0;
}
static int tcp_dnat_base(struct sk_buff *skb,__be32 vaddr,__be32 daddr,__be16 vport,__be16 dport){
 
  struct tcphdr *tcph;
  unsigned int tcphoff;
  int oldlen;

 tcphoff = ip_hdrlen(skb);
 oldlen = skb->len - tcphoff; 
 tcph = (void *)skb_network_header(skb) + tcphoff;
 
 tcph->dest = dport;
 tcph->check=
  csum_fold(ip_vs_check_diff4(vaddr,daddr,
   ip_vs_check_diff2(vport,dport,
    ~csum_unfold(tcph->check))));
 if(skb->ip_summed==CHECKSUM_COMPLETE)
  skb->ip_summed=CHECKSUM_NONE;
 return 0;
}
static int udp_snat_base(struct sk_buff *skb,__be32 vaddr,__be32 daddr,__be16 vport,__be16 dport){
 
  struct udphdr *udph;
  unsigned int udphoff;
  int oldlen;

 udphoff = ip_hdrlen(skb);
 oldlen = skb->len - udphoff; 
 udph = (void *)skb_network_header(skb) + udphoff;
 
 udph->source = vport;
 udph->check=
  csum_fold(ip_vs_check_diff4(daddr,vaddr,
   ip_vs_check_diff2(dport,vport,
    ~csum_unfold(udph->check))));
 if(!udph->check){
  udph->check = CSUM_MANGLED_0;
 }
 if(skb->ip_summed==CHECKSUM_COMPLETE)
  skb->ip_summed=CHECKSUM_NONE;
 return 0;
}
static int udp_dnat_base(struct sk_buff *skb,__be32 vaddr,__be32 daddr,__be16 vport,__be16 dport){
 
  struct udphdr *udph;
  unsigned int udphoff;
  int oldlen;

 udphoff = ip_hdrlen(skb);
 oldlen = skb->len - udphoff; 
 udph = (void *)skb_network_header(skb) + udphoff;
 
 udph->dest = dport;
 udph->check=
  csum_fold(ip_vs_check_diff4(vaddr,daddr,
   ip_vs_check_diff2(vport,dport,
    ~csum_unfold(udph->check))));
 if(!udph->check){
  udph->check = CSUM_MANGLED_0;
 }
 if(skb->ip_summed==CHECKSUM_COMPLETE)
  skb->ip_summed=CHECKSUM_NONE;
 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、测试
测试环境和前一个版本的simpLB模块相同,只是多加了一个Server_2(192.168.99.102)。
4.1、于LoadBalaner上:
编译(make)、安装(make install)simpLB模块。
4.2、于Server_1和Server_2上:
安装netMonitor模块。
4.3、于Client上:
运行:ping 192.168.122.1 -c 4
得到如下字样:
PING vmLB (192.168.122.1) 56(84) bytes of data.
64 bytes from vmLB (192.168.122.1): icmp_seq=1 ttl=63 time=0.238 ms
64 bytes from vmLB (192.168.122.1): icmp_seq=2 ttl=63 time=0.229 ms
64 bytes from vmLB (192.168.122.1): icmp_seq=3 ttl=63 time=0.238 ms
64 bytes from vmLB (192.168.122.1): icmp_seq=4 ttl=63 time=0.283 ms

再分别在LoadBalancer、Server_1和Server_2上 运行dmesg | tail。可以发现,LoadBalaner将4个ping包轮询转发个Server_1和Server_2。

 

抱歉!评论已关闭.