mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
5061 字
14 分钟
数据中心与SDN网络:数据包的终点与控制
2022-09-15

数据包在 CDN与内容分发 的边缘节点被缓存、被任播路由加速,但总有些请求必须回源——动态内容、写操作、个性化推荐——这些请求穿越 CDN 之后,终点就是数据中心。成千上万台服务器密集地堆在同一个建筑里,它们之间的流量模式、拓扑结构、控制方式,跟互联网骨干网截然不同。

数据中心是数据包旅程的”终点站”,也是现代云服务的”起点”。本章从数据中心网络的演进出发,看 CLOS 架构如何打破树形瓶颈,VXLAN 如何解决多租户隔离,SDN 如何实现控制平面集中化,负载均衡与服务网格如何把流量精准地送到正确的容器。最后通过 Mininet 动手实验,亲手搭建一个 SDN 拓扑并下发流表规则。

一、数据中心网络演进#

1.1 从树形拓扑说起#

早期数据中心的网络拓扑跟企业网几乎一样——核心-汇聚-接入三层树形结构。服务器挂在接入交换机下面,汇聚交换机连接接入层,核心交换机坐镇顶端。这种架构有个致命问题:根节点是带宽瓶颈

考虑一个典型的三层树形拓扑:接入层 10G 上联汇聚层,汇聚层 40G 上联核心层。如果底层有 1000 台服务器,每台 10G,理论总带宽 10T——但核心层只有 40G×4=160G 的上联容量。过载比(oversubscription ratio)高达 60:1,意味着大部分服务器间的通信被限速。

更麻烦的是东西向流量(east-west traffic)的增长。早期数据中心以南北向流量为主——客户端请求进来、服务器响应出去。但虚拟化、分布式存储、MapReduce 等计算模式兴起后,服务器之间的内部通信量暴增。一个 Spark 作业的 shuffle 阶段,所有 worker 节点两两交换数据,东西向流量是南北向的数倍。

1.2 传统架构的瓶颈#

传统树形拓扑的核心矛盾:

  • 根节点带宽瓶颈:所有跨汇聚交换机的流量都经过核心,核心交换机端口密度和转发能力决定整个数据中心的带宽上限
  • 单点故障风险:核心交换机宕机,整个数据中心被撕裂成孤岛
  • 过载比过高:为了控制成本,上层带宽远小于下层带宽总和,东西向流量被严重限速
  • 扩展困难:增加服务器意味着增加接入交换机,进而需要增加汇聚和核心交换机,成本非线性增长
问题传统树形理想架构
东西向带宽受限于核心层过载比全带宽无阻塞
单点故障核心宕机=全局故障任意节点故障仅影响局部
扩展成本非线性增长(核心交换机昂贵)线性增长(同构交换机)
路径多样性单一路径或少量冗余大量等价路径
故障恢复依赖 STP 收敛(秒级)快速本地重路由(毫秒级)

1.3 需求驱动变革#

三个趋势推动数据中心网络架构的根本性变革:

  1. 规模爆炸:大型云厂商的数据中心从几千台服务器增长到几十万台,传统三层架构根本无法支撑
  2. 东西向流量主导:分布式计算、微服务通信、存储复制使得服务器间流量远超南北向
  3. 多租户隔离:云平台需要为不同租户提供逻辑隔离的网络环境,VLAN 的 4096 个标签上限远远不够

这些需求催生了 CLOS 架构和 overlay 网络——用大量廉价的同构交换机构建无阻塞网络,用隧道技术实现多租户隔离。

二、CLOS架构#

2.1 脊叶拓扑#

CLOS 网络由 Charles Clos 在 1953 年的电话交换网络论文中提出,核心思想是用多级交换替代单级大容量交换,用大量小容量交换机实现无阻塞互联。数据中心将其简化为两级:脊(Spine)叶(Leaf)

graph TB subgraph 叶层["Leaf 层(接入)"] L1["Leaf 1"] L2["Leaf 2"] L3["Leaf 3"] L4["Leaf 4"] end subgraph 脊层["Spine 层(核心)"] S1["Spine 1"] S2["Spine 2"] S3["Spine 3"] end S1 --- L1 S1 --- L2 S1 --- L3 S1 --- L4 S2 --- L1 S2 --- L2 S2 --- L3 S2 --- L4 S3 --- L1 S3 --- L2 S3 --- L3 S3 --- L4 subgraph 服务器["服务器"] SV1["Server 1"] --- L1 SV2["Server 2"] --- L1 SV3["Server 3"] --- L2 SV4["Server 4"] --- L3 SV5["Server 5"] --- L4 end

关键特征:每台 Leaf 与每台 Spine 全互联。这意味着任意两台 Leaf 之间都有 N 条路径(N = Spine 数量),不存在根节点瓶颈。

2.2 ECMP与路径多样性#

等价多路径路由(ECMP,Equal-Cost Multi-Path)是 CLOS 架构的灵魂。当有多条等代价路径到达同一目的地时,路由器将流量在多条路径上哈希分发:

# Linux 内核 ECMP 配置示例
# 添加两条等价路由
ip route add 10.0.2.0/24 nexthop via 10.0.1.1 dev eth1 weight 1 \
nexthop via 10.0.1.2 dev eth2 weight 1
# 查看路由表中的多路径
ip route show 10.0.2.0/24
# 10.0.2.0/24
# nexthop via 10.0.1.1 dev eth1 weight 1
# nexthop via 10.0.1.2 dev eth2 weight 1

ECMP 的哈希通常基于五元组(源IP、目的IP、源端口、目的端口、协议号),保证同一连接的数据包走同一条路径(避免乱序),不同连接的流量均匀分散。

路径多样性带来的好处:

  • 负载均衡:N 台 Spine 意味着 N 条等价路径,流量自然分散
  • 容错:一台 Spine 宕机,流量自动哈希到剩余路径,无需路由协议收敛
  • 可预测的过载比:1:1 的无阻塞网络只需 Leaf 和 Spine 端口数匹配即可

2.3 扩展特性#

CLOS 架构的扩展分两个维度:

横向扩展(增加服务器):增加 Leaf 交换机。新 Leaf 连接所有 Spine,立刻获得到其他 Leaf 的 N 条路径。前提是 Spine 有足够的空闲端口。

纵向扩展(增加带宽):增加 Spine 交换机。每增加一台 Spine,所有 Leaf 之间的路径数加一,东西向带宽线性增长。

一个简单的容量规划:假设 Leaf 有 48 个下行端口(连服务器)和 4 个上行端口(连 Spine),Spine 有 48 个端口。则最多支持 12 台 Spine(4×12=48),最多 48 台 Leaf(48 台 Leaf × 4 上行 = 192 端口,Spine 端口够用),支撑 48×48=2304 台服务器。过载比为 48:4 = 12:1。如果 Leaf 上行升级到 12 个端口,过载比降到 4:1。

特性传统三层架构CLOS 脊叶架构
拓扑结构树形(核心-汇聚-接入)扁平(Spine-Leaf 全互联)
交换机类型异构(核心昂贵、接入廉价)同构(均可使用相同型号)
东西向带宽受限于核心层过载比可达无阻塞(1:1 过载比)
路径数量少(依赖 STP 阻塞冗余路径)多(ECMP 利用所有等价路径)
扩展方式替换核心交换机(昂贵)增加 Spine/Leaf(线性成本)
故障影响范围核心故障=全局瘫痪单台 Spine/Leaf 故障=局部降级
收敛速度STP 收敛(秒~数十秒)ECMP 本地切换(毫秒级)

三、VXLAN与overlay网络#

3.1 VLAN的局限#

传统数据中心用 VLAN 做二层隔离,但 VLAN 有两个硬伤:

  • 标签空间太小:VLAN ID 只有 12 位,最多 4096 个标签。对于动辄几万租户的公有云来说远远不够
  • 跨数据中心困难:VLAN 是二层概念,跨越三层网络需要专门的二层延伸技术(如 VPLS),复杂且脆弱

更根本的问题是:数据中心的管理员需要灵活地创建、迁移、删除虚拟网络,而不受物理拓扑和 VLAN 标签数量的限制。这就催生了 overlay 网络——在物理网络(underlay)之上用隧道技术构建逻辑网络。

3.2 VXLAN封装#

VXLAN(Virtual eXtensible LAN,RFC 7348)是最广泛使用的 overlay 封装技术。它在 UDP 数据报里封装完整的二层以太网帧,用 24 位的 VNI(VXLAN Network Identifier)替代 12 位的 VLAN ID,标签空间从 4096 扩展到 16777216。

packet-beta title VXLAN 封装格式 0-6: "外层以太网头部" 7-14: "外层 IPv4/IPv6 头部" 15-18: "外层 UDP 头部<br/>dst port: 4789" 19-22: "VXLAN 头部<br/>Flags + VNI(24bit)" 23-30: "内层以太网帧<br/>(原始MAC帧)" 31-34: "内层载荷<br/>(IP包)"

VXLAN 封装的几个关键设计决策:

  • UDP 封装:利用底层网络(underlay)的 IP 路由和 ECMP 负载均衡。外层 UDP 源端口由内层五元组哈希生成,使得不同连接的 VXLAN 隧道流量可以在 underlay 的 ECMP 路径上均匀分布
  • 目的端口 4789:IANA 分配的 VXLAN 标准端口(有些实现用 8472,这是早期的非标准端口)
  • VNI 24 位:约 1677 万个虚拟网络标识符,满足大规模多租户需求

3.3 VTEP与EVPN#

VTEP(VXLAN Tunnel Endpoint)是 VXLAN 隧道的端点,负责封装和解封装。VTEP 可以是物理交换机、虚拟交换机(如 OVS)或软件实现(如 Linux 内核的 vxlan 接口)。

# Linux 创建 VXLAN 接口
ip link add vxlan0 type vxlan \
id 10010 \ # VNI = 10010
dev eth0 \ # underlay 接口
dstport 4789 \ # UDP 目的端口
local 10.0.1.1 \ # 本端 VTEP IP
remote 10.0.2.1 # 对端 VTEP IP(点对点模式)
# 启动接口
ip link set vxlan0 up
# 将 VXLAN 接口加入网桥
ip link add br-vxlan type bridge
ip link set vxlan0 master br-vxlan
ip link set eth1 master br-vxlan # eth1 连接虚拟机/容器
ip link set br-vxlan up

点对点模式只能连接两个 VTEP,无法支撑大规模部署。实际生产环境使用 EVPN(Ethernet VPN,RFC 7432) 作为 VXLAN 的控制平面。EVPN 基于 BGP 的 MP-BGP 扩展,通过 BGP 路由通告来学习远端 MAC 和 IP 信息,替代传统泛洪学习:

  • Type 2 路由:通告 MAC/IP 绑定,替代传统 MAC 地址泛洪学习
  • Type 3 路由:通告 VTEP 的加入/离开,建立组播/泛洪的头部复制列表
  • Type 5 路由:通告 IP 前缀,支持 VXLAN 的三层网关
# FRR EVPN 配置示例
router bgp 65001
bgp router-id 10.0.1.1
neighbor fabric peer-group
neighbor fabric remote-as 65001
neighbor 10.0.0.2 peer-group fabric
neighbor 10.0.0.3 peer-group fabric
!
address-family l2vpn evpn
neighbor fabric activate
advertise-all-vnis
advertise-svi-ip
exit-address-family

3.4 VLAN与VXLAN对比#

特性VLANVXLAN
标签空间12 位,4096 个24 位,约 1677 万个
封装方式在以太网帧头插入 4 字节 tagUDP 封装整个以太网帧
跨三层网络不支持(纯二层)原生支持(overlay over IP)
控制平面依赖 MAC 泛洪学习EVPN(BGP 扩展)
物理拓扑依赖强依赖(同一 VLAN 需二层连通)解耦(underlay 提供三层可达即可)
多租户支持有限(标签不够)原生支持(每个租户独立 VNI)
MTU 影响无额外开销增加 50 字节头部,需调整 underlay MTU
Note

VXLAN 增加 50 字节头部(外层以太网 14 + 外层 IP 20 + 外层 UDP 8 + VXLAN 8 = 50),因此 underlay 网络的 MTU 需要至少设为 1550(1500 + 50)或更大,避免分片带来的性能损失。

四、SDN控制器#

4.1 控制平面分离#

传统网络设备把控制平面(决定怎么转发)和数据平面(执行转发)耦合在同一台设备里。每台交换机独立运行路由协议、独立计算转发表。这种分布式控制在数据中心面临挑战:

  • 配置复杂:上千台交换机需要逐一配置,人工操作容易出错
  • 策略不一致:分布式协议的收敛过程可能导致临时性的策略不一致
  • 流量调度困难:无法根据全局视图做精确的流量工程
  • 创新受限:新协议和新功能需要设备厂商支持,迭代周期长

SDN(Software-Defined Networking)的核心思想是把控制平面从交换机中抽出来,交给集中的控制器。交换机只保留数据平面,按照控制器下发的流表转发数据包。

4.2 OpenFlow协议#

OpenFlow 是 SDN 的南向接口协议,定义了控制器与交换机之间的通信标准。控制器通过 OpenFlow 向交换机下发流表规则,交换机按照流表匹配和转发数据包。

# OpenFlow 流表规则示例
# 匹配条件 动作 优先级
table=0,ip,nw_dst=10.0.1.0/24,output:1 priority=100
table=0,ip,nw_dst=10.0.2.0/24,output:2 priority=100
table=0,arp,arp_tpa=10.0.1.0/24,output:1 priority=200
table=0,tcp,tp_dst=80,output:3 priority=50
table=0,*,controller priority=0 # 默认上送控制器

每条流表规则包含:

  • 匹配字段:入端口、以太网头、IP 头、传输层头等
  • 动作:转发到指定端口、上送控制器、修改头部、丢弃等
  • 优先级:多条规则匹配时,优先级高的生效
  • 计数器:统计匹配的数据包数和字节数

4.3 OVS与SDN控制器#

OVS(Open vSwitch)是最广泛使用的开源虚拟交换机,支持 OpenFlow 和多种隧道协议:

# 创建 OVS 网桥
ovs-vsctl add-br br-sdn
# 添加物理端口
ovs-vsctl add-port br-sdn eth1
# 添加 VXLAN 隧道端口
ovs-vsctl add-port br-sdn vxlan0 \
-- set interface vxlan0 type=vxlan \
options:remote_ip=10.0.2.1 \
options:key=10010 \
options:dst_port=4789
# 设置 OpenFlow 控制器
ovs-vsctl set-controller br-sdn tcp:127.0.0.1:6653
# 查看流表
ovs-ofctl dump-flows br-sdn
# 手动下发流表规则
ovs-ofctl add-flow br-sdn "ip,nw_dst=10.0.1.0/24,actions=output:1"
ovs-ofctl add-flow br-sdn "ip,nw_dst=10.0.2.0/24,actions=output:2"
# 查看端口统计
ovs-ofctl dump-ports br-sdn

主流 SDN 控制器:

  • ONOS(Open Network Operating System):开源分布式 SDN 控制器,支持多南向协议,面向运营商和大型数据中心
  • ODL(OpenDaylight):Linux 基金会下的开源 SDN 控制器,模块化架构,插件丰富
  • Ryu:基于 Python 的轻量级 SDN 控制器框架,适合学习和原型开发
  • Faucet:基于 OpenFlow 的 SDN 控制器,用 YAML 声明式配置网络策略

4.4 SDN架构全景#

graph TB subgraph 应用层["应用层"] APP1["网络虚拟化"] APP2["流量工程"] APP3["安全策略"] APP4["负载均衡"] end subgraph 控制层["控制层(SDN 控制器)"] CTRL["集中控制器<br/>ONOS / ODL / Ryu"] NBI["北向接口<br/>REST API"] SBI["南向接口<br/>OpenFlow / NETCONF / OVSDB"] end subgraph 基础设施层["基础设施层(数据平面)"] SW1["交换机 1"] SW2["交换机 2"] SW3["交换机 3"] SW4["交换机 4"] end APP1 --> NBI APP2 --> NBI APP3 --> NBI APP4 --> NBI NBI --> CTRL CTRL --> SBI SBI --> SW1 SBI --> SW2 SBI --> SW3 SBI --> SW4

SDN 的三层架构:

  • 应用层:网络应用通过北向接口(通常是 REST API)向控制器请求网络服务
  • 控制层:控制器维护全局网络视图,计算转发策略,通过南向接口下发流表
  • 基础设施层:交换机按照流表执行数据包转发,不参与路由决策
Warning

SDN 控制器是整个网络的”大脑”,它的可用性直接决定网络可用性。生产环境必须部署控制器集群(通常 3 节点或 5 节点),使用 Raft/Paxos 等共识协议保证一致性,避免单点故障导致全网瘫痪。

五、负载均衡与服务网格#

5.1 四层与七层负载均衡#

请求到达数据中心后,需要在后端的多个服务器实例之间分发。负载均衡器就是数据中心的”交通指挥”。

四层负载均衡(L4 LB) 工作在传输层,基于 IP 和端口做转发决策。它只看五元组,不解析应用层协议,速度快、延迟低:

# nginx 四层负载均衡配置(stream 模块)
stream {
upstream backend_mysql {
# 简单轮询
server 10.0.1.10:3306;
server 10.0.1.11:3306;
server 10.0.1.12:3306;
}
server {
listen 3306;
proxy_pass backend_mysql;
proxy_connect_timeout 1s;
}
}

七层负载均衡(L7 LB) 工作在应用层,可以解析 HTTP 头部、URL、Cookie 等,做更精细的流量调度:

# nginx 七层负载均衡配置(http 模块)
http {
upstream backend_api {
# 加权轮询 + 健康检查
server 10.0.1.10:8080 weight=3 max_fails=2 fail_timeout=10s;
server 10.0.1.11:8080 weight=2 max_fails=2 fail_timeout=10s;
server 10.0.1.12:8080 weight=1 max_fails=2 fail_timeout=10s;
# 一致性哈希(基于客户端 IP)
# hash $remote_addr consistent;
}
server {
listen 80;
location /api/ {
proxy_pass http://backend_api;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static/ {
# 静态资源直接返回
root /var/www/static;
}
}
}

5.2 健康检查与一致性哈希#

健康检查确保流量只发给健康的后端实例。常见方式:

  • 主动检查:LB 定期向后端发送探测请求(HTTP GET /healthz、TCP SYN 等),连续失败 N 次则标记为不健康
  • 被动检查:LB 监控实际请求的响应状态,5xx 错误率超阈值则摘除实例

一致性哈希解决传统哈希在节点增减时大量重映射的问题。普通哈希(hash(key) % N)在节点数变化时几乎所有键都要重新映射,一致性哈希只在环上移动少量键:

  • 将哈希值空间组织成环(0 ~ 2^32-1)
  • 每个后端节点映射到环上的多个位置(虚拟节点)
  • 请求 key 映射到环上,顺时针找到最近的节点
  • 节点增减时只影响相邻节点间的键

5.3 L4与L7负载均衡对比#

特性L4 负载均衡L7 负载均衡
工作层级传输层(TCP/UDP)应用层(HTTP/gRPC)
调度粒度五元组(IP+端口)URL/Header/Cookie/内容
性能高(内核态转发,百万级 CPS)较低(需解析应用层,十万级 CPS)
延迟低(只改写地址,不解析载荷)较高(需等待应用层头部)
功能简单转发、DNAT路由、重写、限流、认证、缓存
典型实现LVS、IPVS、Katrannginx、HAProxy、Envoy、Traefik
连接终止不终止(直接转发)终止连接(两端独立 TCP)
适用场景数据库、Redis、MQ 等非 HTTP 协议HTTP API、Web 服务、gRPC

5.4 服务网格#

微服务架构下,服务间的通信变得复杂——服务发现、负载均衡、熔断、限流、可观测性、加密认证……如果每个服务自己实现这些功能,代码重复且难以统一管理。服务网格(Service Mesh)把这些能力从业务代码中剥离出来,下沉到基础设施层。

服务网格的核心模式是 Sidecar 代理:每个服务实例旁边部署一个代理进程(sidecar),拦截该实例的所有入站和出站流量。所有通信策略由控制平面统一管理,数据平面由 sidecar 执行。

graph LR subgraph 控制平面["控制平面(Control Plane)"] PILOT["Pilot<br/>配置分发"] CITADEL["Citadel<br/>证书管理"] GALLEY["Galley<br/>配置验证"] end subgraph 数据平面["数据平面(Data Plane)"] subgraph PodA["服务 A Pod"] SA["Service A"] --- CA["Envoy<br/>Sidecar"] end subgraph PodB["服务 B Pod"] SB["Service B"] --- CB["Envoy<br/>Sidecar"] end end CA -->|"mTLS"| CB PILOT -.->|配置下发| CA PILOT -.->|配置下发| CB CITADEL -.->|证书轮换| CA CITADEL -.->|证书轮换| CB

主流服务网格实现:

  • Istio:功能最全面的服务网格,控制平面包含 Pilot(流量管理)、Citadel(安全)、Galley(配置),数据平面使用 Envoy 作为 sidecar
  • Linkerd:轻量级服务网格,Rust 编写的 sidecar 代理,资源开销小,适合对性能敏感的场景
# Istio VirtualService 配置示例:按版本路由
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
x-user-type:
exact: premium
route:
- destination:
host: reviews
subset: v2
weight: 100
- route:
- destination:
host: reviews
subset: v1
weight: 90
- destination:
host: reviews
subset: v2
weight: 10

服务网格与 Kubernetes 的配合:Kubernetes 的 Service 提供基本的负载均衡(iptables/IPVS),服务网格在此基础上增加七层路由、熔断、mTLS、可观测性等能力。两者互补而非替代。

六、动手实践:Mininet SDN实验#

6.1 Mininet拓扑#

Mininet 是一个轻量级网络仿真平台,在一台机器上创建包含主机、交换机、控制器的虚拟网络拓扑。它利用 Linux 网络命名空间实现隔离,所有节点共享内核,性能接近真实网络。

# 安装 Mininet
sudo apt install mininet
# 启动默认拓扑(1 交换机 + 2 主机)
sudo mn
# 启动自定义拓扑
sudo mn --topo tree,depth=2,fanout=3 --controller=remote,ip=127.0.0.1,port=6653
# Mininet 交互命令
# mininet> nodes # 查看所有节点
# mininet> links # 查看所有链路
# mininet> h1 ping h2 # 主机间 ping
# mininet> iperf h1 h2 # 测量带宽
# mininet> dump # 导出节点信息

用 Python 脚本创建自定义 CLOS 拓扑:

#!/usr/bin/env python3
"""Mininet CLOS 脊叶拓扑实验"""
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import RemoteController
from mininet.cli import CLI
class CLOSTopo(Topo):
"""2 Spine + 4 Leaf 的 CLOS 拓扑"""
def build(self):
# 创建 Spine 交换机
s1 = self.addSwitch('s1') # Spine 1
s2 = self.addSwitch('s2') # Spine 2
# 创建 Leaf 交换机和主机
for i in range(1, 5):
leaf = self.addSwitch(f'l{i}')
# 每台 Leaf 下挂 2 台主机
for j in range(1, 3):
host = self.addHost(f'h{i}{j}',
ip=f'10.0.{i}.{j}/24')
self.addLink(host, leaf)
# Leaf 与所有 Spine 全互联
self.addLink(leaf, s1)
self.addLink(leaf, s2)
if __name__ == '__main__':
topo = CLOSTopo()
net = Mininet(topo=topo,
controller=RemoteController('ryu', ip='127.0.0.1',
port=6653))
net.start()
CLI(net)
net.stop()

6.2 OVS流表操作#

Mininet 默认使用 OVS 作为交换机。当没有控制器时,交换机的流表为空,所有数据包被丢弃。需要手动下发流表规则:

# 查看 OVS 网桥
ovs-vsctl show
# 查看交换机 s1 的流表(初始为空)
ovs-ofctl dump-flows s1
# 下发 L2 学习交换规则(将 s1 配置为学习交换机)
# 匹配所有包,泛洪到除入端口外的所有端口
ovs-ofctl add-flow s1 "priority=1,actions=flood"
# 更精细的规则:基于目的 MAC 转发
ovs-ofctl add-flow s1 "priority=10,dl_dst=00:00:00:00:00:01,actions=output:1"
ovs-ofctl add-flow s1 "priority=10,dl_dst=00:00:00:00:00:02,actions=output:2"
# 下发 L3 路由规则
ovs-ofctl add-flow l1 "priority=100,ip,nw_dst=10.0.1.0/24,actions=output:1"
ovs-ofctl add-flow l1 "priority=100,ip,nw_dst=10.0.2.0/24,actions=output:2"
# 查看流表统计(匹配计数)
ovs-ofctl dump-flows s1
# NXST_FLOW reply:
# cookie=0x0, duration=10.5s, table=0, n_packets=42, n_bytes=3864,
# priority=10,dl_dst=00:00:00:00:00:01 actions=output:1
# 删除流表规则
ovs-ofctl del-flows s1 "dl_dst=00:00:00:00:00:01"
# 清空所有流表
ovs-ofctl del-flows s1

6.3 Ryu控制器#

Ryu 是一个基于 Python 的 SDN 控制器框架,适合学习和快速原型开发。下面实现一个简单的 L2 学习交换机控制器:

#!/usr/bin/env python3
"""Ryu L2 学习交换机控制器"""
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
class L2Switch(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.mac_to_port = {} # {dpid: {mac: port}}
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
"""交换机连接时下发默认规则:未知包上送控制器"""
datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
def add_flow(self, datapath, priority, match, actions):
"""向交换机下发流表规则"""
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
inst = [parser.OFPInstructionActions(
ofproto.OFPIT_APPLY_ACTIONS, actions)]
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
"""处理上送的数据包:学习源 MAC,转发目的 MAC"""
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
dpid = datapath.id
# 获取入端口
in_port = msg.match['in_port']
# 解析以太网头部
pkt = msg.data
dl_src = pkt[6:12].hex() # 源 MAC
dl_dst = pkt[0:6].hex() # 目的 MAC
# 学习源 MAC
self.mac_to_port.setdefault(dpid, {})
self.mac_to_port[dpid][dl_src] = in_port
# 查找目的 MAC
out_port = self.mac_to_port[dpid].get(dl_dst, ofproto.OFPP_FLOOD)
# 下发精确匹配规则(后续同流量的包不再上送控制器)
actions = [parser.OFPActionOutput(out_port)]
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dl_dst)
self.add_flow(datapath, 1, match, actions)
# 发送当前数据包
out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
in_port=in_port, actions=actions)
datapath.send_msg(out)

运行实验:

# 终端 1:启动 Ryu 控制器
ryu-manager l2_switch.py --ofp-tcp-listen-port 6653
# 终端 2:启动 Mininet 拓扑,连接 Ryu 控制器
sudo python3 clos_topo.py
# Mininet 终端内测试
# mininet> h11 ping h21
# mininet> h11 iperf -c h21
# 终端 3:观察流表变化
watch -n 1 'ovs-ofctl dump-flows s1 | tail -5'

6.4 流表检查与排错#

# 查看交换机与控制器的连接状态
ovs-vsctl get-controller s1
# "tcp:127.0.0.1:6653"
# 查看流表匹配统计,定位流量是否按预期转发
ovs-ofctl dump-flows l1 --stats
# 注意 n_packets 和 n_bytes 字段
# 抓包分析 OpenFlow 消息
sudo tcpdump -i lo -w of.pcap tcp port 6653
# 查看交换机端口状态
ovs-ofctl show l1
# 模拟链路故障
ovs-ofctl mod-port l1 2 down # 关闭端口
ovs-ofctl mod-port l1 2 up # 恢复端口

七、本章小结#

主题核心概念关键技术
数据中心演进东西向流量增长、过载比瓶颈三层树形 → CLOS 脊叶
CLOS 架构全互联、无阻塞、线性扩展Spine-Leaf、ECMP、路径多样性
VXLAN overlay多租户隔离、跨三层二层延伸VNI、VTEP、EVPN 控制平面
SDN 控制控制平面集中化、可编程网络OpenFlow、OVS、ONOS/ODL/Ryu
负载均衡流量分发、健康检查、会话保持L4/L7 LB、一致性哈希
服务网格通信能力下沉、sidecar 代理Istio、Linkerd、Envoy、mTLS

数据包的旅程至此抵达了终点——数据中心。从 以太网与交换 的 MAC 帧转发,到 IP地址与子网 的三层寻址,到 BGP与域间路由 的跨域选路,到 TCP连接管理 的可靠传输,到 HTTP协议演进 的应用层协议,到 CDN与内容分发 的边缘加速——数据包穿越了整个互联网协议栈,最终到达了运行在数据中心里的服务器进程。

但数据包的旅程并不总是发生在有线网络中。下一章 无线与异构接入 将转向另一个维度:数据包如何通过 WiFi 的 CSMA/CA 竞争信道、5G 的 OFDMA 调度、低轨卫星的跨波束切换,从无线接入网抵达终端用户。


参考#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

数据中心与SDN网络:数据包的终点与控制
https://blog.souloss.com/posts/internet-architecture/data-center-and-sdn-networking/
作者
Souloss
发布于
2022-09-15
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时