一、为什么需要 SDN

1.1 传统方式的三个问题

回顾第 17 讲:传统网络中,每台路由器自己运行路由协议、自己算转发表

问题 1:垂直集成,厂商锁定

路由器 = 专用硬件 + 厂商私有操作系统 + 厂商私有协议实现
        ⭐ 三者捆绑销售,无法拆开

你不能在 Cisco 的硬件上跑 Juniper 的软件。创新只能等厂商。

问题 2:难以实现"策略"

传统路由协议的目标是「找最短路」。但运营者真正想要的往往是:

「让视频流量走 A 路径,备份流量走 B 路径」
「客户 X 的流量必须经过安全审计设备」
「链路利用率超过 70% 时自动重新分流」

⚠️ 这些需求在传统架构下只能靠在每台设备上手工配置、拼凑各种协议特性(策略路由、路由映射、访问控制列表)来实现。脆弱、易错、难以验证。

问题 3:没有全局视角

每台路由器只根据自己算出的最短路做决策。没有任何实体拥有全网的实时视图,也就无法做全局最优的流量工程。

1.2 SDN 的核心思想

把控制平面从设备里剥离出来,集中到一个(逻辑上的)控制器上。

传统:                          SDN:
┌──────────────┐               ┌──────────────────────┐
│ 控制 + 数据    │               │   ⭐ 控制器(软件)     │
│ 控制 + 数据    │               └─┬──────┬──────┬──────┘
│ 控制 + 数据    │                 │      │      │
└──────────────┘               ┌──▼──┐┌──▼──┐┌──▼──┐
每台设备各自决策                 │数据 ││数据 ││数据 │  ← "哑"转发设备
                                └─────┘└─────┘└─────┘

二、SDN 的四层架构

┌───────────────────────────────────────────────────┐
│  ④ 网络控制应用                                     │
│     路由 · 负载均衡 · 访问控制 · 流量工程            │
└──────────────────────┬────────────────────────────┘
                       │  ⭐ 北向接口(REST API)
┌──────────────────────▼────────────────────────────┐
│  ③ SDN 控制器(网络操作系统)                        │
│     维护网络状态信息 · 提供统一抽象                   │
│     (ONOS、OpenDaylight、Ryu)                     │
└──────────────────────┬────────────────────────────┘
                       │  ⭐ 南向接口(OpenFlow / P4Runtime / NETCONF)
┌──────────────────────▼────────────────────────────┐
│  ② SDN 控制的交换机                                 │
│     只做「匹配 + 动作」(第 19 讲)                   │
└───────────────────────────────────────────────────┘
│  ① 物理网络:链路与设备                              │
└───────────────────────────────────────────────────┘

关键概念

「逻辑上集中,物理上分布」

⚠️ 控制器是【逻辑上】集中的,但【物理上】必须是分布式的集群
   否则它就是单点故障,而且性能会成为瓶颈
   实际实现用 Raft 等共识算法在多个控制器实例间同步状态

北向接口 vs 南向接口

方向 作用 典型协议
北向 控制器 ↔ 应用 让应用能描述"我想要什么" REST API
南向 控制器 ↔ 交换机 下发流表、收集状态 OpenFlow、P4Runtime、NETCONF

📌 注意这个架构的抽象层次:应用说「我要让流量避开链路 X」,控制器把它翻译成几百条流表规则下发。**这与操作系统把 open() 翻译成磁盘 IO 是同一种抽象。**这就是控制器被称为「网络操作系统」的原因。


三、OpenFlow 协议

控制器与交换机之间跑在 TCP(通常 6653 端口) 上,可选 TLS 加密。

控制器 → 交换机

报文 作用
FEATURES 查询交换机能力
CONFIGURE 设置配置参数
MODIFY-STATE 增删改流表项(最核心的一个)
PACKET-OUT 让交换机从某端口发出一个指定的分组
READ-STATE 读取统计计数器

交换机 → 控制器

报文 作用
PACKET-IN 「有个分组我不知道怎么处理」,上送控制器决定
FLOW-REMOVED 某流表项超时或被删除
PORT-STATUS 端口状态变化(链路 up/down)

PACKET-IN 是 SDN 的关键交互

分组到达 → 查流表 → 没有匹配项
   → ⭐ 封装进 PACKET-IN 送给控制器
   → 控制器决策,通过 MODIFY-STATE 下发新流表项
   → 后续同类分组直接在数据平面转发(不再麻烦控制器)

⚠️ 这里有一个性能陷阱:如果流表设计不当导致大量分组上送控制器,控制器会成为瓶颈,且引入巨大时延。这也是 DDoS 攻击 SDN 网络的一个途径(构造大量不匹配的流)。

P4:可编程数据平面

OpenFlow 的局限:它只能匹配预先定义好的那些字段。若出现一个新协议,硬件不认识它,OpenFlow 也无能为力。

P4(Programming Protocol-independent Packet Processors) 更进一步:

⭐ 用一种语言【描述交换机应该如何解析报文头部】,
   然后编译下发到可编程 ASIC

→ 交换机可以理解任意自定义的协议格式
→ "协议无关" 的转发

📌 从 OpenFlow 到 P4 的演进,是从「可配置」走向「可编程」。


四、ICMP:网络层的信使

4.1 定位

⚠️ ICMP 的层次归属是一道经典的考题。

ICMP 报文【封装在 IP 数据报中】(IP 协议号 = 1)
   → 从封装看,它像是 IP 的上层

但它传递的是【网络层自身的控制信息】
   → 从功能看,它是网络层的一部分

⭐ 标准答案:ICMP 是网络层协议,但在 IP 之上传输。

4.2 报文格式

┌────────┬────────┬─────────────────┐
│ 类型(8) │ 代码(8) │    校验和 (16)   │
├────────┴────────┴─────────────────┤
│         (类型相关字段)             │
├───────────────────────────────────┤
│ ⭐ 出错的 IP 数据报头部 + 前 8 字节数据 │
└───────────────────────────────────┘

为什么要携带"前 8 字节数据"?因为 TCP/UDP 头部的前 8 字节包含源端口和目的端口——这让主机能知道是哪个进程的哪条连接出了问题,从而把错误报告给正确的应用。

这是一个跨层设计的小巧思:网络层的错误报告,需要传输层的信息才能被正确投递。

4.3 常见类型

类型 代码 含义
0 0 Echo Reply(ping 的回复)
3 0 目的网络不可达
3 1 目的主机不可达
3 3 目的端口不可达(没有进程在监听)
3 4 需要分片但设置了 DF(Path MTU Discovery 靠它)
4 0 源抑制(已废弃)
8 0 Echo Request(ping)
11 0 TTL 超时(traceroute 靠它)
12 0 头部参数错误

4.4 traceroute 的完整原理 ⭐

回顾第 3 讲,现在可以讲清全部细节:

① 发送方向目的地发送 UDP 报文段,⭐ 目的端口是一个【极不可能被使用】的值
   (传统实现用 33434+)
② 第一批 3 个报文的 ⭐ TTL = 1
③ 第一跳路由器把 TTL 减为 0 → 丢弃 → ⭐ 回送 ICMP【类型 11】超时报文
④ 发送方记录:第 1 跳是谁、往返用了多久(发 3 个所以有 3 个时间)
⑤ TTL = 2,重复 …… 直到 TTL = n 时到达目的主机
⑥ ⭐ 目的主机没有进程监听那个端口 → 回送 ICMP【类型 3 代码 3】端口不可达
⑦ 发送方看到"端口不可达"而不是"超时",知道已经到达终点,停止

两个巧妙之处

  1. 用 TTL 当"探测深度"的旋钮——一个为防环路而设计的字段被用来做拓扑发现
  2. 用"端口不可达"当终止信号——故意用一个不存在的端口,把错误变成信息

⚠️ 常见现象的解释

现象 原因
* * * 该跳配置为不回 ICMP,或对 ICMP 限速。不代表不通
中间某跳时延比后面的跳还大 该跳的控制平面 CPU 忙(生成 ICMP 是软件路径),不代表转发慢
往返路径不对称 热土豆路由(第 21 讲),traceroute 只能看到去程

📌 Windows 的 tracertICMP Echo Request 而不是 UDP,因此在某些只放行 ICMP 的网络里表现不同。

4.5 ICMP 的安全考量

⚠️ ICMP 被广泛用于攻击与侦察:

  • Smurf 攻击:向广播地址发 ping、伪造源地址为受害者 → 放大攻击
  • ICMP 隧道:把数据藏在 ICMP 载荷里绕过防火墙(数据外泄)
  • 网络侦察:ping 扫描发现存活主机

但完全屏蔽 ICMP 是错误的

⚠️ 屏蔽类型 3 代码 4 → ⭐ Path MTU Discovery 失效
   → 大分组被静默丢弃 → 连接建立成功但传数据时"黑洞"
   ⭐ 这是最难排查的网络故障之一

⚠️ 屏蔽 ICMPv6 → IPv6 完全无法工作(NDP 依赖它,第 19 讲)

📌 正确做法是限速与选择性放行,而不是一律丢弃。


五、网络管理

5.1 要管什么

故障管理(Fault)· 配置管理(Configuration)· 计费(Accounting)
性能管理(Performance)· 安全管理(Security)
              ⭐ 合称 FCAPS

5.2 SNMP(简单网络管理协议)

三个组成部分

组件 说明
MIB(管理信息库) 被管设备上的一组对象,如「接口 3 的入字节数」
SMI(管理信息结构) 定义 MIB 对象的数据类型与命名规则
SNMP 协议 在管理服务器与被管设备之间传递信息

两种操作模式

⭐ 请求-响应(拉):
   管理服务器 ──GetRequest──▶ 被管设备
              ◀──Response──

⭐ Trap(推):
   被管设备 ──Trap──▶ 管理服务器      「我出问题了!」
   (不需要等轮询,事件驱动)

⚠️ SNMP 的问题

  • v1/v2c 用明文的 “community string” 当密码(默认还常常是 public)——安全性极差
  • v3 加了认证和加密,但配置复杂,部署率不高
  • 读容易,写难:SNMP 在监控上很成功,在配置上几乎没人用

5.3 NETCONF / YANG:现代范式

**SNMP 只解决了"看",没解决"改"。**运维人员实际上还是在用 SSH + CLI 脚本改配置——脆弱、无事务、无回滚。

NETCONF(RFC 6241)

运行在 ⭐ SSH 之上,用 XML 编码
提供操作: get-config / edit-config / copy-config / delete-config
       ⭐ lock / unlock / commit / ⭐ rollback

关键改进:事务语义。

配置可以先【提交到候选配置】,验证通过后再【commit】
出错可以【rollback】
多台设备的配置变更可以作为一个整体成功或整体失败

YANG:一种数据建模语言,用来精确描述配置和状态数据的结构。

YANG 定义"配置长什么样"  →  NETCONF/RESTCONF 负责"怎么传输和应用"

📌 **从 SNMP 到 NETCONF/YANG 的转变,本质上是网络运维从「手工操作 + 监控」走向「基础设施即代码」。**这与软件工程从手工部署走向 CI/CD 是同一场变革。

5.4 实用工具速查

工具 用途
ping ICMP Echo,测连通性与 RTT
traceroute / mtr 逐跳路径与时延(mtr 持续采样,更实用
dig / nslookup DNS 查询(第 7 讲)
ss / netstat 查看本机连接与端口状态
tcpdump / Wireshark 抓包(Lab 1
ip route / ip addr 查看路由表与接口地址
iperf3 吞吐量测试
curl -v 查看完整 HTTP 交互

六、MPLS:在分组网上模拟电路

6.1 动机

回顾第 2 讲的电路交换 vs 分组交换。MPLS 是一个混合体

IP 转发的两个痛点

  1. 最长前缀匹配相对昂贵(虽然 TCAM 已经很快)
  2. 无法做流量工程——IP 只按目的地址转发,无法让两条去往同一目的地的流走不同路径

6.2 机制

在 IP 头部之前插入一个 MPLS 标签:

┌──────────────────────────────┬─────────┬──────────┐
│ MPLS 头(20 位标签 + 8 位 TTL 等)│ IP 头   │  数据     │
└──────────────────────────────┴─────────┴──────────┘
        ⭐ 位于链路层与网络层之间 → 常称"2.5 层"

转发方式

⭐ 路由器只看【标签】,做一次简单的表查询(不是最长前缀匹配)
   然后【交换标签】并转发
   → 这叫"标签交换"(Label Switching)

LSP(Label Switched Path):由一系列标签构成的、预先建立的端到端路径。

📌 这就是"电路"的复活:LSP 本质上是一条虚电路,只不过建在分组网络上。

6.3 用途

用途 说明
流量工程(TE) 可以让流量走非最短路径,均衡链路利用率
VPN(L3VPN) 用标签隔离不同客户的流量,这是 MPLS 最大的商业应用
快速重路由(FRR) 预先建好备份 LSP,故障时毫秒级切换
QoS 不同 LSP 给不同的服务等级

⚠️ MPLS 需要一个额外的信令协议来分发标签(LDP 或 RSVP-TE),增加了复杂度。

📌 今天的地位:MPLS 在运营商核心网和企业专线(MPLS VPN)中仍然是主流,但在数据中心内部已大量被 VXLAN 等基于 IP 的隧道方案取代,在广域网接入侧则面临 SD-WAN 的竞争。


七、例题(Worked Example)

题目:某工程师执行 traceroute example.com,得到如下输出:

 1  192.168.1.1        1.2 ms   1.1 ms   1.1 ms
 2  10.10.0.1          8.4 ms   9.1 ms   8.7 ms
 3  * * *
 4  203.0.113.9       45.2 ms  44.8 ms  45.1 ms
 5  198.51.100.2      22.3 ms  22.1 ms  22.5 ms
 6  93.184.216.34     23.0 ms  22.8 ms  23.1 ms

(a) 第 3 跳的 * * * 说明该路由器故障了吗? (b) 第 4 跳的 45 ms 比第 5 跳的 22 ms 还大,这可能吗?为什么? (c) traceroute 如何知道第 6 跳是终点,从而停止? (d) 若该工程师在防火墙上屏蔽了所有 ICMP,会发生什么?

解答

(a) 不能说明故障。

判据很明确:第 4、5、6 跳都正常返回了,说明探测分组确实穿过了第 3 跳。它只是被配置为不回送 ICMP 超时报文(出于安全策略),或对 ICMP 的生成做了速率限制。

(b) 完全可能,而且很常见。

两个原因:

  1. ⭐ **生成 ICMP 报文走的是路由器的控制平面(软件路径),而转发走的是数据平面(硬件路径)。**如果第 4 跳的 CPU 正忙,它生成 ICMP 响应的时间就会很长——这反映的是该路由器 CPU 的繁忙程度,不是它的转发性能
  2. ⭐ **返回路径可能不同。**由于热土豆路由(第 21 讲),第 4 跳回送 ICMP 时走的返程路径,可能与第 5 跳的返程路径完全不同,且更长。

📌 重要结论:traceroute 显示的是「到该跳的往返时延」,不是「到该跳的单向时延」,也不是路径上的累积时延。中间某跳数值偏高,通常不构成性能问题的证据。

(c) 因为第 6 跳返回的是 ICMP 类型 3 代码 3(端口不可达),而不是类型 11(TTL 超时)

traceroute 故意把 UDP 目的端口设成一个极不可能有进程监听的值(如 33434+)。当分组终于到达目的主机时,主机的传输层发现没有进程在那个端口上,就回送"端口不可达"——traceroute 把这个错误当作"我到了"的信号。

(d) 会造成多重故障

① traceroute 完全失效(收不到类型 11 和类型 3)
② ping 失效(收不到类型 0)
③ ⭐ 最严重:Path MTU Discovery 失效
   屏蔽类型 3 代码 4 后,发送方永远收不到"需要分片"的通知
   → 大分组被静默丢弃
   → 症状:TCP 三次握手成功、小请求正常,但一传大数据就【卡死】
   ⭐ 这就是俗称的"PMTUD 黑洞",是最难排查的网络故障之一
④ 若是 IPv6,屏蔽 ICMPv6 会让 NDP 失效 → 网络完全不通(第 19 讲)

正确做法:对 ICMP 限速选择性放行必要类型(尤其是类型 3 代码 4 和 ICMPv6 的 NDP 相关类型),而不是一律丢弃。


八、随堂自测

  1. 传统每路由器控制平面的三个问题是什么?
  2. SDN 控制器为什么必须「逻辑集中、物理分布」?
  3. PACKET-IN 报文在什么时候产生?它可能带来什么性能问题?
  4. P4 相对 OpenFlow 的进步是什么?
  5. ICMP 属于第几层?为什么这个问题有争议?
  6. ICMP 报文为什么要携带出错数据报的前 8 字节数据?
  7. 完整描述 traceroute 的工作原理,包括它如何判断到达终点。
  8. SNMP 的三个组成部分是什么?它为什么在配置管理上失败了?
  9. NETCONF 相对 SNMP 的关键改进是什么?
  10. MPLS 解决了 IP 转发的什么问题?为什么说它是"2.5 层"?

九、本讲要点回顾

  • 传统控制平面的三个问题:垂直集成锁定、难以实现策略、缺乏全局视角
  • SDN 四层:物理网络 → SDN 交换机 → 控制器 → 网络应用南向 OpenFlow,北向 REST
  • 控制器逻辑集中、物理分布,否则就是单点故障。
  • PACKET-IN:流表未命中时上送控制器——也是性能瓶颈与攻击面
  • P4 = 从可配置走向可编程(协议无关的报文解析)。
  • ICMP 是网络层协议,但封装在 IP 之上;携带出错数据报头部 + 前 8 字节(含端口号)
  • traceroute = 递增 TTL 触发类型 11,用"端口不可达"(类型 3 代码 3)判断终点。
  • ⚠️ 一律屏蔽 ICMP 会导致 PMTUD 黑洞和 IPv6 完全瘫痪。
  • SNMP 擅长监控,不擅长配置NETCONF/YANG 带来了事务、回滚与「基础设施即代码」
  • MPLS 是"2.5 层"标签交换,主要价值在流量工程L3VPN

十、自测答案

1.垂直集成:硬件、操作系统、协议实现由同一厂商捆绑,无法混搭,创新受制于厂商节奏。② 难以实现策略:路由协议只会算最短路,运营者真正想要的策略(按业务分流、强制经过某设备、按利用率调度)只能靠在每台设备上手工拼凑配置来近似,脆弱且难以验证。③ 缺乏全局视角:没有任何实体拥有全网实时状态,无法做全局最优的流量工程。

2. 逻辑集中是为了给应用提供「整个网络是一台设备」的统一抽象,从而能做全局决策;物理分布是必需的,因为单个控制器实例会成为单点故障(它挂了整个网络失去控制能力)和性能瓶颈(成千上万台交换机的事件都要它处理)。实际部署用 Raft 等共识算法在多个控制器实例间同步状态。

3. 当一个分组到达交换机、在流表中找不到匹配项时产生——交换机把该分组(或其头部)封装进 PACKET-IN 送给控制器请求决策。性能问题:若流表设计不当(规则过于具体、通配不足),大量分组会上送控制器,导致 ① 控制器 CPU 与控制通道成为瓶颈;② 这些分组经历巨大的额外时延。这也构成一种攻击面——攻击者构造大量互不相同的流,故意制造 PACKET-IN 风暴。

4. OpenFlow 只能匹配预先在标准中定义好的固定字段集合,遇到新协议或自定义头部就无能为力。P4 允许用一种语言描述交换机应当如何解析报文头部,并编译下发到可编程 ASIC,因而可以支持任意自定义的协议格式——从「可配置」走向「可编程」

5. 是网络层协议。争议来源于:从封装上看,ICMP 报文装在 IP 数据报里(协议号 1),位置像是 IP 的上层用户;但从功能上看,它传递的是 IP 自身的差错与控制信息,是网络层不可分割的一部分(IPv6 中 NDP 甚至依赖它才能工作)。标准表述是:ICMP 是网络层协议,但其报文在 IP 之上传输。

6. 因为 TCP/UDP 头部的前 8 字节恰好包含源端口号和目的端口号。有了它们,收到 ICMP 差错报文的主机才能确定是哪个进程的哪条连接触发了错误,从而把差错正确地报告给对应的应用(例如把"端口不可达"转换成应用层的 Connection refused)。这是一个跨层设计:网络层的错误报告需要传输层的信息才能被正确投递。

7. 发送方向目的地发送探测分组(传统实现用 UDP,目的端口设为一个极不可能被监听的值如 33434+),TTL 从 1 开始逐次递增,每个 TTL 值发 3 个探测。TTL 为 n 的分组在第 n 跳被减到 0 而丢弃,该路由器回送 ICMP 类型 11(TTL 超时),发送方据此记录第 n 跳的地址与往返时延。当 TTL 足够大、分组终于到达目的主机时,目的主机发现没有进程监听那个端口,回送 ICMP 类型 3 代码 3(端口不可达)——收到的是"端口不可达"而非"超时",就意味着已经到达终点,traceroute 随即停止。

8.MIB(管理信息库:被管设备上的对象集合);② SMI(管理信息结构:定义 MIB 对象的数据类型与命名规则);③ SNMP 协议本身(传递 Get/Set 请求与 Trap 通知)。它在配置管理上失败,原因是:安全模型薄弱(v1/v2c 用明文 community string,因此没人敢开放写权限)、缺乏事务语义(没有 commit/rollback,一半成功一半失败无法处理)、以及缺少跨设备的一致性保证。结果是运维人员宁愿用 SSH + CLI 脚本,SNMP 沦为纯监控协议。

9. 关键改进是⭐ 事务语义:配置可以先写入候选配置、经验证后 commit,出错可 rollback,并支持 lock 防止并发修改冲突;多台设备的变更可以作为一个整体成功或整体失败。此外 NETCONF 跑在 SSH 上(安全性远好于 SNMPv2c),用 YANG 精确建模配置结构(使配置可校验、可自动生成代码),这共同支撑了「网络基础设施即代码」的运维范式。

10. MPLS 解决了 ① 最长前缀匹配的开销(改为简单的标签表查询)和 ② ⭐ IP 无法做流量工程的问题——IP 只按目的地址转发,两条去往同一目的地的流必然走同一路径,而 MPLS 可以为它们建立不同的 LSP,从而实现负载均衡和非最短路径调度。称它"2.5 层",是因为 MPLS 头部插在链路层头部之后、IP 头部之前,既不属于链路层也不属于网络层,介于两者之间。