跨网段组播数据转发

来源:互联网 发布:查看linux系统内存大小 编辑:程序博客网 时间:2024/04/26 15:51

最近在实际的项目中遇到了组播通信,其中最主要的问题是组播如何跨网络路由的问题,起初在网络找资料,找到了PIMD来实现组播数包的转发。

借助pimd也能实现组包数据包的转发。但是,pimd是个应用程序,如果组播数据平凡的话,会影响到系统的效率。同时考虑到实际的项目中,组播数据源和组播的接受者是

在同一个局域网之内,只要交换机支持组播,通过交换机将组播的发送者和接受者连接起来,之后通过更改驱动程序直接实现数据包的转发,即eth0->eth1或者eth1->eth0,。eth0和eth1不在同一个网段。
数据交互框图如下:

单播数据处理如下:

B中的DSP只发送单播给A中的DSP,单播数据的转发可以根据iptable规则来实现。
A上面的单播数据转发配置如下:

WAN IP:10.10.104.221
LAN IP:192.168.119.7
DSP IP:192.168.119.3
iptables -t nat -A PREROUTING -d 10.10.104.221 -p udp --dport 5001 -j DNAT --to 192.168.119.3
iptable规则表示目前地址为:10.10.104.221 时,将此数据包的目的地址更改为:192.168.119.3。即数据转发给A中的DSP。

B上面的单播数据转发配置如下:

WAN IP:10.10.104.219LAN IP:192.168.197.1DSP IP:192.168.197.244iptables -t nat -A PREROUTING -d 192.168.197.1  -p udp --dport 5001 -j DNAT --to 10.10.104.221iptables -t nat -A POSTROUTING -o eth0 -s 192.168.197.244 -p udp --dport 5001  -j SNAT --to 10.10.104.219insmod snull.ko ifconfig virt_net0 upbrctl addif br0 virt_net0echo 192.168.197.1 > /proc/LanIpAddrcat /proc/LanIpAddr上面的命令中,俩条iptables命令意思是,第一条:当B中的DSP发送单播数据时如果目的地址为:192.168.197.1就将目的地址改为:10.10.104.221,即表示发送给:A的eth0接口。第二条:当从eth0出去的数据包如果源地址为:192.168.197.244(即DSP的ip地址),将源地址改为B的eth0的IP地址。即首先做DNAT转换,紧接着做SNAT转化。############################################################################

组播数据的处理如下:

组播数据:
数据流向是A中DSP是组播的数据源,B中的DSP是组播的接受者。A中的DSP和eth1是同一个网段,A中DSP的组播数据首先发送eth1,之后再转发到eth0,之后数据通过网络发送给B设备的eth0接口。同理当组播数据到达B设备的eth0接口之后,通过驱动程序将数据转发到eth1接口,eth1和DSP为通一个网段(192.168.100.xx)。


现在对上面的代码进行说明:
应该在linux ethernet驱动程序中,每一个ethN(eth0,eth1....)对应驱动中的一个mac_unit。对于eth0来时mac_unit-=0,对于eth1来说mac_unit=1.故可在驱动的接受函数中判断:一个特定的数据包是来自那个mac_unit或者在特定的mac_unit中处理特定的数据包。此处是:在mac_unit=0上面即eth0上面对特定的组播数据进行处理,首先判断:if((mac->mac_unit == 0)&&(0==memcmp(dest_mac,  MUTICAST_MAC, ETH_ALEN))&&(iph->daddr == *(unsigned int *)MUTICAST_DEST_IP))
即目的IP为:224.1.2.3 ,目的MAC地址为:0100 5e01 0203 。当收到的数据包满足此条件时可以知道此数据包为:组播数据。将此数据包的目的地址更改为:单播目的地址:
memcpy(ethh->h_dest,DSP_VX_MAC,  ETH_ALEN); /* 为:192.168.197.244 对于的MAC地址*/
iph->daddr     =   *(unsigned int *)DSP_VX_IP; /* 192.168.197.244 */

之后:
if(virt_dev != NULL))
{
        is_muticast_package_flag =0; 
         skb->dev =virt_dev;
         retskb =netif_receive_skb(skb);      
      
}
通过虚拟接口将skb的dev更改为:virt_dev。此后数据包就会通过协议栈进行处理。同时有下面的桥接。 
insmod snull.ko //为虚拟网卡,虚拟出来virt_net0设备。
ifconfig virt_net0 up
brctl addif br0 virt_net0

有了上面的处理,B设备中的DSP:192.168.197.244 就会收到一个组播数据(此时只是,目的地址为单播的目的地址,数据内容没有变化)

其代码类似如下:

#if DP_VERSION //DP
//* muticast IP */    //30:22:7B:CA:CC:DB
struct net_device* virt_dev;
EXPORT_SYMBOL(virt_dev);
#define LAN_DSP_UDP_PORT 6735
#define LAN_LOCAL_PORT  2849
static int muticast_dest_ipaddr = 0xE0010203;     /* 224.1.2.3  */ 
static int LAN_ipaddr = 0xC0A8C541;     /* 192.168.197.7 */
 static int DSP_VX_ipaddr = 0xC0A8C5F4;     /* 192.1689.197.244 */
 static int CP_ipaddr = 0x0;     /* 0.0.0.0 */
static unsigned char *LAN_IP = (unsigned char *)&LAN_ipaddr;/* 192.168.197.7 */
 static unsigned char *DSP_VX_IP = (unsigned char *)&DSP_VX_ipaddr;/* 192.1689.197.244 */
static unsigned char *CP_SRC_IP = (unsigned char *)&CP_ipaddr;/* CP端,及组播源的IP地址 */


static unsigned char *MUTICAST_DEST_IP = (unsigned char *)&muticast_dest_ipaddr; /* 224.1.2.3  */ 
static unsigned char  MUTICAST_MAC[ETH_ALEN] = {0x01,0x00,0x5e,0x01,0x02,0x03};        /*  0100 5e01 0203 */
static unsigned char LAN_MAC[ETH_ALEN] = {0x30,0x22,0x7B,0xCA,0xCC,0xDB };  /*HWaddr 00:27:1D:10:00:00 */
static unsigned char DSP_VX_MAC[ETH_ALEN] = {0xAA,0xBB,0xCC,0x01,0x19,0x1C }; /*aa:bb:cc:01:19:1c */
static unsigned char TEMP_MAC[ETH_ALEN] = {0x00,0x03,0x7F,0xFF,0xFF,0xFF };       /* 00:03:7F:FF:FF:FF */
 static unsigned char CP_SRC_MAC[ETH_ALEN] = {0xAA,0xBB,0xCC,0x01,0x19,0x1C }; /* CP端,及组播源的MAC地址 */
static int Lan_Ipaddr_read (char *page, char **start, off_t off,int count, int *eof, void *data)
{
count = sprintf(page, "%d.%d.%d.%d\n", \
(LAN_ipaddr>>24)&0x000000ff,(LAN_ipaddr>>16)&0x000000ff,\
(LAN_ipaddr>>8)&0x000000ff,(LAN_ipaddr)&0x000000ff);


count = sprintf(page, "%s%02x:%02x:%02x:%02x:%02x:%02x\n", page,\
LAN_MAC[0],LAN_MAC[1],LAN_MAC[2],LAN_MAC[3],LAN_MAC[4],LAN_MAC[5]);

*eof = 1; /* Indicate completion */
return count;
}
static int dp_muticastsrouce_Ipaddr_read (char *page, char **start, off_t off,int count, int *eof, void *data)
{
count = sprintf(page,"cp_wan_ip\ncp_wan_ip=%d.%d.%d.%d\n", \
(CP_ipaddr>>24)&0x000000ff,(CP_ipaddr>>16)&0x000000ff,\
(CP_ipaddr>>8)&0x000000ff,(CP_ipaddr)&0x000000ff);


count = sprintf(page, "%s%02x:%02x:%02x:%02x:%02x:%02x\n", page,\
CP_SRC_MAC[0],CP_SRC_MAC[1],CP_SRC_MAC[2],CP_SRC_MAC[3],CP_SRC_MAC[4],CP_SRC_MAC[5]);

*eof = 1; /* Indicate completion */
return count;
}


static int Lan_Ipaddr_write (struct file *file, const char *buf,unsigned long count, void *data)
{
char *end;
unsigned int u32temp,u32temp1;


u32temp = (int)simple_strtoul(buf,&end,10);
u32temp1 = (u32temp&0x000000ff) <<24;
if(*end!='.') return 0;
buf = end + 1;
u32temp = (int)simple_strtoul(buf,&end,10);
u32temp1 += (u32temp&0x000000ff) <<16;
if(*end!='.') return 0;
buf = end + 1;
u32temp = (int)simple_strtoul(buf,&end,10);
u32temp1 += (u32temp&0x000000ff) <<8;
if(*end!='.') return 0;
buf = end + 1;
u32temp = (int)simple_strtoul(buf,&end,10);
u32temp1 += (u32temp&0x000000ff);


LAN_ipaddr = u32temp1;
return count;
}


void init_dp_ip_addr()
{
static struct proc_dir_entry * dp_lan_proc_entry;
static struct proc_dir_entry * dpside_cp_ip_proc_entry;
mode_t mode =0444;
dp_lan_proc_entry = create_proc_entry("dp_lanIpAddr",mode, NULL);
dp_lan_proc_entry->read_proc = Lan_Ipaddr_read;
dp_lan_proc_entry->write_proc = Lan_Ipaddr_write;
dpside_cp_ip_proc_entry = create_proc_entry("cp_wan_ip",mode, NULL);
dpside_cp_ip_proc_entry->read_proc = dp_muticastsrouce_Ipaddr_read;
}
#endif

在函数int athr_gmac_hard_start(struct sk_buff *skb, struct net_device *dev)

{//中自动学习MAC地址
       #if DP_VERSION
       {
  /* 修改目的,源MAC地址*/
struct ethhdr *ethh;
struct iphdr *  iph;
unsigned char *dest_mac;
ethh =(struct ethhdr*)skb->data;
iph = (struct iphdr *)(skb->data + ETH_HLEN);   
 dest_mac = ethh->h_dest; 
if(mac->mac_unit == 1)
  {
   if((ethh->h_proto == htons(ETH_P_ARP))||(ethh->h_proto == htons(ETH_P_RARP)))
   {  
 //    printk("arp ,rap .....\n")
       if(0 == memcmp(skb->data + 28,LAN_IP, 4))
       {
           if(0 != memcmp(skb->data + 22,LAN_MAC, 6))
           {
               memcpy(LAN_MAC, skb->data + 22, ETH_ALEN);
               printk(" LAN_MAC MAC changed by ARP, the new MAC is: %02X:%02X:%02X:%02X:%02X:%02X\n", \
               LAN_MAC[0],LAN_MAC[1],LAN_MAC[2],LAN_MAC[3],LAN_MAC[4],LAN_MAC[5]);
         }        
      }
   }    
  }


#endif 

}

在函数有线口驱动接受函数

athr_receive_pkt()

{


#if DP_VERSION
       {
  /* 修改目的,源MAC地址*/
struct ethhdr *ethh;
struct iphdr *  iph;
struct udp_hdr *udph;
unsigned char *dest_mac,*src_mac;
ethh =(struct ethhdr*)skb->data;
iph = (struct iphdr *)(skb->data + ETH_HLEN);   
 dest_mac = ethh->h_dest;
 src_mac = ethh->h_source; 
 if(virt_dev != NULL)
{  
 if((mac->mac_unit == 0)&&(0==memcmp(dest_mac,  MUTICAST_MAC, ETH_ALEN))&&(iph->daddr == *(unsigned int *)MUTICAST_DEST_IP))
 {
    //printk("**********muticast data package**************************************************\n");
memcpy(CP_SRC_MAC,ethh->h_source,  ETH_ALEN);  
*(unsigned int *)CP_SRC_IP =iph->saddr;
memcpy(ethh->h_dest,DSP_VX_MAC,  ETH_ALEN);
iph->daddr     =   *(unsigned int *)DSP_VX_IP;
ip_send_check(iph); 
udph = (struct udp_hdr *)(skb->data + ETH_HLEN + 20);  
udph->check = 0;
is_muticast_package_flag =1;
 }  
}
if((mac->mac_unit == 1)&&(0==memcmp(src_mac,  DSP_VX_MAC, ETH_ALEN))&&(iph->saddr == *(unsigned int *)DSP_VX_IP))
{
    memcpy(ethh->h_dest,LAN_MAC,  ETH_ALEN);
    iph->daddr     =   *(unsigned int *)LAN_IP;
    ip_send_check(iph); 
udph = (struct udp_hdr *)(skb->data + ETH_HLEN + 20);   //udp 8 bytes
  udph->check = 0;
}  
}
#endif  
{
   #if DP_VERSION
 if((mac->mac_unit == 0)&&(is_muticast_package_flag ==1)&&(virt_dev != NULL))
 {
       // print_ip_buffer1(skb, (char *)"umtical", __LINE__);
       // printk("----------------------------------------------------------------------\n"); 
         is_muticast_package_flag =0; 
         skb->dev =virt_dev;
         retskb =netif_receive_skb(skb);             
}
else
{
retskb =netif_receive_skb(skb);
}
#endif  

}


------------------------------------------------------------------------

#if CP_7240_ON_OFF_VERSION2
      if((mac->mac_unit == 1)&&(0==memcmp(dest_mac,  MUTICAST_MAC, ETH_ALEN))&&(iph->daddr == *(unsigned int *)MUTICAST_DEST_IP))
//if((mac->mac_unit == 1)&&(is_multicast_ether_addr(dest_mac)))
{
//athr_gmacs[i]->mac_dev
   skb->dev =athr_gmacs[0]->mac_dev;
   printk("----------------------------------------------------------------------\n");

memcpy(ethh->h_source, WAN_MAC, ETH_ALEN); 
iph->saddr     =   *(unsigned int *)WAN_IP_ADDR;  
    ip_send_check(iph); 
    udph = (struct udp_hdr *)(skb->data + ETH_HLEN + 20);  
udph->check = 0; 
 if(athr_gmacs[0]->mac_ifup) //athr_gmac_hard_start(struct sk_buff *skb, struct net_device *dev)
  {
  athr_gmacs[0]->mac_dev->netdev_ops->ndo_start_xmit(skb, athr_gmacs[0]->mac_dev);
  } 
}
 else
 {         
  netif_receive_skb(skb); //这个地方注意。  
 }
#else
{
netif_receive_skb(skb); //这个地方注意。
}
#endif  

原创粉丝点击