• Openflow协议详解


    来自:http://www.h3c.com/cn/d_201811/1131080_30005_0.htm

    1 OpenFlow背景

    转发和控制分离是SDN网络的本质特点之一 。在SDN网络架构中,控制平面与转发平面分离,网络的管理和状态在逻辑上集中到一起,底层的网络基础从应用中独立出来,由此,网络获得前所未有的可编程、可控制和自动化能力。这使用户可以很容易根据业务需求,建立高度可扩展的弹性网络。要实现SDN网络的转控分离架构,就需要在SDN控制器与数据转发层之间建立一个通信接口标准。

    2008年,斯坦福大学成立了一个名为Clean Slate的特别工作小组,这个小组在2009年开发出了一个可以满足SDN网络转控分离架构的标准,即OpenFlow 1.0。同时该小组还开发出了OpenFlow的参考交换机和NOX控制器。OpenFlow标准协议允许控制器直接访问和操作网络设备的转发平面,这些设备可以是物理设备,也可以是虚拟的路由器或者交换机。转发平面则采用基于流的方式进行转发。

    OpenFlow 1.0问世后不久就引起了业界关注。2011年3月21日,德国电信、脸书、谷歌、微软、雅虎等公司共同成立的了ONF(Open Networking Foundation)组织,旨在推广SDN,并加大OpenFlow的标准化力度。芯片商Broadcom,设备商Cisco、Juniper、HP等,各数据中心解决方案提供者以及众多运营商纷纷参与。该组织陆续制定了OpenFlow 1.1、1.2、1.3、1.4等标准,目前仍在继续完善中。随着越来越多的公司加入ONF,OpenFlow及SDN技术的影响力也越来越大。

    图1给出了OpenFlow协议各个版本的演进过程和主要变化,目前使用和支持最多的是OpenFlow1.3版本。

     

    图1 OpenFlow版本

     

    2 OpenFlow基本概念

    2.1 OpenFlow组件

    OpenFlow网络由OpenFlow网络设备(OpenFlow 交换机)、控制器(OpenFlow控制器)、用于连接设备和控制器的安全通道(Secure Channel)以及OpenFlow表项组成。其中,OpenFlow 交换机设备和OpenFlow控制器是组成OpenFlow网络的实体,要求能够支持安全信道和OpenFlow表项。

     

    图2 OpenFlow组件

    2.1.1 OpenFlow控制器

    OpenFlow控制器位于SDN架构中的控制层,通过OpenFlow协议南向指导设备的转发。目前主流的OpenFlow控制器分为两大类:开源控制器和厂商开发的商用控制器。这里简要介绍几款较为知名的开源控制器。

    1、NOX/POX

    NOX是第一款真正的SDN OpenFlow控制器,由Nicira公司在08年开发,并且捐赠给了开源组织。NOX支持OpenFlow V1.0,并提供相关C++的API,采用异步的、基于时间的编程模型。而POX可以视作是更新的、基于Python的NOX版本,支持Windows,Mac OS和Linux系统上的Python开发,主要用于研究和教育领域。

    2、ONOS

    ONOS(Open Network Operating System)控制器是由The Open Networking Lab使用Java及Apache实现发布的首款开源SDN网络操作系统,主要面向服务提供商和企业骨干网。ONOS的设计宗旨是实现可靠性强、性能好、灵活度高的SDN控制器。

    3、OpenDaylight

    OpenDaylight是一个Linux 基金合作项目,该项目以开源社区为主导,使用Java语言实现开源框架,旨在推动创新实施以及软件定义网络透明化。面对SDN型网络,OpenDaylight作为项目核心,拥有一套模块化、可插拔且极为灵活的控制器,还包含一套模块合集,能够执行需要快速完成的网络任务。OpenDaylight控制器的命名以化学元素为名,最初的产品是Hydrogen(氢),当前已经发布了第八个版本Oxygen(氧),并且实现了OpenDaylight与NFV开放平台OPNFV(Open Platform for NFV)、开源云平台OpenStack和开放网络自动化平台ONAP(Open Network Automation Platform)同步。

    大多数开源的SDN控制器是完全基于OpenFlow协议开发的,这是因为其设计多数源自于Onix(一种分布式控制器框架)。相比之下,大部分商用控制器会将OpenFlow和其他协议进行联合使用,以完成更复杂的功能。在当下SDN网络大行其道的时代,大多数主流网络厂商例如VMware、Cisco、H3C等都推出了自己的商用控制器。例如,H3C的VCFC(Virtual Converged Framework Controller,虚拟应用融合架构控制器)南向通过OpenFlow、OVSDB、NETCONF协议对SDN网络设备(主要是OpenFlow交换机)进行管控和指导转发,北向提供开放的Rest API以及JAVA编程接口。整体架构如下所示:

     

    图3 VCFC整体架构

    2.1.2 OpenFlow交换机

    OpenFlow交换机由硬件平面上的OpenFlow表项和软件平面上的安全通道构成,OpenFlow表项为OpenFlow的关键组成部分,由Controller下发来实现控制平面对转发平面的控制。

    OpenFlow 交换机主要有下面两种:

    • OpenFlow-Only Switch:仅支持OpenFlow转发。

    • OpenFlow-Hybrid Switch:既支持OpenFlow转发,也支持普通二三层转发。

    一个OpenFlow交换机可以有若干个OpenFlow实例,每个OpenFlow实例可以单独连接控制器,相当于一台独立的交换机,根据控制器下发的流表项指导流量转发。OpenFlow实例使得一个OpenFlow交换机同时被多组控制器控制成为可能。

     

    图4 OpenFlow交换机与控制器

    OpenFlow交换机实际在转发过程中,依赖于OpenFlow表项,转发动作则是由交换机的OpenFlow接口完成。OpenFlow接口有下面三类。

    物理接口:比如交换机的以太网口等。可以作为匹配的入接口和出接口。

    逻辑接口:比如聚合接口、Tunnel接口等。可以作为匹配的入接口和出接口。

    保留接口:由转发动作定义的接口,实现OpenFlow转发功能。

    2.2 OpenFlow表项详解

    OpenFlow的表项在V1.0阶段,只有普通的单播表项,也即我们通常所说的OpenFlow流表。随着OpenFlow协议的发展,更多的OpenFlow表项被添加进来,如组表(Group Table),计量表(Meter Table)等,以实现更多的转发特性以及QoS功能。

    2.2.1 OpenFlow流表

    狭义的OpenFlow流表是指OpenFlow单播表项,广义的OpenFlow流表则包含了所有类型的OpenFlow表项。OpenFlow通过用户定义的流表来匹配和处理报文。所有流表项都被组织在不同的Flow Table中,在同一个Flow Table中按流表项的优先级进行先后匹配。一个OpenFlow的设备可以包含一个或者多个Flow Table。

    1、流表项组成

    一条OpenFlow的表项(Flow Entry)由匹配域(Match Fields)、优先级(Priority)、处理指令(Instructions)和统计数据(如Counters)等字段组成,流表项的结构随着OpenFlow版本的演进不断丰富,不同协议版本的流表项结构如下。

     

    图5 流表项组成

    (1)Match Fields

    流表项匹配规则,可以匹配入接口、物理入接口,流表间数据,二层报文头,三层报文头,四层端口号等报文字段等。

    (2)Priority

    流表项优先级,定义流表项之间的匹配顺序,优先级高的先匹配。

    (3)Counters

    流表项统计计数,统计有多少个报文和字节匹配到该流表项。

    (4)Instructions & Actions

    流表项动作指令(Instructions & Actions)集,定义匹配到该流表项的报文需要进行的处理。当报文匹配流表项时,每个流表项包含的指令集就会执行。这些指令会影响到报文、动作集以及管道流程。 交换机不需要支持所有的指令类型,并且控制器可以询问OpenFlow交换机所支持的指令类型。 具体的指令类型参见下表:

    Instruction

    处理

    Meter

    对匹配到流表项的报文进行限速

    Apply-Actions

    立即执行Action

    Clear-Actions

    清除动作集(Action Set)中的所有Action。

    Write-Actions

    更改动作集(Action Set)中的所有Action。

    Write-Metadata

    更改流表间数据,在支持多级流表时使用。

    Goto-Table

    进入下一级流表。

    表1流表项动作指令

    每个流表表项的指令集中每种指令类型最多只能有一个,指令的执行的优先顺序为:

    Meter –> Apply-Actions -> Clear Actions -> Write-Actions -> Write-Metadata -> Goto-Table

    当OpenFlow交换机无法执行某个流表项中的动作时,该交换机可以拒绝这个流表项,并向Controller返回unsupported flow error 信息。

    常见Action动作的类型如下:

    必选的

    Output

    转发到指定的OpenFlow端口

    Drop

    无直接动作,指令集中无output动作则丢弃该报文

    Group

    处理报文到指定Group

    可选的

    Set-Queue

    设置报文的队列id

    Push-Tag/Pop-Tag

    写入/弹出标签 例如VLAN, MPLS等

    Set-Field

    修改报文的头字段

    Change-TTL

    修改TTL,Hop Limit等字段

    表2 Action动作

    (5)Timeouts

    流表项的超时时间,包括了Idle Time和Hard Time。

    Idle Time:在Idle Time时间超时后如果没有报文匹配到该流表项,则此流表项被删除。

    Hard Time:在Hard Time时间超时后,无论是否有报文匹配到该流表项,此流表项都会被删除。

    (6)Cookie

    Controller下发的流表项的标识

    2、流表处理流程

    OpenFlow规范中定义了流水线式的处理流程,报文匹配处理流程如下图所示:

     

    图6 流表处理流程

    当报文进入Switch后,必须从最小的Flow Table开始依次匹配。Flow Table可以按次序从小到大越级跳转,但不能从某一Flow Table向前跳转至编号更小的Flow Table。当报文成功匹配一条Flow Entry后,将首先更新该Flow Entry对应的统计数据(如成功匹配数据包总数目和总字节数等),然后根据Flow Table中的指令进行相应操作,比如跳转至后续某一Flow Table继续处理,修改或者立即执行该数据包对应的Action Set等。当数据包已经处于最后一个Flow Table时,其对应的Action Set中的所有Action将被执行,包括转发至某一端口,修改数据包某一字段,丢弃数据包等。具体实现时,OpenFlow交换机还需要对匹配表项次数进行计数、更新匹配集和元数据等操作。

     

    图7 流表匹配流程

    3、Table Miss表项

    每个流表(Flow Table)都包含一个Table Miss流表项,该表项用于定义在流表中没有匹配的报文的处理方式,该表项的匹配域为通配,即匹配任何报文,优先级为0,Instructions与正常表项相同。通常,如果Table-Miss表项不存在,默认行为是丢弃报文。

    4、Flow Remove

    Flow Entry可以由Controller通过OpenFlow消息进行删除,也可以在Idle Time超时或者Hard Time超时后自动删除。Idle Time超时有两种情况:某个流表表项长时间不匹配报文则idle_timeout字段设置为非0;某个流表表项一定时间过后,无论是否匹配报文 hard_timeout字段设置为非0。如果Controller在建立表项时,携带了Flow Remove标记,则表项在删除时,设备需要通知Controller Flow Remove消息。

    2.2.2 OpenFlow组表

    OpenFlow组表的表项被流表项(Flow Entry)所引用,提供组播报文转发功能。一系列的Group表项组成了Group Table,每个表项结构如图:

     

    图8 OpenFlow组表

    根据Group ID可检索到相应Group表项,每个Group表项包含多个动作Bucket,每个Bucket包含多个动作,Bucket内的动作执行顺序依照Action Set的顺序。

    2.2.3 OpenFlow Meter表

    Meter计量表项被流表项(Flow Entry)所引用,为所有引用Meter表项的流表项提供报文限速的功能。一系列的Meter表项组成了Meter Table, 每个Meter表项的组织结构如下:

     

    图9 OpenFlow计量表

    一个Meter表项可以包含一个或者多个Meter Bands,每个Meter Band定义了速率以及动作,报文的速率超过了某些MeterBand,根据这些MeterBand中速率最大的那个定义的动作进行处理。

    2.3 OpenFlow安全通道

    OpenFlow设备与Controller通过建立OpenFlow信道,进行OpenFlow消息交互,实现表项下发,查询以及状态上报等功能。通过OpenFlow信道的报文都是根据OpenFlow协议定义的,通常采用TLS(Transport Layer Security)加密,但也支持简单的TCP直接传输。如果安全通道采用TLS连接加密,当交换机启动时,会尝试连接到控制器的6633 TCP端口(Openflow端口通常默认建议设置为6633)。双方通过交换证书进行认证。因此,在加密时,每个交换机至少需配置两个证书。

    3 OpenFlow运行机制

    3.1 OpenFlow信道建立

    3.1.1 OpenFlow消息类型

    要了解OpenFlow信道的建立过程,首先需要了解OpenFlow协议目前支持的三种报文类型:

    1、Controller to Switch消息

    由Controller发起、Switch接收并处理的消息。这些消息主要用于Controller对Switch进行状态查询和修改配置等管理操作,可能不需要交换机响应。

     

    图10 Controller to Switch

    Controller to Switch消息主要包含以下几种类型:

    l Features:用于控制器发送请求来了解交换机的性能,交换机必须回应该报文。

    l Modify-State:用于管理交换机的状态,如流表项和端口状态。该命令主要用于增加、删除、修改OpenFlow交换机内的流表表项,组表表项以及交换机端口的属性。

    l Read-State:用于控制器收集交换机各方面的信息,例如当前配置,统计信息等 。

    l Flow-Mod:Flow-Mod消息用来添加、删除、修改OpenFlow交换机的流表信息。Flow-Mod消息共有五种类型:ADD、DELETE、DELETE-STRICT、MODIFY、MODIFY-STRICT。

    l Packet-out:用于通过交换机特定端口发送报文 ,这些报文是通过Packet-in消息接收到的。通常Packet-out消息包含整个之前接收到的Packet-in消息所携带的报文或者buffer ID(用于指示存储在交换机内的特定报文)。这个消息需要包含一个动作列表,当OpenFlow交换机收到该动作列表后会对Packet-out消息所携带的报文执行该动作列表。如果动作列表为空,Packet-out消息所携带的报文将被OpenFlow交换机丢弃。

    l Asynchronous-Configuration:控制器使用该报文设定异步消息过滤器来接收其只希望接收到的异步消息报文,或者向OpenFlow交换机查询该过滤器。该消息通常用于OpenFlow交换机和多个控制器相连的情况。

    2、异步(Asynchronous)消息

    由Switch发送给Controller,用来通知Switch上发生的某些异步事件的消息,主要包括Packet-in、Flow-Removed、Port-Status和Error等。例如,当某一条规则因为超时而被删除时,Switch将自动发送一条Flow-Removed消息通知Controller,以方便Controller作出相应的操作,如重新设置相关规则等。

     

    图11 Switch to Controller

    异步消息具体包含以下几种类型:

    l Packet-in:转移报文的控制权到控制器。对于所有通过匹配流表项或者Table Miss后转发到Controller端口的报文均要通过Packet-in消息送到Controller。也有部分其他流程(如TTL检查等)也需要通过该消息和Controller交互。Packet-in既可以携带整个需要转移控制权的报文,也可以通过在交换机内部设置报文的Buffer来仅携带报文头以及其Buffer ID传输给Controller。Controller在接收到Packet-in消息后会对其接收到的报文或者报文头和Buffer ID进行处理,并发回Packet-out消息通知OpenFlow交换机如何处理该报文。

    l Flow-Removed:通知控制器将某个流表项从流表的移除。通常该消息在控制器发送删除流表项的消息或者流表项的定时器其超时后产生。

    l Port-Status:通知控制器端口状态或设置的改变。

    3、同步(Symmetric)消息

    顾名思义,同步(Symmetric)消息是双向对称的消息,主要用来建立连接、检测对方是否在线等,是控制器和OpenFlow交换机都会在无请求情况下发送的消息,包括Hello、Echo和Experimenter三种消息,这里我们介绍应用最常见的前两种:

     

    图12 同步消息

    l Hello:当连接启动时交换机和控制器会发送Hello交互。

    l Echo:用于验证控制器与交换机之间连接的存活,控制器和OpenFlow交换机都会发送Echo Request/Reply消息。对于接收到的Echo Request消息必须能返回Echo Reply消息。Echo消息也可用于测量控制器与交换机之间链路的延迟和带宽。

    3.1.2 信道建立过程解析

    OpenFlow控制器和OpenFlow交换机之间建立信道连接的基本过程,具体步骤如下:

    1. OpenFlow交换机与OpenFlow控制器之间通过TCP三次握手过程建立连接,使用的TCP端口号为6633。

    2. TCP连接建立后,交换机和控制器就会互相发送hello报文。Hello报文负责在交换机和控制器之间进行版本协商,该报文中OpenFlow数据头的类型值为0。

    3. 功能请求(Feature Request):控制器发向交换机的一条OpenFlow 消息,目的是为了获取交换机性能,功能以及一些系统参数。该报文中OpenFlow 数据头的类型值为5。

    4. 功能响应(Feature Reply):由交换机向控制器发送的功能响应(Feature Reply)报文,描述了OpenFlow交换机的详细细节。控制器获得交换机功能信息后,OpenFlow协议相关的特定操作就可以开始了。

    5. Echo请求(Echo Request)和Echo响应(EchoReply)属于OpenFlow中的对称型报文,他们通常用于OpenFlow交换机和OpenFlow控制器之间的保活。通常echo请求报文中OpenFlow数据头的类型值为2,echo响应的类型值为3。不同厂商提供的不同实现中,echo请求和响应报文中携带的信息也会有所不同。

    3.1.3 信道连接断开模式

    当OpenFlow设备与所有Controller断开连接后,设备进入Fail Open模式。OpenFlow设备存在两种Fail Open模式:

    l Fail Secure mode交换机:在该模式下的OpenFlow交换机,流表项继续生效,直到流表项超时删除。OpenFlow交换机内的流表表项会正常老化。

    l Fail Standalone mode交换机:所有报文都会通过保留端口Normal处理。即此时的OpenFlow交换机变成传统的以太网交换机。Fail Standalone mode只适用于OpenFlow-Hybrid交换机。

    安全通道也有两种模式,不同模式下安全通道重连的机制不同。

    l 并行模式:并行模式下,Switch允许同时与多个Controller建立连接,Switch与每个Controller单独进行保活和重连,互相之间不影响。当且仅当Switch与所有Controller的连接断开后,Switch才进入Fail Open状态。

    l 串行模式:串行模式下,Switch在同一时刻仅允许与一个Controller建立连接。一旦与该Controller连接断开后,Switch并不会进入Fail Open状态,而是立即根据Controller的ID顺序依次尝试与Controller连接。如果与所有Controller都无法建立连接,则等待重连时间后,继续遍历Controller尝试建立连接。在三次尝试后,仍然没有成功建立连接,则Switch进入Fail Open状态。

    3.2 OpenFlow消息处理

    3.2.1 OpenFlow流表下发与初始流表

    OpenFlow流表下发分为主动和被动两种机制:

    主动模式下,Controller将自己收集的流表信息主动下发给网络设备,随后网络设备可以直接根据流表进行转发。

    被动模式下,网络设备收到一个报文没有匹配的FlowTable记录时,会将该报文转发给Controller,由后者进行决策该如何转发,并下发相应的流表。被动模式的好处是网络设备无需维护全部的流表,只有当实际的流量产生时才向Controller获取流表记录并存储,当老化定时器超时后可以删除相应的流表,因此可以大大节省交换机芯片空间。

    在实际应用中,通常是主动模式与被动模式结合使用。

    当OpenFlow交换机和Controller建立连接后,Controller需要主动给OpenFlow交换机下发初始流表,否则进入OpenFlow交换机的报文查找不到流表项,就会做丢弃处理。这里的初始流表保证了OpenFlow的未知报文能够上送控制器。而后续正常业务报文的转发流表,则在实际流量产生时,由主动下发的初始流表将业务报文的首包上送给控制器后,触发控制器以被动模式下发。

    这里我们以H3C VCFC控制器给交换机下发的一个初始流表举例。

    前面我们了解到,OpenFlow流表是分级匹配的,通常按0表、1表、2表这样依次匹配过去,每个级别的表中则由优先级高的表项先进行匹配。

     

    图13 OpenFlow流表举例

    如上图所示,0表优先级最高为65535的两条流表匹配到的是端口号为67、68的UDP报文,也就是DHCP报文,匹配动作为goto_table 1,剩下的其他所有报文也命中优先级最低为0的表项后goto_table 1。而在表1中,优先级最低的表项对应的动作为output controller,这保证了虚拟机的DHCP请求可以发送给控制器,由控制器作为网络中的DHCP Server,避免DHCP请求泛洪,同时还保证了交换机上所有未知的无流表匹配的报文都可以上送控制器,触发控制器被动下发流表给交换机指导转发。这里,我们把表1里优先级最低为0,匹配所有未知报文的表项叫做table-miss表项。

    我们在OpenFlow交换机上同样可以观察到初始流表,这里以H3C S6800交换机上的一个初始流表举例。上图中的这条表项匹配报文类型为以太网报文,UDP端口67、68说明匹配DHCP请求报文,动作为上送控制器:

     

    图14 OpenFlow交换机上流表举例

    3.2.2 OpenFlow报文上送控制器

    OpenFlow报文上送控制器详细过程如下:

     

    图15 OpenFlow报文上送控制器过程

    1.控制器和交换机建立连接事件是Packet-in事件发生的前提。

    2.当OpenFlow交换机收到数据包后,如果明细流表中与数据包没有任何匹配条目,就会命中table-miss表项,触发Packet-in事件,交换机会将这个数据包封装在OpenFlow协议报文中发送至控制器。

    3.一旦交换机触发了Packet-in事件,Packet-in报文就将发送至控制器。

    Packet-in数据头包括了:

    l 缓冲ID

    l 数据包长度

    l 输入端口

    l Packet-in的原因,分两种:

    0: 无匹配

    1: 流表中明确提到将数据包发送至控制器

    3.2.3 控制器回应OpenFlow报文

    控制器收到Packet-in消息后,可以发送Flow-Mod消息向交换机写一个流表项。并且将Flow-Mod消息中的buffer_id字段设置为Packet-in消息中的buffer_id值。从而控制器向交换机写入了一条与数据包相关的流表项,并且指定该数据包按照此流表项的action列表处理。

    Controller根据报文的特征信息(如IP、mac等)下发一条新的流表项到OpenFlow交换机或者做其他处理之后下,发Packet-out消息动作为output到table,具体过程如下所示:

     

    图16 控制器回应OpenFlow报文过程

    1.控制器和交换机之间建立连接事件是Packet-out事件发生的前提;

    2.控制器要发送数据包至交换机时,就会触发Packet-out事件将数据包发送至交换机。这一事件的触发可以看做是控制器主动通知交换机发送一些数据报文的操作。通常,当控制器想对交换机的某一端口进行操作时,就会使用Packet-out报文。

    3.该数据包由控制器发往交换机,内部信息使用Packet-out,并由OpenFlow数据头封装。OpenFlow Packet-out信息包括:

    l 缓冲ID

    l 入口端口编号

    l 动作明细(添加为动作描述符)

    l 输出动作描述符

    l VLAN VID动作描述符

    l VLAN PCP动作描述符

    l 提取VLAN标签动作描述符

    l 以太网地址动作描述符

    l IPv4地址动作描述符

    l IPv4 DSCP动作描述符

    l TCP/UDP端口动作描述

    l 队列动作描述符

    l 各厂商动作描述符

    3.3 OpenFlow交换机转发

    3.3.1 单播报文转发流程

    当OpenFlow交换机接收到Flow-Mod消息,生成流表后,就可以按照流表转发接收到的Packet-out报文了,过程举例如下:

     

    图17 单播报文转发流表

    在本例中,OpenFlow 交换机需要转发一个从7.7.7.1到9.9.9.1的流量。当流量上送到OpenFlow交换机后,流量的第一个包会先进行Packet-in、Flow-Mod、Packet out的过程,之后同流量的报文就能匹配控制器已经下发的流表进行转发了。

    3.3.2 组播报文转发

    当终端发出的组播报文到达OpenFlow交换机后,OpenFlow交换机Packet-in给控制器,控制器会为网络下发指导查询组表的流表,并进行流表与组表关联。交换机参考流表,引用组表进行转发。举例如下:

    组播报文转发所使用的流表:

     

    图18 组播报文转发流表

    上条流表的动作为引用组表4096,组表4096详细内容如下:

     

    图19 组表详细内容

    4 OpenFlow的未来

    OpenFlow作为SDN转控分离架构和可编程性的灵魂已经存在近十年了,作为SDN技术家族中的老前辈可谓劳苦功高。然而,从整个网络技术数十年的发展历程来看,Openflow还只是个刚刚长成的少年,尽管已具备了丰富的功能雏形,在未来的日子里仍然还有很长的成熟期要度过。我相信伴随着云计算和虚拟化技术的进一步推广落地,在众多SDN技术支持者的贡献下,OpenFlow会更加稳定、强大,最终能够某种程度上推动全人类科技的发展和生活的改善。最后,套用一句我最喜欢的话来结尾:OpenFlow的征途是星辰大海,诸君努力!

  • 相关阅读:
    对象比较
    ObservableCollection<T> 的同类 ListCollectionView
    数据模板--DataTemplate
    ListBox的虚拟可视化技术
    WPF 动画 和 色彩 的随笔
    Binding.RelativeSource 属性
    javascript基础DOM操作
    js dom 操作技巧
    js 内置对象和方法 示例
    javascript 编程技巧
  • 原文地址:https://www.cnblogs.com/zy09/p/15879619.html
Copyright © 2020-2023  润新知