文集文档索引

OpenFlow


  • 文集信息
  • 目录大纲
  • 最新文档
  • 知识宇宙

文集详情

文集导读

OpenFlow OpenFlow 协议详解与实践 OpenFlow 协议概述 OpenFlow 是一种网络交换协议,它允许软件定义网络(SDN)控制器直接访问和控制网络设备的转发平面。 传统的网络设备,如交换机和路由器,其控制平面和数据平面紧密耦合。 OpenFlow 将这两个平面分离,使得控制平面可以在一个集中的控制器上实现,而数据平面则由网络设备执行。 这种分离带来了极大的灵活性和可编程性,使得网络管理和创新变得更加容易。 1.1 核心概念 Flow Table (流表): OpenFlow 交换机的核心组件,包含一系列流条目(Flow Entry)。每个流条目定义了如何处理特定类型的网络流量。 Flow Entry (流条目): 由匹配规则(Match Fields)、指令集(Instructions)和统计信息(Counters)组成。 Match Fields: 用于匹配特定类型的网络流量,例如源/目的 MAC 地址、IP 地址、端口号等。 Instructions: 定义了匹配流量后要执行的操作,例如转发到特定端口、修改 VLAN ID、丢弃等。 Counters: 用于记录匹配流量的统计信息,例如匹配的包数量和字节数量。 Secure Channel (安全通道): OpenFlow 交换机与控制器之间的安全通信通道,通常使用 TLS 协议。

OpenFlow

OpenFlow 协议详解与实践

1. OpenFlow 协议概述

OpenFlow 是一种网络交换协议,它允许软件定义网络(SDN)控制器直接访问和控制网络设备的转发平面。 传统的网络设备,如交换机和路由器,其控制平面和数据平面紧密耦合。 OpenFlow 将这两个平面分离,使得控制平面可以在一个集中的控制器上实现,而数据平面则由网络设备执行。 这种分离带来了极大的灵活性和可编程性,使得网络管理和创新变得更加容易。

1.1 核心概念

  • Flow Table (流表): OpenFlow 交换机的核心组件,包含一系列流条目(Flow Entry)。每个流条目定义了如何处理特定类型的网络流量。

  • Flow Entry (流条目): 由匹配规则(Match Fields)、指令集(Instructions)和统计信息(Counters)组成。

    • Match Fields: 用于匹配特定类型的网络流量,例如源/目的 MAC 地址、IP 地址、端口号等。

    • Instructions: 定义了匹配流量后要执行的操作,例如转发到特定端口、修改 VLAN ID、丢弃等。

    • Counters: 用于记录匹配流量的统计信息,例如匹配的包数量和字节数量。

  • Secure Channel (安全通道): OpenFlow 交换机与控制器之间的安全通信通道,通常使用 TLS 协议。

  • OpenFlow Controller (OpenFlow 控制器): 负责管理和配置 OpenFlow 交换机的流表,并收集网络状态信息。

1.2 工作原理

  1. 当 OpenFlow 交换机收到一个数据包时,它首先会在流表中查找匹配的流条目。

  2. 如果找到匹配的流条目,交换机将按照流条目中定义的指令处理该数据包。

  3. 如果没有找到匹配的流条目,交换机可以将该数据包发送到控制器进行处理(Packet-In 消息),或者按照默认行为(例如丢弃)处理。

  4. 控制器收到 Packet-In 消息后,可以根据网络策略决定如何处理该数据包,并向交换机下发新的流条目,以便后续流量可以直接在交换机上处理。

1.3 协议版本

OpenFlow 协议有多个版本,常见的版本包括 OpenFlow 1.0、1.3 和 1.5。 不同版本之间存在一些差异,例如支持的匹配字段、指令集和消息类型。

2. OpenFlow 协议详解

2.1 流表结构

流表由多个流条目组成,每个流条目包含以下字段:

  • Priority (优先级): 用于确定流条目的匹配顺序。 优先级较高的流条目会优先匹配。

  • Match Fields (匹配字段): 用于匹配特定类型的网络流量。 常见的匹配字段包括:

    • in_port: 入口端口

    • eth_dst: 目的 MAC 地址

    • eth_src: 源 MAC 地址

    • eth_type: 以太网类型

    • vlan_id: VLAN ID

    • ip_src: 源 IP 地址

    • ip_dst: 目的 IP 地址

    • ip_proto: IP 协议

    • tcp_src: TCP 源端口

    • tcp_dst: TCP 目的端口

    • udp_src: UDP 源端口

    • udp_dst: UDP 目的端口

  • Instructions (指令): 定义了匹配流量后要执行的操作。 常见的指令包括:

    • GOTO_TABLE: 跳转到另一个流表

    • WRITE_METADATA: 写入元数据

    • APPLY_ACTIONS: 应用动作

    • CLEAR_ACTIONS: 清除动作

    • WRITE_ACTIONS: 写入动作

    • METER: 应用 Meter

  • Actions (动作): 用于修改数据包或执行转发操作。 常见的动作包括:

    • OUTPUT: 转发到指定端口

    • SET_FIELD: 修改数据包头部字段

    • PUSH_VLAN: 添加 VLAN 标签

    • POP_VLAN: 移除 VLAN 标签

    • GROUP: 转发到组表

  • Counters (计数器): 用于记录匹配流量的统计信息。

2.2 OpenFlow 消息类型

OpenFlow 协议定义了多种消息类型,用于控制器和交换机之间的通信。 主要消息类型包括:

  • Controller-to-Switch Messages (控制器到交换机消息):

    • Features Request/Reply: 用于查询交换机的能力。

    • Configuration Messages: 用于配置交换机的参数。

    • Modify State Messages: 用于添加、修改或删除流条目。

    • Packet-Out: 用于从控制器发送数据包到交换机。

    • Barrier Request/Reply: 用于确保消息的顺序执行。

    • Role Request/Reply: 用于设置控制器的角色。

  • Switch-to-Controller Messages (交换机到控制器消息):

    • Packet-In: 用于将未匹配的数据包发送到控制器。

    • Flow Removed: 用于通知控制器流条目被移除。

    • Port Status: 用于通知控制器端口状态的变化。

    • Error: 用于通知控制器发生的错误。

2.3 协议流程示例

以下是一个简单的 OpenFlow 协议流程示例:

3. OpenFlow 代码实践 (Python + Mininet + Ryu)

本节将使用 Python 编程语言,结合 Mininet 网络仿真器和 Ryu OpenFlow 控制器,演示如何编写 OpenFlow 程序。

3.1 环境搭建

  1. 安装 Mininet:

    sudo apt-get update sudo apt-get install mininet
  2. 安装 Ryu:

    sudo apt-get install python3-pip sudo pip3 install ryu

3.2 编写 Ryu 控制器

以下是一个简单的 Ryu 控制器,用于实现一个 Hub 功能:

from ryu.base import app_manager from ryu.controller import ofp_event from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER from ryu.controller.handler import set_ev_cls from ryu.ofproto import ofproto_v1_3 from ryu.lib.packet import packet from ryu.lib.packet import ethernet class SimpleSwitch13(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] def __init__(self, *args, **kwargs): super(SimpleSwitch13, self).__init__(*args, **kwargs) self.mac_to_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 # install the table-miss flow entry. # # We specify NO BUFFER to drop the packet regarding table-miss # unless you have reasons to send the packet to the controller. 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, buffer_id=None): ofproto = datapath.ofproto parser = datapath.ofproto_parser inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)] if buffer_id: mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, priority=priority, match=match, instructions=inst) else: 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): # If you hit this you might want to increase # the "miss_send_length" of the switch if ev.msg.msg_len < ev.msg.total_len: self.logger.debug("packet truncated: only %s of %s bytes", ev.msg.msg_len, ev.msg.total_len) msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser in_port = msg.match['in_port'] pkt = packet.Packet(msg.data) eth = pkt.get_protocols(ethernet.ethernet)[0] dst = eth.dst src = eth.src dpid = datapath.id self.mac_to_port.setdefault(dpid, {}) self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port) # learn a mac address to avoid FLOOD next time. self.mac_to_port[dpid][src] = in_port if dst in self.mac_to_port[dpid]: out_port = self.mac_to_port[dpid][dst] else: out_port = ofproto.OFPP_FLOOD actions = [parser.OFPActionOutput(out_port)] # install a flow to avoid packet_in next time if out_port != ofproto.OFPP_FLOOD: match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) # verify if we have a valid buffer_id, if yes avoid to send both # flow_mod & packet_out if msg.buffer_id != ofproto.OFP_NO_BUFFER: self.add_flow(datapath, 1, match, actions, msg.buffer_id) return else: self.add_flow(datapath, 1, match, actions) data = None if msg.buffer_id == ofproto.OFP_NO_BUFFER: data = msg.data out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, in_port=in_port, actions=actions, data=data) datapath.send_msg(out)

将上述代码保存为 simple_switch_13.py

3.3 运行 Mininet 拓扑

创建一个简单的 Mininet 拓扑:

from mininet.net import Mininet from mininet.node import Controller, RemoteController from mininet.cli import CLI from mininet.log import setLogLevel, info def create_topo(): net = Mininet(topo=None, build=False, ipBase='10.0.0.0/8') info('*** Adding controller\n') c0 = net.addController(name='c0', controller=RemoteController, ip='127.0.0.1', port=6633) info('*** Adding switches\n') s1 = net.addSwitch('s1', cls=OVSKernelSwitch) info('*** Adding hosts\n') h1 = net.addHost('h1', cls=Host, ip='10.0.0.1/8', defaultRoute=None) h2 = net.addHost('h2', cls=Host, ip='10.0.0.2/8', defaultRoute=None) info('*** Creating links\n') net.addLink(h1, s1) net.addLink(h2, s1) return net if __name__ == '__main__': setLogLevel('info') net = create_topo() net.start() CLI(net) net.stop()

将上述代码保存为 topo.py

3.4 运行程序

  1. 启动 Ryu 控制器:

    ryu-manager simple_switch_13.py
  2. 启动 Mininet 拓扑:

    sudo python3 topo.py
  3. 在 Mininet CLI 中,尝试从 h1 ping h2

    mininet> h1 ping h2

如果一切正常,h1 应该能够成功 ping 通 h2。 这个简单的例子展示了如何使用 OpenFlow 和 Ryu 来控制网络流量。

4. 总结

OpenFlow 协议是 SDN 的核心组成部分,它通过将控制平面和数据平面分离,实现了网络的灵活性和可编程性。 通过使用 OpenFlow,网络管理员可以更加方便地管理和配置网络,并实现各种创新的网络应用。 本文详细介绍了 OpenFlow 协议的原理、结构和消息类型,并提供了一个使用 Python、Mininet 和 Ryu 的 OpenFlow 实践示例。 掌握 OpenFlow 协议对于理解和应用 SDN 技术至关重要。

目录大纲

    最新文档

    知识宇宙

    正在加载知识图谱...


    转发