Linux内核分析 - 网络[六]:网桥
如果端口state= BR_STATE_LEARNING,如果是发往本机的报文,则设置pkt_type为PACKET_HOST,然后执行 br_handle_frame_finish来完成报文的进一步处理。要注意的是,这里将报文发往本机的报文设为PACKET_HOST,实现了经过网 桥处理后,再次进入netif_receive_skb()时,不会再被网桥处理(结果进入网桥的条件理解): if (! compare_ether_addr(p->br->dev->dev_addr, dest)) skb->pkt_type = PACKET_HOST; NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, br_handle_frame_finish); 除此之外,端口处于不可用状态,此时丢弃掉报文: kfree_skb(skb); 下 面来详细看下br_handle_frame_finish()函数。 首先还是会根据收到报文的源mac和端口更新CAM表,这是交换机区别于hub的 重要特征: br_fdb_update(br, p, eth_hdr(skb)->h_source); 然后如果端口处于LEARNING状态,则只是学习 到CAM表中,而不对报文作任何处理,所以丢弃掉报文: if (p->state == BR_STATE_LEARNING) goto drop; 否则端口已处于FORWARDING状态,此时分情况: 1. 如果报文是多播的,则br_flood_forward(br, skb, skb2); 2. 如果报文是单播的,但不在网桥的CAM表中,则br_flood_forward(br, skb, skb2); 3. 如果报文是单播的 ,在网桥的CAM表中,但不是发往本机,则br_forward(dst->dst, skb, skb2); 4. 如果报文是单播的,在网桥的CAM表中 ,且是发往本机,则br_pass_frame_upbr_pass_frame_up(skb2); br_handle_frame_finish()处理完后,顺着最后一种情 况继续往下走,br_pass_frame_up()。 该函数比较简单,我们知道,在底层报文的向上传递就是通过设备的更换来进行的(参 考802.1q),这里将skb的设备换成网桥设备,使上层协议不知道报文来自网卡,而是认为报文来自于网桥;然后调用 netif_receive_skb()再次进入接收栈: skb->dev = brdev; return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, netif_receive_skb); 经过网桥处理后,再次进入netif_receive_skb()->handle_bridge(),此时skb- >dev已经不是网卡设备了,而是网桥设备,注意到在向网桥添加端口时,是相应网卡dev->br_port赋值为创建的端口,网 桥设备是没有的,因此其br_port为空,在这一句会直接返回,进入正常的协议栈流程: if (skb->pkt_type == PACKET_LOOPBACK || (port = rcu_dereference(skb->dev->br_port)) == NULL) return skb; 当发送数据报文时,会调用br_dev_xmit()[netbridgebr_device.c],大致会根据目的地址调用 br_multicast_deliver()或br_flood_deliver()或br_deliver(),在其过程中会将skb->dev由原来的网桥设备brdev换面网卡 设备dev,然后通过网卡变更向下传递报文; 内核协议栈中,发送与接收是分离的,接收像是报文脱壳的过程,发送则是函数的嵌套调用。有关发送的流程,稍 后专门详述。 (编辑:源码网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |