当前位置:首页 > 嵌入式 > 嵌入式硬件
[导读]PPPoE(Point.to.Point Protoeol over Ethernet)是将PPP协议封装在以太网帧上进行传输,它的通信过程分为探测(Discovery)和PPP会话(Session)2个阶段。PPPoE Discovery阶段

PPPoE(Point.to.Point Protoeol over Ethernet)是将PPP协议封装在以太网帧上进行传输,它的通信过程分为探测(Discovery)和PPP会话(Session)2个阶段。PPPoE Discovery阶段主要是客户机确定AC(Access Concentrator)以及客户机与AC协商Session ID。而PPPoE Sess-ion用于完成数据包的接收与发送,同时它也用于完成PPP链路的协商(LCP),以及网络层的控制协商(IPCP)等。

传统的PPPoE先会用Raw socket读取数据,然后采用用户态程序对其封包解包,然后再发送给内核。但是这种方法会引起大量的内核空间与用户空间的上下文切换,从而带来不必要的开销。而对于实现于内核态的PPPoE,它会把所有的封包以及解包实现于内核,这样就大大提高PPPoE的效率。

1 PPPoE协议概述

1. 1 PPPoE Discovery阶段

在PPPoE Discovery阶段,客户机首先广播一个PADI(0x09)帧。收到PADI帧的一个或多个服务器会发送PADO(0x07)帧,这个包中包含了服务器的各种标识。然后,客户机会选择其中一个服务器发送PADR(0x19),表明主机选择了这个服务器。最终,收到PADR(0x65)帧的服务器会为新的会话分配资源并向客户机发送PADS(0x65)。当此阶段完成,这两次的对话完成了SESSION_ID以及双方物理地址,为后续数据会话打好基础。

同时PPP协议还提供了一个PADT请求,该请求用于结束这次PPPoE会话。这个请求可以由任何一方发出,同时代表这次回话的结束,图1描述整个discovery过程。

 

1.2 PPPoE Session阶段

PPPoE Discovery阶段是为整个PPPoE会话获取双方物理地址以及Session_ID,这个Session_ID就成为了双方的通信凭证,在整个会话过程中保持不变。PPP帧数据被封在以太帧中,它在以太帧的标识为0x8864,当碰到0x8864时,就认为是一个PPPoE包。

在PPPoE Session阶段,PPPoE除数据传输以外,还提供了链路的协商(LCP),以及网络层的控制协商(IPCP)等其他服务。对于LCP,它主要用于配置和测试数据通信链路,用来协商PPP协议的一些配置参数选项;处理不同大小的数据帧:检测链路环路和一些链路的错误;终止一条链路,其作用类似于IP层的ICMP协议。而对于IPCP,它主要用于动态地协商客户机与服务器双方IP,实际的数据报文交换过程中主要涉及Config-Request、 Config-Ack、Config-Nak和Config-Re-ject。图2描述IPCP协商IP的过程。

 

2 PPPOE设计实现

从上述PPPoE协议描述中,了解到整个PPPoE会话包括Discovery、链路协商和数据传输3种交互。这3种数据中,数据传输最重要,数据量最大。对于用户空间模式的PPPoE,数据包收发需要通过pty,由用户空间的PPPoE进程处理PPPoE包头后通过Raw socket收发。也就是说所有的PPPoE数据封包结果都在用户空间执行,这样就大大增加了内核空间与用户空间数据切换的次数。为了减少这种开销。这里采用一个内核模块来处理数据的封包解包,这样就大大减少了内核空间与用户空间数据切换的次数,提高效率。所以对内核空间模式的PPPoE的处理策略是:Discovery以及链路协商交互全部在用户空间完成,而数据的封解包则通过一个内核模块在内核空间完成。

2.1 PPPoE会话初始化

PPPoE的初始化包括整个Discovery阶段以及Session阶段的IPCP和LCP等其他链路协商过程,所有的工作都在用户空间完成,图3描述了整个初始化的流程。

 

首先通过Raw socket发送PADS、PADR、PADO、PADI,当这个请求完成后,得到远端服务器的MAC地址以及双方建立起来的Session_ID。由于后面的内核封包需要用到这些数据,所以需要将这些数据切换到内核空间去。由于数据量较小,则采用proc文件系统完成内核空间与用户空间的数据切换。

对于proc中的数据,设计以下数据格式:接口名词SMAC DMAC SESSION_ID RX TX。

其中“接口名词”为接口名称,设计中不再用虚拟PPP接口传输数据,而是将数据迁移到物理网卡上,这样在某种程度上减轻了路由模块的负担,但需要去proc文件读取接口名称以此判断该物理接口是否启用PPPoE拨号。“SMAC”和“DMAC”参数为双方的MAC地址,在内核封包中用到。 “SESSION_ID”双方建立起来的Session_ID,也用于内核封包。而“RX”和“TX”是用于记录最后一次解包与封包的时间点,该数据用于按需拨号。

在建立好PPP连接后就进行IPCP协商,这个过程将为协商到双方的IP的地址,并将这个IP地址配置到物理口上,而这些数据将通过PPP口通信。除此之外,还需要为PPPoE链路配置相应的路由、更新ARP列表以及获取相应的DNS服务器地址。

2.2 PPPoE数据接收

PPPoE数据接收主要是对数据进行解包,其全部动作在内核空间完成。当一个PPPoE数据包从网卡驱动里面读出来时,是一个完整的PPPoE 包。而上层模块无法识别这样的包,所以需要将中间的那些PPP协议数据从包中剥离出来,使其变成一个普通的IP数据包,图4描述了PPPoE接收数据的整体流程。

 

当从网卡驱动上读取数据时,也就是获取数据的SKB,首先需要判断这个SKB是否有效,然后再判断该网卡是否起动了PPPoE服务,很显然这里需要读取proc的接口信息。如果已经PPPoE拨号服务,还需要判断该包是不是一个LCP或者IPCP等其他协商数据,也就是判断协议域的数据是不是 0X0021。因为如果是协商数据,则不需要解包,而直接将其转发到PPP虚拟接口上。对于具体的解包过程将进行代码分析。解完包以后该数据包就属于普通的IP包,后续流程与普通的IP包处理相同。[!--empirenews.page--]

2.3 PPPoE数据发送

PPPoE数据发送流程基本上是数据接收的逆过程,图5描述整个数据发送过程。首先从用户空间或者FORWARDING模块获取一个数据包,这个数据包属于正常的IP包。很显然这个包是无法发送到PPP链路上的,因为PPPoE服务器并不识别这样的数据包。所以需要利用proc文件中的 Session_ID、远端MAC和本地MAC数据来封装IP包,使其成为一个标准的PPP包。

 

2.4 核心代码实现

整个PPPoE内核模式拨号的核心代码主要集中在内核模块上,该模块主要功能有proc文件读写、数据包的封装、解包等操作,下面是这个内核模块的包封装的部分程序。

 

 

以上只是部分代码,由于代码太多,而且很多代码和项目的硬件抽象层模块(HAL)息息相关,所以在此不再详细阐述。具体可以参考Lin-ux内核中pppoe模块里面的代码,虽然工作的层次有点不一样,但是总体的思路是一样的,本文的实现代码基本上也是参考的Linux内核中PP-PoE的代码。

3 结束语

本文主要描述了PPPoE内核模式拨号的设计与实现,该模式将封包动作从用户空间转移到内核空间,从而大大降低了内核空间与用户空间切换的次数,目前这种内核模式下的拨号已经大量地应用于各种网关产品中。虽然PPPoE是一种非常成熟的技术,Linux内核也已开始支持PP-PoE内核态拨号,同时由卡耐基梅隆大学开发的PPPD开源项目已经广泛应用于各种网关产品中,但是熟悉整个内核态拨号的流程是非常重要的,同时PPPD目前还存在一些 BUG,在项目开发的过程中还需做大量修改。本文提供解决方案有别于传统的通过PPP虚拟接口来传输数据的方案,在某种程度上也降低了路由模块的工作任务,尤其是需要实现多路PPPoE的时候。另外该设计方案在Linux2.6.18上已经成功通过测试,并投入使用。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

在人工智能飞速发展的当下,大模型展现出了强大的语言理解与生成能力。然而,要让这些模型真正在实际场景中发挥作用,与外部丰富的工具及数据源顺畅交互至关重要。在此背景下,Model Context Protocol(MCP),...

关键字: 人工智能 大模型 协议

CPU亲和度通过限制进程或线程可以运行的CPU核心集合,使得它们只能在指定的CPU核心上执行。这可以减少CPU缓存的失效次数,提高缓存命中率,从而提升系统性能。

关键字: Linux 嵌入式

在Linux系统性能优化中,内存管理与网络连接处理是两大核心领域。vm.swappiness与net.core.somaxconn作为关键内核参数,直接影响系统在高负载场景下的稳定性与响应速度。本文通过实战案例解析这两个...

关键字: Linux 内存管理

对于LLM,我使用b谷歌Gemini的免费层,所以唯一的成本是n8n托管。在使用了n8n Cloud的免费积分后,我决定将其托管在Railway上(5美元/月)。然而,由于n8n是开源的,您可以在自己的服务器上托管它,而...

关键字: 人工智能 n8n Linux

在Linux系统管理中,权限控制是安全运维的核心。本文通过解析/etc/sudoers文件配置与组策略的深度应用,结合某金融企业生产环境案例(成功拦截98.7%的非法提权尝试),揭示精细化权限管理的关键技术点,包括命令别...

关键字: Linux 用户权限 sudoers文件

Linux内核中的信号量(Semaphore)是一种用于资源管理的同步原语,它允许多个进程或线程对共享资源进行访问控制。信号量的主要作用是限制对共享资源的并发访问数量,从而防止系统过载和数据不一致的问题。

关键字: Linux 嵌入式

在云计算与容器化技术蓬勃发展的今天,Linux网络命名空间(Network Namespace)已成为构建轻量级虚拟网络的核心组件。某头部互联网企业通过命名空间技术将测试环境资源消耗降低75%,故障隔离效率提升90%。本...

关键字: Linux 云计算

在Linux内核4.18+和主流发行版(RHEL 8/Ubuntu 20.04+)全面转向nftables的背景下,某电商平台通过迁移将防火墙规则处理效率提升40%,延迟降低65%。本文基于真实生产环境案例,详解从ipt...

关键字: nftables Linux

在Linux设备驱动开发中,等待队列(Wait Queue)是实现进程睡眠与唤醒的核心机制,它允许进程在资源不可用时主动放弃CPU,进入可中断睡眠状态,待资源就绪后再被唤醒。本文通过C语言模型解析等待队列的实现原理,结合...

关键字: 驱动开发 C语言 Linux

在Unix/Linux进程间通信中,管道(pipe)因其简单高效被广泛使用,但默认的半双工特性和无同步机制容易导致数据竞争。本文通过父子进程双向通信案例,深入分析互斥锁与状态机在管道同步中的应用,实现100%可靠的数据传...

关键字: 管道通信 父子进程 Linux
关闭