干网络这行,没人能绕开PPP和PPPoE这对组合。十几年前用电话线上网,得先听到一阵刺耳的拨号音,那是Modem在协商链路;现在家里光猫改成桥接,路由器WAN口填上宽带账号密码,拨号成功那一瞬间,走的还是PPP那套老底子。可以说,PPP是数据链路层最老牌的点对点协议之一,而PPPoE是它在新网络环境里最成功的延续形态。
这篇文章我打算把两件事讲透:一是PPP到底由哪些部分组成、帧结构为什么这么设计,二是PPPoE为什么非要套在以太网上、会话是怎么一步步建立的。我会结合自己抓包排障的经验来写,手把手带你看一次完整的拨号协商流程,再把常见故障场景和排查思路一块儿梳理出来。不管你是刚入行的网络工程师、在备考认证的学生,还是家里宽带老是掉线想自己搞明白的普通用户,这篇都能让你少走点弯路。
1. PPP协议:点对点链路上的老牌协议
1.1 从SLIP到PPP:PPP诞生的背景
先把时间拨回上世纪八九十年代。当时的网络设备要互联,最朴素的方式就是拉一根串行线,比如RS-232,两端点对点直连。最早的解决方案是SLIP(Serial Line IP),1988年就有了,但它实在太简陋:只能封装IP、没有协商机制、不认证、不做错误检测,甚至对端IP都得手工写死。两台设备之间想换个参数,得停机改配置,这在生产环境里是没法接受的。
PPP(Point-to-Point Protocol)就是在这个背景下诞生的,1994年正式成为RFC 1661。它的目标很明确:在一根点对点链路上,完成链路的建立、配置、认证、网络层参数的自动协商,以及数据的可靠封装。你可以把PPP理解为“点对点链路上的完整协议栈管家”,它不光管数据怎么封装,还管链路生命周期里的所有状态变化。
为什么说PPP是个“协议族”而不是单一协议?因为它由三部分组成:封装格式、LCP(链路控制协议)和NCP(网络控制协议)。封装格式解决“数据怎么放进去”,LCP解决“链路怎么建起来、怎么维持、怎么断开”,NCP解决“网络层参数怎么协商”,比如IP地址由谁分配、DNS服务器是多少。这种分层设计在当时相当超前,也正是这种清晰的分工,让PPP在几十年后还能以PPPoE的形态活跃在千家万户的宽带线路上。
1.2 PPP的三层结构:LCP、NCP与认证协议
展开说一下PPP的内部构造。很多人都看过讲解PPP的PPT,画得花里胡哨,其实你只需要记住三件事。
第一件事是LCP。链路刚建立的时候,两端设备互相不知道对方的能力,LCP就是用来“打招呼、对参数”的。它要协商的内容包括:
- MRU(最大接收单元):告诉对端我最多能接收多大的数据包,默认1500字节。
- 认证协议:协商好后面用PAP还是CHAP来做身份验证。
- 魔术字(Magic Number):用来检测环路。每端生成一个随机数,如果发现对端的魔术字和自己的相同,说明链路可能形成了环,会主动断开。
- PFC/ACFC压缩选项:协议字段压缩和地址控制字段压缩,现在大多数场景都不开,开了反而容易出兼容性问题。
LCP协商通过交换Configure-Request、Configure-Ack、Configure-Nak、Configure-Reject这几种报文来完成。整套动作很像两个人第一次见面,互相确认“你能接受我说话的方式吗”。
第二件事是认证协议。PPP支持两种主流认证方式:
- PAP:两次握手。客户端把用户名密码明文发给服务器,服务器回ACK或NAK。简单粗暴,但密码在链路上是明文,风险大,现在基本只在兼容老设备时用。
- CHAP:三次握手。服务器先发一个挑战码(Challenge),客户端用MD5把密码和挑战码一起算出一个摘要回传,服务器自己也算一遍,一致才算通过。密码始终不出现链路上,安全性比PAP高得多。
家用宽带的PPPoE拨号,运营商的接入设备一般会优先要求CHAP。你在路由器上填的宽带账号密码,在链路上传输时其实不是明文,这一点可以放心。
第三件事是NCP。链路建好、认证通过之后,就要开始谈网络层的事。最典型的是IPCP,它负责两件事:一是给客户端分配IP地址,二是下发DNS服务器地址。拨号成功后电脑或路由器拿到的IP、网关、DNS,就是这一步协商出来的。IPv6线路则走IPv6CP,协商IPv6地址和前缀。
这三件事有严格的先后顺序:先LCP建链,再认证,最后NCP配网络参数。任何一步失败,整条链路都起不来。理解了这个顺序,后面排查拨号故障时就能按图索骥。
1.3 PPP帧结构拆解
PPP帧的格式很经典,一个完整帧由以下几部分组成:
| 字段 | 长度 | 说明 |
|---|---|---|
| Flag | 1字节 | 固定0x7E,标识帧边界 |
| Address | 1字节 | 固定0xFF,点对点链路不需要寻址 |
| Control | 1字节 | 固定0x03,无序号帧 |
| Protocol | 2字节 | 标识载荷类型,0x0021为IP、0xC021为LCP、0xC023为PAP、0xC223为CHAP |
| Information | 可变 | 实际载荷 |
| FCS | 2或4字节 | 帧校验序列,用于检错 |
因为PPP跑在串行链路上,数据是逐字节发送的,Flag 0x7E用来定界。问题来了:如果载荷里恰好出现0x7E怎么办?那就需要字节填充(Byte Stuffing)。规则很简单:发送端遇到0x7E,就替换成0x7D 0x5E;遇到0x7D,替换成0x7D 0x5D;遇到小于0x20的控制字符,在前面加上0x7D并对原字符做异或0x20处理。接收端看到0x7D就知道后面是转义后的字节,再还原回去。这套机制保证了帧边界的可靠性,代价是传输效率有轻微损耗,但点对点链路上这点开销完全可接受。
2. PPPoE:为什么非要把PPP搬到以太网上
2.1 以太网的一个先天缺陷
现在进入重头戏:PPPoE。先说一个事实:以太网这种多点共享介质,天生没有“会话”这个概念。一台交换机上可能挂了几百个用户,每个用户的流量在交换机看来都是以太网帧,只不过源MAC地址不同而已。如果运营商给每个用户都直接分配一个IP并允许上网,账号认证、计费、带宽控制这些东西全都无从谈起。用户换个MAC地址就能蹭网,运营商根本没法管理。
而PPP恰好提供了以太网缺的所有东西:用户认证、按会话计费、动态IP分配、链路状态管理。所以设计者们想到一个很自然的思路:把PPP封装在以太网帧里,让PPP的会话机制为以太网上的每个用户单独建立一条“虚拟拨号链路”。这就是PPPoE,1999年发布的RFC 2516。
打个比方。以太网就像一条人来人往的大马路,谁都能走;PPP就像两个人之间的一根专线电话,私密可控。PPPoE干的事,就是在马路上先喊一嗓子“这里有人能提供专线服务吗?”,有人应答之后,两个人之间画出一条虚拟的专线通道,之后的对话都在这条通道里进行,路人看不到也插不进。
2.2 PPPoE的两阶段工作流程
PPPoE的最大特点是把整个过程分成两个阶段:发现阶段(Discovery)和会话阶段(Session)。
发现阶段的目的很纯粹:在共享的以太网上找到服务端,并协商出一个会话ID(Session ID)。它由四个报文完成:
- PADI(PPPoE Active Discovery Initiation):客户端以广播方式发出,相当于“有人在吗?我要拨号上网”。
- PADO(PPPoE Active Discovery Offer):服务端收到PADI后,单播回应一个PADO,相当于“我在,我能提供服务”,报文里会带上服务端名称和可提供的服务标签。
- PADR(PPPoE Active Discovery Request):客户端从可能收到的多个PADO里挑一个,单播发PADR,相当于“就你了,给我建立会话”。
- PADS(PPPoE Active Discovery Session-confirmation):服务端确认,分配一个唯一的Session ID并回复PADS。从此客户端和服务端之间就有了一个双方都认同的会话编号。
从发出PADI到收到PADS,四步握手一气呵成。之后链路进入会话阶段,以太网帧的EtherType从0x8863变成0x8864,载荷里直接封装PPP帧。从这一刻开始,PPP的LCP、认证、IPCP协商就在这条PPPoE会话里按部就班地进行。
如果中途要断开,任何一方都可以发送PADT(PPPoE Active Discovery Terminate)报文,会话ID即刻失效。这个过程很像打电话:先拨号、对方接听、建立通话,挂断时双方都知道通话结束。
2.3 PPPoE报文的里里外外
一个完整的PPPoE报文包含三层封装。先是以太网头部(14字节):目的MAC、源MAC,以及EtherType字段。发现阶段EtherType为0x8863,会话阶段为0x8864。接着是PPPoE头部(6字节):VER字段占4bit,值为1;TYPE字段占4bit,值为1;CODE字段占1字节,标识报文类型,发现阶段PADI是0x09、PADO是0x07、PADR是0x19、PADS是0x65、PADT是0xA7,会话阶段Code为0x00;SESSION_ID占2字节,发现阶段为0,会话阶段是实际分配的ID;最后是LENGTH字段占2字节,表示PPPoE载荷长度,不包含以太网头和PPPoE头自身。载荷部分,发现阶段放的是各种TLV格式的标签,会话阶段放的是完整PPP帧。
这里有个关键点要记住:以太网帧原本允许的载荷最大是1500字节,PPPoE自身头部占6字节,PPP协议字段又占2字节,总共8字节额外开销,所以PPPoE链路上的MTU只能到1492。这也是为什么路由器或电脑上PPPoE拨号接口的MTU值是1492而不是1500。很多人改MTU翻车,就是没搞明白这8字节去哪了。
3. 实操视角:拨号全流程与抓包验证
3.1 PPPoE在你的网络里到底跑在哪
先捋一下家庭宽带最常见的组网方式。光猫如果工作在路由模式,PPPoE拨号由光猫自己完成,下面的路由器只需要做NAT和无线覆盖,你基本感觉不到PPPoE的存在。但如果把光猫改成桥接模式,PPPoE会话就由路由器WAN口发起,运营商机房的接入设备(通常叫BRAS)负责终结会话、分配IP。
我个人建议有一定动手能力的用户把光猫改成桥接,让路由器来拨号。原因很简单:运营商光猫的性能普遍一般,CPU和内存都紧巴巴的,PPPoE终结、NAT、防火墙全压在上面,多设备并发连接一多就容易卡。路由器性能强得多,拨号、NAT、QoS这些活儿交给它更靠谱。
从报文层面看,PPPoE报文本身不变,变的只是承载设备。桥接模式下,光猫只做VLAN封装转换,BRAS和路由器之间的PPPoE报文原样通过。这里有个容易踩的坑:运营商不同线路的VLAN ID可能不一样,桥接模式下路由器WAN口的VLAN ID必须和运营商光猫配置对齐,否则连PADI都发不出去。
3.2 亲手抓一次PPPoE协商过程
理论说了这么多,不如直接抓包看一次。用Wireshark,过滤条件写成 eth.type == 0x8863 || eth.type == 0x8864,或者更省事直接写 pppoe。然后让路由器重新拨号,或者用电脑的宽带连接拨一次号,完整协商过程就一目了然。
我抓过很多次,正常流程是这样的。先是发现阶段,电脑或路由器发出PADI广播,目的MAC是全F,在抓包里能看到一个EtherType为0x8863的广播帧,里面带有一个Host-Uniq标签,这是客户端用来匹配自己请求的唯一标识。紧接着BRAS回PADO,单播帧,带接入设备名称标签。然后客户端发PADR,BRAS回PADS,分配一个Session ID,比如0x0001,至此发现阶段结束。
然后是会话阶段。第一件事是LCP协商,两边互发Configure-Request和Configure-Ack,协商MRU、认证协议、魔术字。认证协议这里通常写着CHAP或PAP,BRAS一般会明确要求用哪种,如果客户端配置的认证方式和它不一致,LCP协商就会失败。认证通过后进入IPCP协商,客户端拿到运营商分配的IP地址和DNS服务器地址。
抓包时有个细节值得留意:完整的PPPoE报文在Wireshark里会分层展示,以太网头、PPPoE头、PPP头(包括Protocol字段)、IP载荷一层一层展开,看得非常清楚。你甚至可以右键某个字段,把它作为显示过滤器,跟踪这个会话的完整报文序列。
3.3 必须搞懂的MTU/MRU问题
前面说了PPPoE链路的MTU是1492,但问题远不止“改个数”这么简单。MTU是最大传输单元,影响的是发送端能塞进一帧的数据量;MRU是最大接收单元,是接收端告诉对端自己最多能收多大。LCP协商里明确交换MRU,双方都以较小的那一个作为链路上实际可用的上限。
在PPPoE链路上,一个非常常见的问题是TCP MSS。TCP握手时的MSS选项,告诉对端“我这边能接受的TCP载荷最大是多少”,正常以太网路径上MSS是1460,也就是1500减去40字节的IP头和TCP头。但PPPoE链路MTU只有1492,如果MSS还是1460,等对端真发一个1460字节的TCP段过来,加上IP头和TCP头就超过1492了,这个包在发送端就会被分片,而很多场景下分片会被丢弃或导致性能骤降。典型症状就是:网页打不开、图片加载不出来,但微信消息还能收,因为小包不受影响。
解决思路有两个。一是把接口MTU正确设成1492,同时在路由器上做TCP MSS Clamping,把经过PPPoE接口的TCP握手报文里的MSS值改写为1452,也就是1492减40。家用路由器固件大多内置这个功能,名字可能叫“调整MSS/MTU”,有些默认开启,有些需要手动勾选。二是在非常老旧的设备上无法调整MSS时,可以通过降低接口MTU来规避,但不要低于1400,否则正常网页浏览可能因分片过多而变慢。
我实测下来的经验是:优先保证MTU等于1492,同时开启MSS Clamping,双管齐下,绝大多数“网页打不开但微信能收”的诡异问题都能解决。
4. 故障排查:常见问题和实操心得
4.1 拨号失败的几类典型场景
PPPoE拨号失败的报错五花八门,但归纳起来逃不出下面几类。
第一类,认证失败。这是最常见的一种,报错通常直接提示用户名或密码错误。排查顺序很简单:先确认宽带账号密码有没有输错,注意大小写;再确认账号有没有欠费、是否在运营商侧被停用;最后确认你是不是在一个被绑定的端口上拨号,部分运营商的账号会和线路绑定。
第二类,找不到服务端。表现为在发现阶段就卡住了,客户端发了PADI但收不到PADO,或者发了PADR但收不到PADS。这种时候先排查物理层:光猫指示灯是否正常、网线是否插好、光功率是否正常。如果是桥接模式,重点检查路由器的VLAN ID配置是否和运营商一致,VLAN错了,广播帧根本到不了BRAS。
第三类,LCP协商失败。链路在发现阶段成功建立了会话,但PPP的LCP阶段谈崩了。最常见的诱因是认证协议不匹配,比如BRAS要求CHAP而你这边偏向PAP,或者MRU协商异常。抓包里能看到一堆Configure-Nak或Configure-Reject循环,这时候就要去核对双方的LCP配置选项。
第四类,链路建立后马上断开。表现为拨号成功、拿到IP,但几秒后掉线重拨。原因可能是账号被限制为单一会话,比如之前掉线的老会话还没被服务器收回,新会话被拒绝;也可能是线路质量不好,导致LCP保活报文没收到回复而主动断开。
4.2 稳定性问题的排查思路
比拨不上更烦人的是时不时掉线。掉线类问题我一般按这个顺序排查。
先是物理层。光猫如果新装不久,先看光功率,进运营商光猫的管理界面能看到接收光功率,一般在-20dBm以内都算正常,超过-25dBm就得怀疑光线路有问题。光猫到路由器之间的网线,别用那种老旧的四芯线,到不了千兆速率,还容易受干扰。
其次是协议层。抓一次掉线瞬间的包,看是客户端主动发PADT,比如路由器的超时配置到了,还是服务器侧没回应LCP Echo而超时断开。前者多半是设备配置或运营商会话限制,后者更偏向线路或BRAS侧的问题。
最后是设备层面的老问题:路由器长时间运行,内存碎片和连接表占满也会导致PPPoE异常。遇到这种情况,重启一次路由器往往就好了,但根本解法是换一台性能足够稳定、散热正常的路由器,或者给路由器设置每天定时重启。
还有一个容易被忽略的点:光猫和路由器同时在拨号。如果光猫是路由模式,但路由器上也配了PPPoE,会出现两个设备都在拨号,互相抢会话,导致不断重拨。检查方法很简单,看光猫管理界面的WAN状态,确认是不是只有一处终结PPPoE。
4.3 配置层面的经验小结
最后整理几条我踩过坑之后总结出来的配置经验,照着做能少很多折腾。
第一,桥接模式下别乱动光猫的VLAN设置。有些光猫在桥接WAN里就把VLAN ID写死了,路由器WAN口的设置要么跟它一致,要么按运营商给的参数来,别凭感觉填。
第二,拨号账号的大小写和特殊字符要原样复制。宽带账号看起来像手机号或一串数字,但有些运营商的账号里其实有隐藏后缀,比如带有区域标识,填错了直接认证失败。
第三,拨号成功后先核对关键参数:拿到的IP、网关、DNS。如果IP是100.64开头的共享地址段,说明你没有拿到公网IP,对远程访问、端口转发会有影响,这是运营商网络架构决定的,光改路由器配置没用。
第四,MTU别乱改。没有确认问题之前,老老实实用1492;一旦确认需要调整,也要配合MSS Clamping一起改,只改MTU不改MSS往往解决不了实际故障。
第五,怀疑是PPPoE问题但又不想抓包的时候,最快的验证办法是把光猫改成桥接模式,然后用电脑直接建宽带连接拨号。如果电脑拨号正常,问题大概率出在路由器;如果电脑也拨不上,那就可以专心排查线路和运营商侧了。这个办法我用了无数次,比报障等客服快得多。
写到这里,PPP和PPPoE的核心内容基本讲完了。说实话,这两个协议算不上高深,但它们是网络基础设施里最不起眼却最关键的环节之一。我这些年排过的宽带故障,一大半最终都能归结到PPPoE会话、MTU或认证方式上,搞清楚了底层逻辑,问题就变得非常直白。
最后再分享一个小技巧。诊断PPPoE问题的时候,不要光看错误码。同一个认证类报错,可能是密码错误、账号欠费、绑定不一致,也可能是LCP协商出了问题被包装成认证失败。把Wireshark打开抓一次完整的协商流程,看报文在哪个阶段停下来,问题定位的效率至少翻一倍。抓包这件事,真的值得认真学一学,花点时间换回来的排障能力,是长期受益的。