Linux-4.20.8内核桥收包源码解析(五)----------桥处理流程br_handle_frame

2024-01-23 20:58

本文主要是介绍Linux-4.20.8内核桥收包源码解析(五)----------桥处理流程br_handle_frame,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:lwyang?
内核版本:Linux-4.20.8

网桥是一种2层网络互连设备,而不是一种网络协议。它在协议结构上并没有占有一席之地,因此不能通过向协议栈注册协议的方式来申请网桥数据包的处理。相反,网桥接口的数据包和一般接口(如eth0)在格式上完全是一样的,不同之处是网桥在2层上就对它进行了转了,而一般接口要在3层 才能根据路由信息来决定是否要转发,如何转发。

linux内核是通过一个虚拟的网桥设备来实现桥接的。这个虚拟设备可以绑定若干个以太网接口设备,从而将它们桥接起来。如下图(摘自ULNI):
在这里插入图片描述
网桥设备br0绑定了eth0eth1。对于网络协议栈的上层来说,只看得到br0,因为桥接是在数据链路层实现的,上层不需要关心桥接的细节。于是协议栈上层需要发送的报文被送到br0,网桥设备的处理代码再来判断报文该被转发到eth0或是eth1,或者两者皆是;反过来,从eth0或从eth1接收到的报文被提交给网桥的处理代码,在这里会判断报文该转发、丢弃、或提交到协议栈上层

linux内核支持网口的桥接(目前只支持以太网接口)。但是与单纯的交换机不同,交换机只是一个二层设备,对于接收到的报文,要么转发、要么丢弃。小型的交换机里面只需要一块交换芯片即可,并不需要CPU。而运行着linux内核的机器本身就是一台主机,有可能就是网络报文的目的地。其收到的报文除了转发和丢弃,还可能被送到网络协议栈的上层(网络层),从而被自己消化

rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
{struct net_bridge_port *p;struct sk_buff *skb = *pskb;//获取数据包的目的mac地址const unsigned char *dest = eth_hdr(skb)->h_dest;//开启ebtables时br_should_route_hook_t *rhook;//如果是本地环回包则跳过桥处理,直接返回if (unlikely(skb->pkt_type == PACKET_LOOPBACK))return RX_HANDLER_PASS;//源mac地址无效则丢弃if (!is_valid_ether_addr(eth_hdr(skb)->h_source))goto drop;//判断skb是否共享(skb->users!=1 ?),如果是共享则克隆一份,并将原skb的引用计数-1(skb->users-1)//如果不克隆则会影响共享此skb的其他函数,如果此skb为不共享,则直接返回此skbskb = skb_share_check(skb, GFP_ATOMIC);if (!skb)return RX_HANDLER_CONSUMED;//获取net_bridge_port网桥接口(dev->rx_handler_data),在br_add_if中赋值的,见上节桥处理函数的注册p = br_port_get_rcu(skb->dev);if (p->flags & BR_VLAN_TUNNEL) {if (br_handle_ingress_vlan_tunnel(skb, p,nbp_vlan_group_rcu(p)))goto drop;}//如果目的mac地址是本地链路地址link local reserved addr (01:80:c2:00:00:0X) STP报文if (unlikely(is_link_local_ether_addr(dest))) {u16 fwd_mask = p->br->group_fwd_mask_required;/** See IEEE 802.1D Table 7-10 Reserved addresses** Assignment		 		Value* Bridge Group Address		01-80-C2-00-00-00* (MAC Control) 802.3		01-80-C2-00-00-01* (Link Aggregation) 802.3	01-80-C2-00-00-02* 802.1X PAE address		01-80-C2-00-00-03** 802.1AB LLDP 		01-80-C2-00-00-0E** Others reserved for future standardization*/fwd_mask |= p->group_fwd_mask;switch (dest[5]) {case 0x00:	/* Bridge Group Address *//* If STP is turned off,then must forward to keep loop detection */if (p->br->stp_enabled == BR_NO_STP ||fwd_mask & (1u << dest[5]))goto forward;*pskb = skb;__br_handle_local_finish(skb);return RX_HANDLER_PASS;case 0x01:	/* IEEE MAC (Pause) */goto drop;case 0x0E:	/* 802.1AB LLDP */fwd_mask |= p->br->group_fwd_mask;if (fwd_mask & (1u << dest[5]))goto forward;*pskb = skb;__br_handle_local_finish(skb);return RX_HANDLER_PASS;default:/* Allow selective forwarding for most other protocols */fwd_mask |= p->br->group_fwd_mask;if (fwd_mask & (1u << dest[5]))goto forward;}/* Deliver packet to local host only */NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, dev_net(skb->dev),NULL, skb, skb->dev, NULL, br_handle_local_finish);return RX_HANDLER_CONSUMED;}//p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD
forward://STP的五种状态switch (p->state) {//网桥端口处于转发状态case BR_STATE_FORWARDING://ebtables获取路由的hook点rhook = rcu_dereference(br_should_route_hook);if (rhook) {//转发数据包,然后返回if ((*rhook)(skb)) {*pskb = skb;return RX_HANDLER_PASS;}dest = eth_hdr(skb)->h_dest;}/* fall through *///网桥端口处于学习状态,处于BR_STATE_FORWARDING 状态也会执行下面的代码,因为上面的case没有breakcase BR_STATE_LEARNING://数据包目的mac地址等于网桥的mac地址,属于发往本地的数据包if (ether_addr_equal(p->br->dev->dev_addr, dest))skb->pkt_type = PACKET_HOST;//进入NF_BR_PRE_ROUTING钩子点,最后调用br_handle_frame_finish函数NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,dev_net(skb->dev), NULL, skb, skb->dev, NULL,br_handle_frame_finish);break;default:
drop:kfree_skb(skb);}//最后返回RX_HANDLER_CONSUMED 表明我们在桥上已经处理了此数据包,原__netif_receive_skb_core应当直接返回return RX_HANDLER_CONSUMED;
}

br_handle_frame函数中,主要就是将数据包放入NF_BR_PRE_ROUTING 钩子点,如有特殊的报文STP报文会直接放入NF_BR_LOCAL_IN交给上层处理

那么接下来数据包会进入NF_BR_PRE_ROUTING链进行处理,若我们在NF_BR_PRE_ROUTING链注册了自己的hook函数,则会根据按优先级处理我们的hook函数,若注册的hook函数返回值都为NF_ACCEPT,然后最后会调用br_handle_frame_finish决定数据包是转发还是发往本地

这篇关于Linux-4.20.8内核桥收包源码解析(五)----------桥处理流程br_handle_frame的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/637502

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal