linux协议栈bridgeWord下载.docx

上传人:b****4 文档编号:17879062 上传时间:2022-12-11 格式:DOCX 页数:14 大小:140.86KB
下载 相关 举报
linux协议栈bridgeWord下载.docx_第1页
第1页 / 共14页
linux协议栈bridgeWord下载.docx_第2页
第2页 / 共14页
linux协议栈bridgeWord下载.docx_第3页
第3页 / 共14页
linux协议栈bridgeWord下载.docx_第4页
第4页 / 共14页
linux协议栈bridgeWord下载.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

linux协议栈bridgeWord下载.docx

《linux协议栈bridgeWord下载.docx》由会员分享,可在线阅读,更多相关《linux协议栈bridgeWord下载.docx(14页珍藏版)》请在冰豆网上搜索。

linux协议栈bridgeWord下载.docx

pt_prev,&

ret,orig_dev))

  gotoout;

  }

  staticinlinestructsk_buff*handle_bridge(structsk_buff*skb,

  structpacket_type**pt_prev,int*ret,

  structnet_device*orig_dev)

  structnet_bridge_port*port;

  //对于回环设备以及skb->

dev->

br_port为空(即不被任何网桥所包含)的数据包直接返回

  if(skb->

pkt_type==PACKET_LOOPBACK||

  (port=rcu_dereference(skb->

br_port))==NULL)

  returnskb;

  if(*pt_prev){

  *ret=deliver_skb(skb,*pt_prev,orig_dev);

  *pt_prev=NULL;

  //网桥的基本挂接点处理函数

  returnbr_handle_frame_hook(port,skb);

  br_handle_frame_hook在网桥初始化模块br_init(void)函数中被赋值.

  br_handle_frame_hook=br_handle_frame;

  所以网桥对于数据包的处理过程是从br_handle_frame开始的。

 

  structsk_buff*br_handle_frame(structnet_bridge_port*p,structsk_buff*skb)

  constunsignedchar*dest=eth_hdr(skb)->

h_dest;

  int(*rhook)(structsk_buff*skb);

  //判断是否为有效的物理地址,非全0地址以及非广播地址

  if(!

is_valid_ether_addr(eth_hdr(skb)->

h_source))

  gotodrop;

  //判断skb包是否被共享skb->

users!

=1,若是,则复制一份,否则直接返回

  skb=skb_share_check(skb,GFP_ATOMIC);

skb)

  returnNULL;

  //这个函数并非像想象的那样,判断是否为本地地址

  //而是在判断是否为链路本地多播地址,01:

80:

c2:

00:

0x

  if(unlikely(is_link_local(dest))){

  /*Pauseframesshouldn'

tbepassedupbydriveranyway*/

protocol==htons(ETH_P_PAUSE))

  /*IfSTPisturnedoff,thenforward*/

  if(p->

br->

stp_enabled==BR_NO_STP&

&

dest[5]==0)

  gotoforward;

  if(NF_HOOK(PF_BRIDGE,NF_BR_LOCAL_IN,skb,skb->

dev,

  NULL,br_handle_local_finish))

/*frameconsumedbyfilter*/

  else

/*continueprocessing*/

  forward:

  switch(p->

state){

  caseBR_STATE_FORWARDING:

  //如果网桥处于forwarding状态,并且该报文必须要走L3层进行转发,则直接返回

  //br_should_route_hook钩子函数在ebtable里面设置为ebt_broute函数,它根据用户的规

  //决定该报文是否要通过L3层来转发;

一般rhook为空

  rhook=rcu_dereference(br_should_route_hook);

  if(rhook!

=NULL){

  if(rhook(skb))

  dest=eth_hdr(skb)->

  /*fallthrough*/

  caseBR_STATE_LEARNING:

  //如果数据包的目的mac地址为虚拟网桥设备的mac地址,则标记为host

compare_ether_addr(p->

dev_addr,dest))

  skb->

pkt_type=PACKET_HOST;

  //调用网桥在NF_BR_PREROUTING处挂载的钩子函数,因为网桥在其钩子函数过//程中嵌套调用了INET层BR_PREROUTING的钩子函数,过程有些曲折,故最后//再分析

  NF_HOOK(PF_BRIDGE,NF_BR_PRE_ROUTING,skb,skb->

dev,NULL,

  br_handle_frame_finish);

  break;

  default:

  drop:

  kfree_skb(skb);

  FORWARDING以及LEARNING为网桥的状态,网桥端口一般有5种状态:

  1) 

disable被管理员禁用

  2) 

blcok休息,不参与数据包转发

  3) 

listening监听

  4) 

learning学习ARP信息,准备向工作状态改变

  5) 

forwarding正常工作,转发数据包

  /*note:

alreadycalledwithrcu_read_lock(preempt_disabled)*/

  intbr_handle_frame_finish(structsk_buff*skb)

  structnet_bridge_port*p=rcu_dereference(skb->

br_port);

  structnet_bridge*br;

  structnet_bridge_fdb_entry*dst;

  structsk_buff*skb2;

  //判断网桥状态

p||p->

state==BR_STATE_DISABLED)

  /*insertintoforwardingdatabaseafterfilteringtoavoidspoofing*/

  //br为虚拟网桥结构

  br=p->

br;

  //根据数据包的源物理地址,更新网桥的转发表

  br_fdb_update(br,p,eth_hdr(skb)->

h_source);

state==BR_STATE_LEARNING)

  /*Thepacketskb2goestothelocalhost(NULLtoskip).*/

  //skb2数据包用于交付本机,skb数据包则用于forward

  skb2=NULL;

  //如果网口处于混杂模式,复制一份交付主机

  if(br->

flags&

IFF_PROMISC)

  skb2=skb;

  dst=NULL;

  //如果为广播数据包,增加计数,同样需要发一份给主机

  if(is_multicast_ether_addr(dest)){

  br->

stats.multicast++;

  /*根据网桥口以及目标地址判断是否为本机数据包*/

  elseif((dst=__br_fdb_get(br,dest))&

dst->

is_local){

  /*Donotforwardthepacketsinceit'

slocal.*/

  skb=NULL;

  if(skb2==skb)

  skb2=skb_clone(skb,GFP_ATOMIC);

  if(skb2)

  /*完成将数据包交付给本机的工作*/

  br_pass_frame_up(br,skb2);

  if(skb){

  if(dst)

  //如果存在目的地址则将其转发

  br_forward(dst->

dst,skb);

  //否则,flood数据包,向除接收网口外的其余网口发送该数据包

  br_flood_forward(br,skb);

  out:

  return0;

  //此函数主要实现通过网桥接收发往本机的数据包

  staticvoidbr_pass_frame_up(structnet_bridge*br,structsk_buff*skb)

  structnet_device*indev,*brdev=br->

dev;

  //完成数据包的统计计数

  brdev->

stats.rx_packets++;

stats.rx_bytes+=skb->

len;

  //将skb的dev改变为网桥结构的brdev

  //此时skb的dev选项由实际网络设备eth0等改变为虚拟网桥设备br0

  indev=skb->

dev=brdev;

  //重新走数据包接收流程,netif_receive_skb

  //但因为dev的改变,dev的br_port字段不再为空,不会重走网桥流程,直接交付

  NF_HOOK(PF_BRIDGE,NF_BR_LOCAL_IN,skb,indev,NULL,

  netif_receive_skb);

  下面看一下转发数据包的流程,对于flood_forward的流程,同样通过br_forward来实现,只不过改为循环遍历hash表中的设备,对于每一个设备都调用一次br_forward流程。

  /*calledwithrcu_read_lock*/

  voidbr_forward(conststructnet_bridge_port*to,structsk_buff*skb)

  /*如果skb->

dev不等于网桥的dev,同时网桥状态为forwarding,则进行转发*/

  if(should_deliver(to,skb)){

  __br_forward(to,skb);

  return;

  staticvoid__br_forward(conststructnet_bridge_port*to,structsk_buff*skb)

  structnet_device*indev;

  if(skb_warn_if_lro(skb)){

  //将skb的dev字段改为查找到的出口dev字段

dev=to->

  skb_forward_csum(skb);

  //遍历执行NF_BR_FORWARD钩子函数

  NF_HOOK(PF_BRIDGE,NF_BR_FORWARD,skb,indev,skb->

  br_forward_finish);

  intbr_forward_finish(structsk_buff*skb)

  //继续跑NF_BR_POST_ROUTING处的钩子函数

  returnNF_HOOK(PF_BRIDGE,NF_BR_POST_ROUTING,skb,NULL,skb->

  br_dev_queue_push_xmit);

  intbr_dev_queue_push_xmit(structsk_buff*skb)

  /*dropmtuoversizedpacketsexceptgso*/

  /*如果skb数据包的长度大于MTU值,则丢弃*/

  if(packet_length(skb)>

skb->

mtu&

!

skb_is_gso(skb))

  else{

  /*ip_refragcallsip_fragment,doesn'

tcopytheMACheader.*/

  if(nf_bridge_maybe_copy_header(skb))

  skb_push(skb,ETH_HLEN);

  //此时skb的dev已经替换成进行转发的dev了,dev_queue_xmit将使

  //用该网口设备的发送函数完成数据包的发送

  dev_queue_xmit(skb);

  发送过程:

  协议栈上层需要发送报文时,调用dev_queue_xmit(skb)函数。

如果这个报文需要通过网桥设备来发送,则skb->

dev指向一个网桥设备。

网桥设备没有使用发送队列(dev->

qdisc为空),所以dev_queue_xmit将直接调用dev->

hard_start_xmit函数,而网桥设备的hard_start_xmit等于函数br_dev_xmit;

  /*netdevicetransmitalwayscalledwithnoBH(preempt_disabled)*/

  /*br_dev_xmit为网桥设备的数据包发送函数*/

  intbr_dev_xmit(structsk_buff*skb,structnet_device*dev)

  structnet_bridge*br=netdev_priv(dev);

  constunsignedchar*dest=skb->

data;

  dev->

stats.tx_packets++;

stats.tx_bytes+=skb->

  skb_reset_mac_header(skb);

  skb_pull(skb,ETH_HLEN);

  /*如果为广播地址,则flood该数据包

  *如果能够根据skb中的目的mac地址查找到对应的网口,则通过br_deliver发送该数据包

  *如果查找不到,同样flood该数据包

  */

  if(dest[0]&

1)

  br_flood_deliver(br,skb);

  elseif((dst=__br_fdb_get(br,dest))!

=NULL)

  br_deliver(dst->

  br_flood_deliver函数的实现过程,同样是遍历hash表,对于每一个网口设备都调用一次__br_deliver,所以下面就主要看一下br_deliver函数的流程

  voidbr_deliver(conststructnet_bridge_port*to,structsk_buff*skb)

  __br_deliver(to,skb);

  staticvoid__br_deliver(conststructnet_bridge_port*to,structsk_buff*skb)

  /*将skb中的dev改成出口设备所对应的dev*/

  NF_HOOK(PF_BRIDGE,NF_BR_LOCAL_OUT,skb,NULL,skb->

  /*最终仍然通过br_dev_queue_push_xmit完成数据包的发送过程*/

  至此,整个网桥中数据的处理流程已经完全结束了。

  Netfilter:

  对于网桥中的netfilter的钩子函数的调度过程有些曲折,对于INET层的钩子函数全部被嵌套进BRIDGE层钩子函数的运行流程中。

  下面首先来看一下网桥一共挂载了哪些钩子函数

  staticstructnf_hook_opsbr_nf_ops[]__read_mostly={

  {.hook=br_nf_pre_routing,

  .owner=THIS_MODULE,

  .pf=PF_BRIDGE,

  .hooknum=NF_BR_PRE_ROUTING,

  .priority=NF_BR_PRI_BRNF,},

  {.hook=br_nf_local_in,

  .hooknum=NF_BR_LOCAL_IN,

  {.hook=br_nf_forward_ip,

  .hooknum=NF_BR_FORWARD,

  .priority=NF_BR_PRI_BRNF-1,},

  {.hook=br_nf_forward_arp,

  {.hook=br_nf_local_out,

  .hooknum=NF_BR_LOCAL_OUT,

  .priority=NF_BR_PRI_FIRST,},

  {.hook=br_nf_post_routing,

  .hooknum=NF_BR_POST_ROUTING,

  .priority=NF_BR_PRI_LAST,},

  //以上为BRIDGE层挂载的钩子函数,一下为INET层挂载的钩子函数

  {.hook=ip_sabotage_in,

  .pf=PF_INET,

  .hooknum=NF_INET_PRE_ROUTING,

  .priority=NF_IP_PRI_FIRST,},

  .pf=PF_INET6,

  .hooknum=NF_INE

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 育儿理论经验

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1