<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Muzixing</title><link>http://www.muzixing.com/</link><description></description><atom:link href="http://www.muzixing.com/feeds/all.rss.xml" rel="self"></atom:link><lastBuildDate>Tue, 02 Jun 2020 00:00:00 +0800</lastBuildDate><item><title>2018/2019总结：推开世界的门</title><link>http://www.muzixing.com/pages/2020/06/02/20182019zong-jie-tui-kai-shi-jie-de-men.html</link><description>&lt;h2&gt;我不会用vim了&lt;/h2&gt;
&lt;p&gt;突然，&lt;/p&gt;
&lt;p&gt;我发现我已经不会用vim了，&lt;/p&gt;
&lt;p&gt;我忘记快捷键了，&lt;/p&gt;
&lt;p&gt;我忘记Markdown了，&lt;/p&gt;
&lt;p&gt;我忘记怎么编辑博客了，&lt;/p&gt;
&lt;p&gt;曾经那么引以为豪的东西，&lt;/p&gt;
&lt;p&gt;就这样慢慢忘了。&lt;/p&gt;
&lt;p&gt;由于微博图床不再支持外挂图片，我已经放弃了修复博客里的文章，还好在SDNLAB.com上发表过，有备份。也因为工作的原因，不方便再继续发表技术博客，所以大概，我放弃了继续写博客吧。&lt;/p&gt;
&lt;p&gt;客观的讲，写博客对我的加成已经不大了，但依然舍不得这个曾经陪伴自己青春的地方。所以还是来这里更新一下自己的年终总结吧。&lt;/p&gt;
&lt;h2&gt;2018+2019总结：20个月，十个故事，一段人生&lt;/h2&gt;
&lt;p&gt;2018年的总结由于太忙，放弃了，所以只好写了2018到2019年20个月的生活总结，也算对得起岁月与时光。&lt;/p&gt;
&lt;p&gt;2018+2019: &lt;a href="https://www.jianshu.com/p/057a8d572dbd"&gt;《廿月谈：大世界与小世界》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;一个关于推开世界的门，遇见自己的生活总结吧。&lt;/p&gt;
&lt;p&gt;===================================&lt;/p&gt;
&lt;p&gt;顺便附上往年的总结：&lt;/p&gt;
&lt;p&gt;2017: &lt;a href="http://www.muzixing.com/pages/2018/06/03/chi-dao-de-2017zong-jie-qi-feng-liao-li-ming.html"&gt;迟到的2017总结：《起风了，黎明》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2016: &lt;a href="http://www.muzixing.com/pages/2017/03/25/2016zong-jie-sha-si-na-ge-tian-zhen-de-zi-ji.html"&gt;2016总结：杀死那个天真的自己&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2015: &lt;a href="http://www.muzixing.com/pages/2016/02/24/deng-feng-lai-chi-dao-de-2015nian-zhong-zong-jie.html"&gt;等风来——迟到的2015年终总结&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2014: &lt;a href="http://www.muzixing.com/pages/2015/03/08/zhan-zai-shi-zi-lu-kou-de-nian.html"&gt;站在十字路口的一年&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2013: &lt;a href="http://www.muzixing.com/pages/2014/01/01/shu-yu-wo-de-2013he-2014.html"&gt;属于我的2013和2014&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;人生啊，真奇妙，回头看，才知道。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 02 Jun 2020 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2020-06-02:pages/2020/06/02/20182019zong-jie-tui-kai-shi-jie-de-men.html</guid><category>story，life</category><category>ietf</category></item><item><title>Cheng Li in IETF</title><link>http://www.muzixing.com/pages/2019/08/06/cheng-li-in-ietf.html</link><description>&lt;p&gt;Hi guys,&lt;/p&gt;
&lt;p&gt;I am so sorry that I did not update my blog in past two years. But thank you for visiting here for anything.&lt;/p&gt;
&lt;p&gt;Work is always so busy, and it is not easy to publish technology articles considering Huawei's confidential policy.&lt;/p&gt;
&lt;p&gt;I am working on IP technology research and standards in Huawei since I joined Huawei, so I will publish some &lt;a href="https:datatracker.ietf.org/person/cheng%20li"&gt;IETF drafts&lt;/a&gt;, which mainly focus on SRv6, SR, PCEP, SFC, etc. Welcome to review my drafts, and looking forward to seeing you in IETF. &lt;/p&gt;
&lt;p&gt;Also, I designed the &lt;a href="https://github.com/muzixing/ietf103-tshirt"&gt;IETF 103 T-shirt&lt;/a&gt;. Amazing experience in IETF!&lt;/p&gt;
&lt;p&gt;My Huawei E-mail is chengli13#huawei.com, comments or questions are welcome.&lt;/p&gt;
&lt;p&gt;Best Regards,&lt;/p&gt;
&lt;p&gt;Cheng&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 06 Aug 2019 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2019-08-06:pages/2019/08/06/cheng-li-in-ietf.html</guid><category>SR</category><category>Segment Routing</category><category>SR-MPLS</category><category>SRv6</category></item><item><title>Segment Routing架构介绍</title><link>http://www.muzixing.com/pages/2018/10/26/segment-routingjia-gou-jie-shao.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;从第一次接触到Segment Routing（SR），到现在专注与Segment Routing的研究和标准化，了解越来越深入，也越来越清楚SR将成为网络的发展趋势。在SR架构文稿成为&lt;a href="https://tools.ietf.org/html/rfc8402"&gt;RFC8402&lt;/a&gt;的这一刻，没有什么比写一篇介绍SR架构的文章更好的选择了。&lt;/p&gt;
&lt;h3&gt;背景&lt;/h3&gt;
&lt;p&gt;Segment Routing的诞生背景和SDN紧密相关。在SDN出现早起，SDN几乎和OpenFlow密不可分。但在商业上，OpenFlow这样极具革命性创新的新协议很难被传统设备商所接受，也影响了巨头们的利益。在技术上，OpenFlow网络中每个节点都要维持网络状态，当网络规模变大，业务变多，网络管理和运维就变得复杂，网络的可扩展性就受到了限制。为了面对OpenFlow的挑战，Cisco提出了Segment Routing(SR)，一种可以在Ingress节点指明数据包转发路径的源路由机制。&lt;/p&gt;
&lt;p&gt;总体来看，SR主要有如下的特征（包括但不限于）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持源路由，支持在源节点显示指定转发路径&lt;/li&gt;
&lt;li&gt;SR只在Ingress节点保持Per-flow的状态，中间网络节点无需维护Per-flow的网络状态，只需无状态转发即可，因此SR具有很好的可扩展性。&lt;/li&gt;
&lt;li&gt;SR无需在节点之间采用任何信令协议，不要求增加任何新的网络协议，减少网络信令协议的使用。&lt;/li&gt;
&lt;li&gt;SR可以部署在MPLS和IPv6两种数据平面。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Segment Routing Architecture&lt;/h3&gt;
&lt;p&gt;Segment Routing (SR)是一种源路由机制。SR支持在源节点往数据报文中插入一组有序的操作指令来显示地指定数据包的转发路径和处理流程。这个操作指令称之为“Segment”。一个Segment可以是具有拓扑意义的，比如代表一个节点或者一条链路，也可以是基于服务的，比如描述一个service。 &lt;/p&gt;
&lt;p&gt;一个Segment可以是本地意义的，也可以是全局意义的。比如描述一个指向一个邻接的链路，或者描述一个全局的节点或者网段。 &lt;/p&gt;
&lt;p&gt;基于SR，可以实现数据流的显示路径转发，而且只需在Ingress节点维持Per-flow的状态而无需在中间节点或尾节点来维持per-flow的状态。相比RSVP-TE MPLS需要在所有节点维持Per-flow的状态，SR大大节省了网络的状态维护难度，从而简化了网络，也提升了网络的可扩展性。&lt;/p&gt;
&lt;p&gt;当下的SR架构可以部署在两种数据平面上：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MPLS&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;部署在MPLS数据平面上的SR，标准上习惯称之为SR-MPLS，当然也有人喜欢叫MPLS-SR。其可以直接基于现有的MPLS数据平面部署，无需对数据平面进行任何改动。这意味着，从RSVP-TE MPLS到SR-MPLS的改动只需对控制平面进行升级，使得网络可以更平滑地存量演进。在SR-MPLS中，一个Segment表现为一个MPLS Label（标签）。&lt;/p&gt;
&lt;p&gt;&lt;img alt="SR-MPLS" src="http://wx3.sinaimg.cn/mw690/7f593341ly1fwlyjl3qa1j21kw0ttdnf.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://support.huawei.com/enterprise/zh/doc/DOC1000173014?section=j004"&gt;Ref:Huawei Document:IPv6 Segment Routing&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Segment／Label可能是具有全局意义的，也可能是具有本地意义的。在SR-MPLS中，每一个节点会配置对应本地标签块SRLB（Segment Routing Local Block）和SRGB（Segment Routing Global Block)。从SRLB中的标签值具有本地意义，从SRGB中的标签值具有全局意义。&lt;/p&gt;
&lt;p&gt;为了满足MPLS标签资源本地化，同时又要满足SR全局标签的需求，SRGB是节点的配置信息，不强制全网统一，但在实际部署时，为方便起见，一般是统一的。&lt;/p&gt;
&lt;p&gt;比如节点A的SRGB为1000-2000，节点B的SRGB为3000-4000。节点A的Node-SID为1，B的Node-SID为2，那么节点A在发布自己的节点SID时，可以选择发布绝对值1001，也可以发布index为1。其他节点会依据节点A发布的SRGB（1000-2000）来计算转发到该节点时，应该使用标签1001。而一个全网路由的Node-SID 1在转发到B节点时，标签值就是其SRGB下限3000+1=3001。从而保证了标签均为本地意义，但同时又提供了全局路由的能力。&lt;/p&gt;
&lt;p&gt;当SRGB均一样时，就容易理解地多。比如SRGB均为1000-2000。那么无论转发到A节点还是B节点，标签值均为1001。&lt;/p&gt;
&lt;p&gt;一组有序的Segment，称之为Segment list，在SR-MPLS网络呈现为一个MPLS标签栈。需要被处理的标签为栈顶的标签。被处理完的标签，将会被弹出。所以随着数据包在MPLS网络中转发，标签栈中的标签会不断弹出，直到最后弹完。数据包的转发动作，则有标签指定，其转发行为同RSVP-TE MPLS网络。&lt;/p&gt;
&lt;p&gt;更多标签操作，如PUSH，NEXT，CONTINUE等基础知识可以参考&lt;a href="https://tools.ietf.org/html/draft-ietf-spring-segment-routing-mpls-15"&gt;draft-ietf-spring-segment-routing-mpls-15&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SRv6&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SR架构也可以应用在IPv6网络中，称为SRv6(Segment Roouting over IPv6)&lt;a href="https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-15"&gt;draft-ietf-6man-segment-routing-header-15&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;在SRv6中，一个Segment表现为一个128 bit的IPv6地址。一个Segment list就表现为插入在SRH中的一组有序的IPv6地址列表。但并不是所有的IPv6地址都是SID，其需要被声明为SID。此外，SID可以是节点的地址或者接口的地址，但大部分情况下是独立声明的SID。&lt;/p&gt;
&lt;p&gt;为了支持SRv6，需要扩展一种新的IPv6 Routing Header: Segment Routing Header(SRH)，格式如下图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="SRH" src="http://wx2.sinaimg.cn/mw690/7f593341ly1fwlyfgeo1oj20vk0nswgi.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;关于SRH的内容后续文章会继续介绍。&lt;/p&gt;
&lt;h3&gt;Link-State IGP Segments&lt;/h3&gt;
&lt;p&gt;描述Segment的ID称为Segment ID，缩写为SID。在不同的数据平面，SID的表现形式不同。在MPLS数据平面，SID表现为一个MPLS标签，而在IPv6数据平面里，SID表现为一个128bit的值，其可以是节点的一个接口地址，也可以不是。&lt;/p&gt;
&lt;p&gt;SR的控制平面在Ingress节点根据&lt;a href="https://tools.ietf.org/html/draft-ietf-spring-segment-routing-policy-02"&gt;SR Policy&lt;/a&gt;给数据包插入Segment List，显示指定数据包的转发路径(松散路径或者严格路径，后面介绍)，以及在指定节点的操作。节点需要根据数据包中的指令来处理和转发数据包。&lt;/p&gt;
&lt;p&gt;SR控制平面可以是分布式的，也可以是集中式的。在分布式的情况下，需要通过扩展IGP（IS-IS／OSPF）或BGP等路由协议来支持SR。&lt;/p&gt;
&lt;h3&gt;IGP SID&lt;/h3&gt;
&lt;p&gt;本小节将简要介绍SR中重要的几类SID。&lt;/p&gt;
&lt;h4&gt;Node-SID&lt;/h4&gt;
&lt;p&gt;节点SID, 用于表示一个SR节点。
SR-MPLS：FEC 10.8.8.3对应的／绑定的SID可以是一个MPLS标签，值为1003。
SRv6: IPv6地址A::1/128本身就可以发布成SID。&lt;/p&gt;
&lt;h4&gt;Prefix-SID&lt;/h4&gt;
&lt;p&gt;用于描述网段的SID。
SR-MPLS：网段10.8/16的SID可以是标签1001。
SRv6：网段A::/48的SID就是A::/48。&lt;/p&gt;
&lt;h4&gt;Adjacency-SID&lt;/h4&gt;
&lt;p&gt;用于描述邻接的SID，描述指向邻接的某条链路或集合。用于指定数据包发向指定链路，可用于严格路径的SR-TE。&lt;/p&gt;
&lt;p&gt;SR-MPLS: 从SRLB中取出的某本地标签值，比如9001。
SRv6: 可以是某一个节点的接口的IPv6地址。比如A::C6。&lt;/p&gt;
&lt;h4&gt;Binding-SID&lt;/h4&gt;
&lt;p&gt;绑定SID。可用于映射SID List。比如SID值100为一个Binding-SID，其映射的SID list为[2001,2003,2005]。那么为了缩短SID list，可以采用插入Binding SID的方式来取代[2001,2003,2005]。一般可用于标签粘连和和&lt;a href="https://tools.ietf.org/html/draft-ietf-spring-segment-routing-policy-02"&gt;SR Policy&lt;/a&gt;场景。&lt;/p&gt;
&lt;p&gt;SR-MPLS: 从SRLB中取出的某本地标签值，比如9002。
SRv6: 发布成SID的某一个IPv6地址，比如A::C6。&lt;/p&gt;
&lt;h4&gt;Path SID&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://tools.ietf.org/html/draft-cheng-spring-mpls-path-segment-03"&gt;Path SID&lt;/a&gt;用于标识SR网络中的路径。其出现的原因主要是因为在SR-MPLS中，标签会不断被弹出，当数据包到达Egress节点时，节点无法识别数据包来自哪一条路径，所以需要一个Path SID来标识。&lt;/p&gt;
&lt;p&gt;而在SRv6网络中，使用SID List来描述一条路径过于复杂，所以&lt;a href="https://tools.ietf.org/html/draft-li-spring-srv6-path-segment-00"&gt;SRv6 Path Segment&lt;/a&gt;也被提出来了。&lt;/p&gt;
&lt;h3&gt;SR-MPLS&lt;/h3&gt;
&lt;p&gt;后续文章会介绍SR-MPLS。可参考&lt;a href="https://tools.ietf.org/html/draft-ietf-spring-segment-routing-mpls-15"&gt;draft-ietf-spring-segment-routing-mpls-15&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;SRv6&lt;/h3&gt;
&lt;p&gt;后续文章会介绍SRv6。可参考&lt;a href="https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-15"&gt;draft-ietf-6man-segment-routing-header-15&lt;/a&gt;。&lt;/p&gt;
&lt;h4&gt;SRv6 NP&lt;/h4&gt;
&lt;p&gt;后续文章会介绍SRv6 Network Programming。可参考&lt;a href="https://tools.ietf.org/html/draft-filsfils-spring-srv6-network-programming-06"&gt;draft-filsfils-spring-srv6-network-programming-06&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;SR Use Cases&lt;/h3&gt;
&lt;p&gt;更多Use cases后续可能会有文稿介绍，建议读者直接阅读ietf标准草案。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SFC&lt;/li&gt;
&lt;li&gt;SR TE&lt;/li&gt;
&lt;li&gt;网络编程&lt;/li&gt;
&lt;li&gt;E2E SRv6&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;关于Segment Routing的更多学习，后续会有更多文章介绍。读者可前往&lt;a href="https://tools.ietf.org/wg/spring"&gt;SPRING WG&lt;/a&gt;阅读进一步内容。也可以下载&lt;a href="http://support.huawei.com/enterprise/zh/doc/DOC1000173014?section=j004"&gt;华为的技术文档&lt;/a&gt;或者&lt;a href="http://e.huawei.com/enterprisesearch/?lang=zh#keyword=segment+routing&amp;amp;lang=zh&amp;amp;site=1&amp;amp;type=ALL"&gt;搜索华为技术文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;PS：本文章为个人学习总结，不涉及任何商业信息。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 26 Oct 2018 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2018-10-26:pages/2018/10/26/segment-routingjia-gou-jie-shao.html</guid><category>SR</category><category>Segment Routing</category><category>SR-MPLS</category><category>SRv6</category></item><item><title>Segment Routing系列文章：To Write List</title><link>http://www.muzixing.com/pages/2018/08/09/segment-routingxi-lie-wen-zhang-to-write-list.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;人啊，总是懒惰的。&lt;/p&gt;
&lt;p&gt;一懒惰，就是两年。&lt;/p&gt;
&lt;p&gt;总是有太多理由，总是有太多借口。&lt;/p&gt;
&lt;p&gt;但终究，还是无法再骗过自己了。&lt;/p&gt;
&lt;p&gt;问过了领导，领导答复：“写互联网公开的，开源的内容没有问题”。那就从我平时研究的Segment Routing开始写吧。为避免踩信息安全红线，还是要很郑重地声明：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;所有文章内容均为互联网公开资料和个人技术理解，不涉及任何商业机密。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;什么是SR&lt;/h3&gt;
&lt;p&gt;Segment Routing， 中文翻译为段路由，是一种源路由架构，其支持在Ingress node(源节点)指定数据包的转发路径。&lt;/p&gt;
&lt;p&gt;Segment Routing的诞生背景和SDN紧密相关。在SDN出现早期，SDN几乎和OpenFlow密不可分。但现在OpenFlow却并没有像前两年那样如火如荼，已经开始慢慢冷却，慢慢退出人们的视野。&lt;/p&gt;
&lt;p&gt;OpenFlow冷却的原因很多。从商业上，极具革命性的OpenFlow可能会打破网络行业的格局，影响了行业巨头的利益，所以很难被传统设备商所接受。在技术上，OpenFlow网络中的每个节点都要维持per-flow的网络状态，当网络规模变大，业务变复杂，网络管理和运维就变得复杂，网络的可扩展性就成了问题。就在此时，一个更容易平滑演进，又具有足够的网络编程能力的网络架构Segment Routing被提了出来。Segment Routing (SR) 是一种可以在源节点指明数据包转发路径的源路由网络架构。&lt;/p&gt;
&lt;h3&gt;后续文章计划&lt;/h3&gt;
&lt;p&gt;更多的内容将会在如下的文章中被介绍，主要包括SR的原理，协议扩展等内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;《Segment Routing架构基础：SR-MPLS和SRv6》—— 待完成&lt;/li&gt;
&lt;li&gt;《SR-MPLS：RSVP-TE的退场与SR-MPLS的崛起》—— 待完成&lt;/li&gt;
&lt;li&gt;《SRv6：SDN的未来？》—— 待完成&lt;ul&gt;
&lt;li&gt;《SRH简介》—— 待完成&lt;/li&gt;
&lt;li&gt;《SRv6 Network Programming》—— 待完成&lt;/li&gt;
&lt;li&gt;《IS-IS extensions for SRv6》—— 待完成&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;《SR for SFC》—— 待完成&lt;ul&gt;
&lt;li&gt;《SFC：PBR vs NSH vs SR》—— 待完成&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;计划都放出来了，难道要反悔？不可能的!&lt;/p&gt;
&lt;p&gt;成长的速度太慢了，要追不上梦想了，要努力哦。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 09 Aug 2018 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2018-08-09:pages/2018/08/09/segment-routingxi-lie-wen-zhang-to-write-list.html</guid><category>SR</category><category>Segment Routing</category><category>SR-MPLS</category><category>SRv6</category></item><item><title>迟到的2017总结：《起风了，黎明》</title><link>http://www.muzixing.com/pages/2018/06/03/chi-dao-de-2017zong-jie-qi-feng-liao-li-ming.html</link><description>&lt;p&gt;终于办完了美国退税支票的托收，走出中国银行的时候，觉得如释重负。&lt;/p&gt;
&lt;p&gt;这一年多，过得太不容易。&lt;/p&gt;
&lt;h3&gt;硅谷故事&lt;/h3&gt;
&lt;p&gt;"It's not a big deal."&lt;/p&gt;
&lt;p&gt;"It is a big deal!"&lt;/p&gt;
&lt;p&gt;"All right, it is a big deal!"，我还是承认了我遇到了一件很大的事，即使我还不愿意承认。&lt;/p&gt;
&lt;p&gt;2017年1月27号，星期五，农历大年三十，除夕。美国硅谷圣何塞郊区的Milpitas，一如以往的平静和安详，没有一丝节日的气息。&lt;/p&gt;
&lt;p&gt;一晚上没睡好的我，在9点多的早晨，与实习生外包公司的人力主管R发生了以上的对话：项目没钱了，希望我收拾好物品，回家。他问我什么时候走合适 ，好给我定回去的机票。今晚就要搬出公寓。&lt;/p&gt;
&lt;p&gt;几个月之前确实有人给我暗示过，如果项目没有预算了，就要回国。但后来项目经理给我保证我的预算没问题，所以我放心了。没想到再次提起预算的时候，竟然实在春节之际。&lt;/p&gt;
&lt;p&gt;“为什么让我走？是因为没有预算是吗？” 沉默了几秒之后，我忍不住开口。&lt;/p&gt;
&lt;p&gt;“是的”&lt;/p&gt;
&lt;p&gt;“没有其他原因？” 我追问。&lt;/p&gt;
&lt;p&gt;“据我所知，没有”，R很职业地回复着。&lt;/p&gt;
&lt;p&gt;“真的吗？”&lt;/p&gt;
&lt;p&gt;“嗯，我没想到有其他的原因”&lt;/p&gt;
&lt;p&gt;“那就是钱的问题？”&lt;/p&gt;
&lt;p&gt;“是的”&lt;/p&gt;
&lt;p&gt;“那如果我能找到钱，我是不是可以留下来？” &lt;/p&gt;
&lt;p&gt;“嗯。。。理论上是的，如果能找到预算，没有理由让你走。” R脸上露出了一丝的疑惑。&lt;/p&gt;
&lt;p&gt;“能给我几天吗？，我想试试找一下预算，如果我找不到，我就走。”&lt;/p&gt;
&lt;p&gt;“嗯。。。行吧，下周二之前吧？”， R并不是那个做决定的恶人，只是一个执行者。我知道。&lt;/p&gt;
&lt;p&gt;“没问题，今天是周五，再加一个周末，如果周一没有拿到预算，我周二就走。”我抓住了一根救命稻草。&lt;/p&gt;
&lt;p&gt;走出会议室之后，我疯狂联系我的mentor，还有远在以色列的项目经理。以色列周五不上班，现在是周四的晚上，放假的时候。&lt;/p&gt;
&lt;p&gt;他们都不知道这件事。&lt;/p&gt;
&lt;p&gt;Mentor安慰我没事，他站在我这边，会努力帮我解决。以色列项目经理告诉我，没问题，预算没问题，我们还有预算，你不需要走。我没敢信。&lt;/p&gt;
&lt;p&gt;半个小时之后，Mentor和项目经理电话聊完了这件事。无奈地告诉我，我们的预算确实没有了，特别抱歉。我不知道说什么，只是点头表示知道了。&lt;/p&gt;
&lt;p&gt;“Money talks.” 我从mentor那里又学到了一个新的英语用法。&lt;/p&gt;
&lt;p&gt;Mentor是一个俄罗斯人，平日里对我特别好，我们是朋友。上一次我被某华人HR主管Dalin当着60多人批评是最差的演讲者的时候，他站了出来，为我说话。后来那个华人HR主管Dalin向他电话道歉了。我知道他是对我好的。但是这次他也没有办法了。&lt;/p&gt;
&lt;p&gt;绝望，第一次感受到绝望。&lt;/p&gt;
&lt;p&gt;我难道就要这样以️一个loser的身份，收拾自己的东西，滚出公寓，滚回国内，在春节之际，给父母一个打击？我不能接受。我宁愿在北京住一个周再回家，也不愿意春节回去告诉他们这个消息。他们一直以我来美国实习而自豪。&lt;/p&gt;
&lt;p&gt;停止恐慌！我需要拯救我自己。&lt;/p&gt;
&lt;p&gt;我给管理这个实习项目的主管发邮件，也在facebook群组中告诉其他的小伙伴我的处境，希望他们能帮帮我。&lt;/p&gt;
&lt;p&gt;所有人都震惊了。&lt;/p&gt;
&lt;p&gt;实习生们都为此感到震惊和愤怒，质疑实习公司的做法不职业，推到最后一天然后赶人，另有目的，不讲人情。甚至连实习项目的主管都不知道这回事，也表示很惊讶，表示会支持我找预算，支持我留下来。&lt;/p&gt;
&lt;p&gt;小伙伴们开始找自己的mentor，询问预算的事情，看看是否能接受我。但预算是上一年就定好的，所以回复大多都否定的。&lt;/p&gt;
&lt;p&gt;除了Yoel，一个西班牙小伙子。&lt;/p&gt;
&lt;p&gt;他说他们Zeus团队的boss知道这件事情之后很震惊也很愤怒，打算接触接触我，看看能不能帮助我。&lt;/p&gt;
&lt;p&gt;我滑着滑板赶向了Building 3，去参加我的面试。这个团队很棒，成员基本都是历年转正的实习生和今年的6个实习生。Boss是一个印度人。&lt;/p&gt;
&lt;p&gt;基本的沟通和安慰之后，我们开始了技术面试，一共3轮，问了一些基本的情况，对方反馈是正面的。但还需要周末操作，让我周一等回复。&lt;/p&gt;
&lt;p&gt;下午六点，我本季度的实习结束了，预算也用完了。我无法再进入大楼，无法用我的ID接入无线网。我被完全隔离在了公司资源之外，只需要一个小时，尤其高效。&lt;/p&gt;
&lt;p&gt;脑子混乱地回到公寓，才发现我住的公寓是今年春节party的举办地。满屋都是华人，桌子上是他们一起做的一盘盘菜。我打了个招呼，就走进了本可能今晚就要搬出的房间。R宽限我到下周二了。&lt;/p&gt;
&lt;p&gt;昏黄的灯光下，我打开了我破旧的电脑，继续发着邮件寻找着新的机会。客厅的欢声笑语穿透了房门，强行钻进了我的耳朵里。他们在唱歌。&lt;/p&gt;
&lt;p&gt;Zeus的Boss给我打来了电话，我奔出了房间，总算逃离那个我格格不入的场合。&lt;/p&gt;
&lt;p&gt;又是一次漫长的交谈，又重复讲了一遍自己的故事。这个周五，我已经向不同的人讲过很多遍我的故事了。&lt;/p&gt;
&lt;p&gt;“你没有和什么领导有冲突吗？” Boss突然问了一个让我措手不及的问题。&lt;/p&gt;
&lt;p&gt;“冲突？嗯。。。我几乎没跟他们接触过，很少有交集，除了Dalin。嗯。。。她不喜欢我的演讲。” 我努力回忆着，思考着。&lt;/p&gt;
&lt;p&gt;“嗯，有人想让你离开，但是我不能说是谁。” Boss语重心长地对我说。我似乎明白了什么，但是也不清楚想让我走的理由是什么。&lt;/p&gt;
&lt;p&gt;一番关于生活，理想的讨论之后，他让我等消息，周末他会联系财务，去操作这件事情。我追问：“应该没问题吧？”&lt;/p&gt;
&lt;p&gt;“应该没问题，我没看出来他们会阻止我给你预算的理由。但是要看财务操作，现在是周末，希望能转账成功。” Boss这样给我回复。&lt;/p&gt;
&lt;p&gt;悬着的心，终于掉下来一半。&lt;/p&gt;
&lt;p&gt;就在我自己几乎要被赶走的时候，Linkedin上有人找我内推，我告诉了他投简历的途径。&lt;/p&gt;
&lt;p&gt;深夜，Zeus团队里面年轻的西班牙leader Marc给我发来了消息，约好了周六的面谈。&lt;/p&gt;
&lt;p&gt;阳光明媚的周六，我滑着滑板来到了Buiding 3，却无法刷卡进门，只能等待Marc下来接我。&lt;/p&gt;
&lt;p&gt;又讲了一次我的遭遇，然后进行了一些具体的技术交谈之后，最终，他给了我确定的答复。下周一你就来上班。钱的事你不用管，会搞定的。门卡用不了可以让其他实习生给我开门，不用担心，一切都会没事的。&lt;/p&gt;
&lt;p&gt;悬着的心，终于要掉到地上了。&lt;/p&gt;
&lt;p&gt;虽然又经历了近半个月门卡刷不了，无线用不了的尴尬，但最终我还是在新的团队继续实习了。我学习了Ruby，学习了Go，也产出了不少的代码，贡献了自己的力量。&lt;/p&gt;
&lt;p&gt;剩下的日子里，我和朋友租车出去玩，去没有去过的地方，去放飞，去享受很快就会过去的美国生活，也因为超速被罚了300多刀。当三个月的预算即将用完的时候，新团队让我自己做选择，如果愿意留下，就继续一个季度，如果想走，那也没关系。我说我愿意留下，Marc说你不要为团队着想，为自己着想，再思考一下，周五给我答复。&lt;/p&gt;
&lt;p&gt;思考了许多的我，最终还是选择了提前走，回国开始正式工作。即使这又带来了一系列的麻烦，让我交了差不多2W RMB 的违约金。但交完钱的瞬间，却如释重负。因为再也不想有任何麻烦。&lt;/p&gt;
&lt;p&gt;但心中的谜团，一直都没有解开，直到离开之前的那个周末。&lt;/p&gt;
&lt;p&gt;小伙伴意外地发现了一些蛛丝马迹，然后告诉了我一些惊人的真相：原来当初在团队里和以色列项目经理争夺管理权的华人Z是那个华人HR Dalin的丈夫。而在演讲之前，我以要准备演讲为理由，把Z的一些需求推迟了。然后就出现了第二天，Dalin出乎意料地来听实习生演讲（她再也没出现过），然后当着60人的面批评我的演讲是是最差的演讲。即使在她评价之前，现场小伙伴都在为我鼓掌。&lt;/p&gt;
&lt;p&gt;在团队内部斗争中，我没有站在Z这边，当然我也没有站在以色列那边，我只是一个实习生而已啊，我只想做好我的工作。即使后面出现了互相攻击服务器的低级行为，我也并没有选择站队。但Z在团队中的表现，确实太压迫，也确实导致了团队内部的冲突。最终也斗争失败，转到其他组。&lt;/p&gt;
&lt;p&gt;另一个原因是，Dalin看到我去参观某竞争对手的园区的朋友圈之后，早就对我颇有意见，只是没跟我说。直到我要走的时候，这个事情才传到了我的耳朵里。再加上她因为在公众场合批评我的事情向我的Mentor电话道歉，以及她丈夫在团队内部斗争中的失败，这一切就蛮清晰的了。&lt;/p&gt;
&lt;p&gt;想通这一切的时候，我并没有对她或者她丈夫有太多的怨恨，只是觉得自己所遭遇的一切终于得到了解释，再也不会去瞎猜为什么，真好，毕竟我只要离开就可以了。&lt;/p&gt;
&lt;p&gt;那一天，硅谷的天气好明媚。&lt;/p&gt;
&lt;p&gt;这一天，我选择回来。&lt;/p&gt;
&lt;h3&gt;北京茫然&lt;/h3&gt;
&lt;p&gt;刚回北京的时候，是失落的。
因为感觉和硅谷的环境相比真的太差了。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="硅谷的公寓，春节party举办的地方" src="https://upload-images.jianshu.io/upload_images/5288879-d143b1f5b9d75f47.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;[硅谷的公寓，春节party举办的地方]&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;面对住房，不愿意将就的我，经历了半个多月的折腾，最终还算找到了一个稍微满意的房子，暂住了下来。物质生活上的失落也得到了一丝缓解。&lt;a href="https://www.jianshu.com/p/5407b581e4e0"&gt;《旧北京的新房事》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;而工作上，我也开始遭遇低谷。实习期没有充足的产出，转正没有拿A。头半年没有充足的产出，没有拿A。说实话，是很焦虑的，也是迷茫的。&lt;/p&gt;
&lt;p&gt;在这种低谷的时候，来自外部猎头，内部部门的诱惑还是不少。也曾思考过一些事情。但最后，还是不愿意当一个逃兵，希望自己能在这个岗位上做好，干出成绩，强硬地去面对困难，而不是逃避。&lt;/p&gt;
&lt;p&gt;目前看起来，选择努力和强硬是没有错的。工作上也得到了领导的认可，在工作上也越来越得心应手，产出也开始慢慢变多。那种内心的迷茫和焦虑感随着产出和认可的增加，慢慢减少了，这是很好的迹象。希望今年能有很好的产出，得到很好的认可，越走越好。&lt;/p&gt;
&lt;p&gt;希望今年专利申更多，文稿发更多，能顺利去加拿大参加人生第一个IETF会议。一切都会慢慢变好吧。&lt;/p&gt;
&lt;h3&gt;斜杠青年&lt;/h3&gt;
&lt;p&gt;留北京的另外一个原因是在北京可以继续即兴戏剧的爱好。&lt;/p&gt;
&lt;p&gt;所以在不上班的周末，我都会进城去参加一些即兴的活动，去学习和表演。&lt;/p&gt;
&lt;p&gt;最开始的时候，去开心麻花学习了一段时间的初级课程。然后蹭了好多场排练，学习到了不少知识。&lt;/p&gt;
&lt;p&gt;后来也去了抓马X即兴学习了一些即兴编剧，即兴初级班，认识了很多新朋友，学习了很多新知识。&lt;/p&gt;
&lt;p&gt;但一直以来大部分时间还是在和后严肃的小伙伴一起排练和演出。虽然很多时候，我们排练场地都没有，演出场地也没有，观众每次都要很辛苦地宣传才能来二十来人。但我们乐在其中，一直坚持着。一直让我坚持下来的除了我自己的喜欢以外，还因为团队中有人能懂我，可以进行很认真，深入的交流，这点很难得。&lt;/p&gt;
&lt;p&gt;学习即兴这两年多，从最开始什么都不懂，到慢慢了解规则，然后到演出自信，收获“粉丝”，感觉原来兴趣爱好也可以玩成专业，玩出竞争力。在演出的过程中，会得到一些观众的认可，特别开心！希望以后的日子里面，能在即兴表演这个兴趣爱好上，学到更多，变得更有魅力。努力当一个隐藏的斜杠青年。&lt;/p&gt;
&lt;h3&gt;恋爱生活&lt;/h3&gt;
&lt;p&gt;在感情生活中，我自认为我是矫情的。&lt;/p&gt;
&lt;p&gt;前年跟研究生期间的女朋友分手之后，花了一段时间才走了出来。在这一段时间之内，男男女女，表达喜欢意愿的也不少，第一次感觉自己原来还是有魅力的。感谢他们让我收获自信，帮我走出情感低谷。&lt;/p&gt;
&lt;p&gt;刚开始工作的时候，感情生活真的很寂寞。离开了热闹的学校，离开了熟悉的舍友，一个人在山里生活，有什么话都没什么人说。很煎熬。&lt;/p&gt;
&lt;p&gt;生活的转机出现在我去年生日的时候。我发了一个朋友圈，一个朋友圈好友就联系了我，说想记录我的生日。然后就聊上了。&lt;/p&gt;
&lt;p&gt;她是一个非常有个性，很有品味，很优秀的姑娘。很快的，我们聊的内容越来越多，越来越深入，很多时候能聊到半夜2点多，依然不想结束。而且时常会感受到思想碰撞的共鸣与心流。这让我兴奋！&lt;/p&gt;
&lt;p&gt;我本以为我跟她的聊天会随着时间的推移，慢慢的，就会丧失热情，然后回到自己的单身狗生活。但是她的做事风格，思维逻辑，才华和个性深深地吸引了我。我们不断深入地了解对方，后来变成了每天分享彼此的见闻和想法。&lt;/p&gt;
&lt;p&gt;后来我邀请她来我房间体验了几晚，因为我的房间布置地很好看。当然她来的时候我不在。&lt;/p&gt;
&lt;p&gt;第一次她来的时候，带来了给我的生日礼物，还留下了好几张纸条。哇，那时候觉得好浪漫啊！同一个空间，在不同的时间中，被两个未曾谋面的人占据着，然后彼此有了连接点。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="Hello Distance-大长腿给我的生日礼物" src="https://upload-images.jianshu.io/upload_images/5288879-c8d9a6c95281c2c7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;[Hello Distance-大长腿给我的生日礼物]&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="纸条与纸巾-大长腿的第二个礼物" src="https://upload-images.jianshu.io/upload_images/5288879-25b5a593b0ed046d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;[纸条与纸巾-大长腿的第二个礼物]&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;第二次她来的时候，我留下了7张纸条，把她的生日礼物放在了房间里的某些角落，让她像密室逃脱一般按图索骥地找到我藏起来的礼物。而我，躲在朋友家的床上，跟她聊微信。其中一个礼物是有我签名的我的书，果然是一个很有意思的姑娘。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="image.png" src="https://upload-images.jianshu.io/upload_images/5288879-6984d0a0db72a8d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;[我的礼物-我签名的书]&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;一个平淡到无聊的周五，我们忍不住见面了，然后在一起了。&lt;/p&gt;
&lt;p&gt;开始的时候，我们还很兴奋，发现了彼此更好玩，更有魅力的地方，但慢慢也发现了彼此不一样的地方，产生了冲突。&lt;/p&gt;
&lt;p&gt;那时候下班回家能见到她，好幸福啊。后来我还强行要做饭，给她做了三顿红烧排骨。那时候第一次在北京有了家的感觉。&lt;/p&gt;
&lt;p&gt;但后来她开始忙了，开始实习了，回家就见不到她了。后来我们更忙了，周末都开始安排满了，我去参加排练和表演；她写文章，组织观影活动。彼此都没有抽出时间来陪对方。矛盾开始慢慢激化，我也开始觉得心累。&lt;/p&gt;
&lt;p&gt;没有互相联系的一周之后，最终我们还是散了。&lt;/p&gt;
&lt;p&gt;从最开始的浪漫，到在一起的激情，再到后来矛盾出现的疲惫，再到后面的失落和放弃。时间真的好短好短！短得让我还没反应过来，就结束了。&lt;/p&gt;
&lt;p&gt;失恋就像感冒，在你以为好的时候，总会复发。&lt;/p&gt;
&lt;p&gt;而我失恋的时候，还感冒了。再加上房东卖房，被迫搬家，我有一次体会到了生活对我的恶意，体会到了北漂的不安与心酸。&lt;/p&gt;
&lt;p&gt;感谢大长腿给我一段高质量、美好感情生活，教会了我很多很多。如何输入，如何思考，分析，如何输出。甚至如何去坦诚地面对自己的欲望，正视自己的脆弱和不足。&lt;/p&gt;
&lt;p&gt;谈恋爱是为了追求真爱，即使失败，如果能从中得到成长，那也是极幸运的了。所以我是幸运的。但是再也不能跟她分享想法了，也没办法像在一起之前那样兴奋地交流了，好可惜。&lt;/p&gt;
&lt;p&gt;在分手之后，我在情绪波动反复的过程中，做了一些愚蠢的事情，让对方感受到了压力与不安。回想起来真的很不好意思。对美好的留恋，对逝去的可惜，总让我不愿意去放手，但其实一切都过去了。&lt;/p&gt;
&lt;p&gt;下一个如此合拍的人，又在哪里？我们会在什么场合相见。
相信，我总会等到姗姗来迟的你。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.jianshu.com/p/a1f7621956dd"&gt;《“会”吵（沟）架（通）的人更幸福》&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;起风了，黎明&lt;/h3&gt;
&lt;p&gt;这是跌宕起伏，饱受折磨的一年，也是我开始独立面对艰难生活的一年。&lt;/p&gt;
&lt;p&gt;从硅谷的遭遇，到工作的失意，再到感情的放弃，这一年，真的遭遇了太多的艰辛。但美国的故事过去了，工作的低谷走出来了，感情的事情，也慢慢释怀了。&lt;/p&gt;
&lt;p&gt;书写这些文字的时候，我坐在海南的家里。为了暂时的逃避生活的压力，也为了让自己有一些间隙喘息，也为了回来看看爸妈，看看爷爷。所以我偷偷飞回家了，给爸妈他们一个惊喜。&lt;/p&gt;
&lt;p&gt;等我回北京，我会搬进新的房子，然后鼓起斗志，努力工作。
&lt;a href="https://www.jianshu.com/p/607b7dc9370a"&gt;《北漂：不舍的不仅是房子，还是美好的回忆》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;同时，我也想着要做出一些改变，给生活带来一些不一样的东西。
我要恢复健身，我要考驾照，我要学表演，我要戴牙套。
我要坚持读书，扩大输入和分析，这是我从大长腿身上学习到的优点。&lt;/p&gt;
&lt;p&gt;全面进化吧，要去做更好的自己。
起风了，黎明，我就要出发。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.jianshu.com/p/f23364c1e9a2"&gt;《2016总结：杀死那个天真的自己》&lt;/a&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 03 Jun 2018 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2018-06-03:pages/2018/06/03/chi-dao-de-2017zong-jie-qi-feng-liao-li-ming.html</guid></item><item><title>简历：专业而美的“术”与“道”</title><link>http://www.muzixing.com/pages/2017/08/06/jian-li-zhuan-ye-er-mei-de-zhu-yu-dao.html</link><description>&lt;p&gt;“我什么都不会”，“我什么都没干”，“这个项目很水”，这是我在帮别人修改简历时听到的最多的几句话。难道你真的什么都不会吗？真的什么都没干吗？真的很水吗？其实很多情况下，是这样的。&lt;/p&gt;
&lt;p&gt;但是很水就放弃治疗了吗？不会的。放下无谓的抱怨和遗憾，好好梳理自己，认真编写简历才能解决问题。然而，写简历却是一个大学问。&lt;/p&gt;
&lt;p&gt;最近帮朋友改了几封简历，反馈不错，转念一想，为什么不把自己的小技能写成一篇文章呢。所以我决定写一篇长文来记录自己的心得，也给别人提供一些帮助。&lt;/p&gt;
&lt;p&gt;本文将介绍如何写好一份技术类简历，尤其指计算机方面的技术简历。读者可以按照文章介绍的技巧去修改自己的简历，相信会有不错的效果。文章的主要内容包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;简历的重要性&lt;/li&gt;
&lt;li&gt;如何写好简历&lt;ul&gt;
&lt;li&gt;格式&lt;/li&gt;
&lt;li&gt;内容书写&lt;ul&gt;
&lt;li&gt;基本信息&lt;/li&gt;
&lt;li&gt;实习／项目&lt;/li&gt;
&lt;li&gt;所获奖项&lt;/li&gt;
&lt;li&gt;个人技能&lt;/li&gt;
&lt;li&gt;其他技能／社会实践&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;内容编排&lt;ul&gt;
&lt;li&gt;排序&lt;/li&gt;
&lt;li&gt;针对性&lt;/li&gt;
&lt;li&gt;锦上添花or画蛇添足？&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;简历之道&lt;ul&gt;
&lt;li&gt;作品化思维&lt;/li&gt;
&lt;li&gt;索引理论&lt;/li&gt;
&lt;li&gt;工匠精神&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cover letter&lt;ul&gt;
&lt;li&gt;发简历的黄金时间&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;总结&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;专业而美是一份简历的最终追求。首先，专业是对一份技术简历最基本也最重要的要求，其次才是美。对于一个非设计类简历而言，能让HR快速地理解简历的信息布局，聚焦到简历所想要展现的专业实力，就达到了笔者认为的美的要求。&lt;/p&gt;
&lt;p&gt;虽然专业性比美重要，但在“如何写好简历”部分，将从难度低而受众广的格式修改入手，争取让读者快速地感受到简历变美的过程，然后再介绍专业性强且难度高的内容修改部分。&lt;/p&gt;
&lt;h2&gt;简历的重要性&lt;/h2&gt;
&lt;p&gt;见“历”如见人。简短的一份简历，其实足以展现一个人的许多方面。一份优秀的简历，可以展现一个人优秀的专业能力，良好的审美，严谨的做事风格，条理清晰的思维习惯和优秀的文字表达能力等等方面的信息。所以写好简历是一件非常重要的事，不论是对于找工作，还是自我梳理。&lt;/p&gt;
&lt;h2&gt;如何写好简历&lt;/h2&gt;
&lt;p&gt;这部分将分为格式，内容书写，内容编排和简历之道四部分来介绍。&lt;/p&gt;
&lt;h3&gt;格式&lt;/h3&gt;
&lt;p&gt;首先，当拿到一份简历的时候，会被其整体的外观所吸引，然后才会注意到局部的信息。所以简历的布局和格式显得格外重要。简历应该被当作一件平面设计来设计，需要追求整体画面的平衡，同时也要保证信息能够高效清晰地表达。&lt;/p&gt;
&lt;p&gt;不要过度设计，因为HR看简历只希望快速定位信息，而过度设计很容易分散注意力。而且，很多人并没有足够的能力设计复杂的简历。所以简约就是美。&lt;/p&gt;
&lt;p&gt;本文提到的简历编写软件为Word。对应的格式上的小建议列举如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;用表格，偷偷用&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;一封简历，首先需要对齐和工整。使用表格可以很轻易地让你实现对齐，不需要担心字符占位大小不同而引起的对齐困难，也不需要担心不同部分的内容的对齐问题。而且在移动内容的过程中，使用表格可以保持原有的格式，不会产生格式错乱。但是使用表格不是明目张胆地使用，而要偷偷用。如下图有边框的简历所展现出来的审美就很让人难过。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx2.sinaimg.cn/mw690/7f593341ly1fi5rm8mv6gj20kc07sjt2.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1.使用表格的错误示范&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;如何做到让别人看不出用了表格？答案就是把表格表框隐藏掉。可以保留上边框来做内容划分，但不需要保留内部边框等多余边框。正确示范：&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx4.sinaimg.cn/mw690/7f593341ly1fi5s003fmjj219g0us7hr.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图2.使用表格&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx1.sinaimg.cn/mw690/7f593341ly1fi5rzufgnij219c0ue15t.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图3.隐藏边框后&lt;/center&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;无序列表&lt;/strong&gt;
    项目的描述千万不要以段落的形式表现，阅读难度太大。内容的介绍一定要选择无序列表来分点描述。在简历中采用段落表达信息的人的思维习惯一般都不够好，缺乏条理性。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx1.sinaimg.cn/mw690/7f593341ly1fia1wifjctj20xa0bg7ac.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图4.整段描述与无序列表对比&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;使用无序列表而不使用有序列表的原因在于前后顺序已经足够，没必要使用数字编号，其次数字会带来额外的信息，分散注意力，而且1，2，3，4的字形不一样，占位宽度也不一样，视觉上没有小圆点等统一的标志舒服。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;单条信息不跨行&lt;/strong&gt;
    任何的分点信息都可以一行写完的，如果不能一行写完，就需要分成两点写。单条信息跨行会影响阅读体验和视觉效果。&lt;/p&gt;
&lt;p&gt;从阅读角度看，如果是一个词被切分到两行，阅读体验会降低，而且句子太长会读起来太累。从视觉角度看，跨行句子很难做到填满两行，第二行往往少于1／2行，且两行与其他行不统一，影响整体效果。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;左对齐还是居中&lt;/strong&gt;
    姓名等关键标题可选择左对齐或者居中。根据实际需求选择。&lt;/p&gt;
&lt;p&gt;左对齐在阅读上更舒服，而且也可以支持将照片放在右侧，从而实现整体画面的平衡。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx2.sinaimg.cn/mw690/7f593341ly1fi5t3n8ba1j216c0fu0y4.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图5.左对齐&lt;/center&gt;  &lt;/p&gt;
&lt;p&gt;居中在整体视觉感受上更好，更有设计感。不放照片时，中心对称的画面平衡感更好，而且更容易让视线聚焦在关键的信息上。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx2.sinaimg.cn/mw690/7f593341ly1fia6cvq1rmj20ye08675a.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图6.居中&lt;/center&gt;  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;页边距&lt;/strong&gt;
    默认的页边距上下左右都是2.54cm，页边距太宽，不好看，而且行长度太短，容易导致内容跨行的现象。&lt;/p&gt;
&lt;p&gt;所以最好采用自定义页边距，左右页边距和上下页边距都可以稍微窄一些，这样可以写下更多内容，整体看起来内容更饱满。尤其在内容稍微多余一页内容时，调整页边距是一个行之有效的方法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;行间距&lt;/strong&gt;
    行间距对于整体内容的视觉效果影响也极大。1.5倍行距对于简历而言太宽，可以选择1.2或者单倍行距。具体数值以视觉上舒服为准。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;字体&amp;amp;字号&amp;amp;颜色&lt;/strong&gt;
    所有的标题采用黑体或者微软雅黑等等宽字体。标题应该加粗。&lt;/p&gt;
&lt;p&gt;对于正文的格式，汉字可选择宋体，英文可以选择Times new Roman，但更推荐Garamond或Calibri。也可尝试其他字体，只需保证中英文搭配美观，不突兀。&lt;/p&gt;
&lt;p&gt;字号方面，视内容而定。如果内容饱满，建议标题采用10.5磅，而正文选择10磅。9磅字太小不推荐使用。如果内容不够饱满，则可以依次增大一磅，或者标题选择小四，正文选择五号。虽然五号的字体对于简历而言已经有点太大了。&lt;/p&gt;
&lt;p&gt;字体颜色方面，如果底色是白色的话，建议选择黑色一种字体颜色即可。如果简历底色是并非白色，则需要根据色彩搭配的一些基本技巧，做到文字明显而不突兀。颜色搭配难度很大，容易弄巧成拙，不建议采用非白色底色。&lt;/p&gt;
&lt;p&gt;中文保持正常字体，不要加下划线（超链接的下划线可以接受）和斜体。英文部分也建议正常字体。斜体等特殊字体属于强调字体，在写纯英文简历时可以考虑，中文简历不建议。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;英文格式&lt;/strong&gt;
    首字母一定要大写，专业名词一定要把大小写写对。比如MySQL而不是Mysql。这些技术名词的书写很重要，如果写错，会很影响专业印象分。&lt;/p&gt;
&lt;p&gt;对于单词首字母大写的技巧，使用Windows的同学不要忘记小魔法：Shift+F3。选中单词后，按一下这个快捷键你就知道都有哪些变化了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数字&lt;/strong&gt;
    数字与英文同字体。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;加粗&lt;/strong&gt;
    一份专业的简历不需要对正文部分的某些内容进行加粗，只需要加粗标题、时间、地点等信息即可。在很多文章中会建议对简历中的某一些内容加粗，比如加粗“一等奖”等信息，以凸显重点信息。但是笔者认为这是一种不太专业的做法。首先，凌乱的加粗词语会在影响整体美观，其次会让人觉得急于表现，不够专业。你应该自信简历中的重点都会被很好的捕捉到，而不应该急切的通过加粗来强调一些逻辑重词。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;标点符号&lt;/strong&gt;
    标点符号也很大程度影响着格式的美观。每个分点之后可以选择使用分号或句号，也可以选择不使用符号结尾。笔者建议不使用标点符号结尾。因为在分点结尾使用标点符号看起来会比较冗余。&lt;/p&gt;
&lt;p&gt;标题部分可能会使用到冒号和破折号，需要注意这两个符号的视觉效果，具体选择哪一个，需要根据整体效果来选择。&lt;/p&gt;
&lt;p&gt;根据内容需要正确的使用逗号，顿号和分号。标点符号的使用规则请电话高中语文老师。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;底色&lt;/strong&gt;
    建议不对底色进行修改，保持白色即可。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;校徽&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不建议。即使校徽是TOP2，也显得不自信。不出名的校徽别人看不懂，不需要加，出名的校徽不需要加，标题中的学校和专业信息已经足够。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;页数&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;页数方面，建议一页，两页亦可。唯一的标准是满页。如果你的内容足够多，一页内容放不下，那么可以两页，但是要保证第二页的内容是满的，而不能到一半。没有注意到这个细节的人，做事一般不严谨，不会从全局的角度去思考和布局。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;文件格式&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PDF。保证任何情况下格式不错乱。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;文件名&lt;/strong&gt;
    如果招聘单位没有给出具体的文件名格式，那么简历的命名方式可以用：姓名+学校／专业+岗位 + 简历（可选）。&lt;/p&gt;
&lt;p&gt;首先姓名和学校／专业这两个关键的信息，已经让HR对应届生有了基本的了解，岗位则明确了求职目的。这三点信息其实已经足够，而简历”两个字可以让HR在邮件分类和检索的时候更快，所以为可选信息。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;内容书写&lt;/h3&gt;
&lt;p&gt;谈完格式，接下来将介绍难度更高的内容书写。&lt;/p&gt;
&lt;p&gt;首先，简历的内容应该满足以下基本三点要求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;信息完整&lt;/li&gt;
&lt;li&gt;高效不冗余&lt;/li&gt;
&lt;li&gt;专业&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如何做到信息完整？如何做到信息高效？什么样的描述是专业的？这些都将会在接下来的内容中介绍。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;基本信息&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当拿到一份简历的时候，第一时间需要让HR看到姓名+学校+专业，所以标题中&lt;strong&gt;姓名和学校·专业&lt;/strong&gt;信息是必须要放在前两位的。&lt;/p&gt;
&lt;p&gt;为了让HR在想联系你的时候，第一时间能定位到你的联系信息。还应该把你的电话和电子邮箱地址放在标题 上。“姓名+学校·专业+电话+Email”的四维信息已经构成了最常见的简历标题。&lt;/p&gt;
&lt;p&gt;如果你的博客或者Github或者其他的个人网站含金量够高，一定要放在标题部分，这绝对是一个吸引注意力的最佳位置。&lt;/p&gt;
&lt;p&gt;以下的信息坚决不要出现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通信地址／家庭住址等一系列居住地址信息。时代变了，没人会给你寄纸质的信件。&lt;/li&gt;
&lt;li&gt;星座，即使你是一个绝对的星座信徒，也不要写，因为还有很大一部分像我这样不相信的人，而且会显得你很不专业。&lt;/li&gt;
&lt;li&gt;"政治身份：团员"。我猜你看这篇文章的时候，你的年纪估计已经自动退团了吧。这个时候还不是党员／预备党员的只有两类人：主动不入党的和被动不入党的。而写上政治身份为团员的人一般是被动不入党的。所以写上去大概率是要被扣分的。如果是党员／预备党员，可以选择性添加，取决于这个信息对简历有没有加分。如果找国企和国内民企，建议加上。如果找外企，建议不要。&lt;/li&gt;
&lt;li&gt;民族：这不是高考，不会加分的。只看能力，不看民族。&lt;/li&gt;
&lt;li&gt;QQ／微信：难道你渴望HR通过QQ／微信联系你？还是加你好友一起嗨？&lt;/li&gt;
&lt;li&gt;身体状况：除了写“健康／良好”，不知道还可以写什么。如果不健康，还是先养好革命本钱，再找工作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;奇怪的信息很多，但是关键的信息只有少数几部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;姓名&lt;/li&gt;
&lt;li&gt;学校·专业&lt;/li&gt;
&lt;li&gt;电话&lt;/li&gt;
&lt;li&gt;Email&lt;/li&gt;
&lt;li&gt;性别&lt;/li&gt;
&lt;li&gt;出生年月（写到月份即可，完整写完太长，保持神秘性。）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其他的可以看情况选择添加。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;教育信息&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;教育信息对于应届生而言非常重要，尤其对于学校还不错，希望通过学校给自己加分的同学。教育信息要写简介，只需要写清楚“&lt;strong&gt;时间+学校+专业+GPA／排名（可选）&lt;/strong&gt;”信息即可。如果本硕都在一个学校，则可以只写一条。可以使用以下的格式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="mi"&gt;2014&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2017&lt;/span&gt;  &lt;span class="err"&gt;北京邮电大学·通信工程·硕士研究生&lt;/span&gt;    &lt;span class="n"&gt;GPA&lt;/span&gt;&lt;span class="err"&gt;：&lt;/span&gt;&lt;span class="mf"&gt;3.5&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;也可以采用以下的格式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="mi"&gt;2015&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2018&lt;/span&gt;  &lt;span class="err"&gt;工学硕士&lt;/span&gt;     &lt;span class="err"&gt;北京邮电大学·通信工程，排名&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;关于GPA的问题，如果你觉得你的GPA足够好，那就写；如果不好，则可以不写，以免减分。GPA对简历的加分远不如一个含金量高的项目。因为不同学校的GPA标准相差太大。排名信息同理。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx3.sinaimg.cn/mw690/7f593341ly1fia2mvphhtj20wi02et95.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图7.教育信息&lt;/center&gt;  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实习／项目&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;实习和项目对于应届生而言，是最重要的内容，也是最难写的部分。&lt;/p&gt;
&lt;p&gt;首先，对于实习而言，标题的信息主要包括“时间+公司·部门·项目+职位（可选）”，所以标题的推荐格式如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="err"&gt;时间&lt;/span&gt;           &lt;span class="err"&gt;公司·部门·项目&lt;/span&gt;                          &lt;span class="err"&gt;职位（可选）&lt;/span&gt;

    &lt;span class="mf"&gt;2016.7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2017.2&lt;/span&gt;  &lt;span class="err"&gt;华为·终端产品线：&lt;/span&gt;&lt;span class="n"&gt;P18&lt;/span&gt;&lt;span class="err"&gt;·手机中的战斗机项目&lt;/span&gt;    &lt;span class="err"&gt;软件工程师&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;当遇到组织架构很多级的时候，不需要写完整信息，要选择具有代表性的部门名称。比如华为某产品线的某部门的某小前端部门，则可以选择写大的产品线，或者和业务直接相关的前端部门名称。&lt;/p&gt;
&lt;p&gt;关于实习的地点信息，如果实习都在国内，则没有必要标注国家。甚至，对于大部分实习而言，也完全没有必要添加地点信息。除非需要突出地点的意义。&lt;/p&gt;
&lt;p&gt;职位信息为可选信息，如果实习的经历都为同类型，比如同为软件开发工程师，则不需要写。如果开发和产品都有，则需要区分职位。但是一封专业的简历里面，最好不要出现不同类型的实习。&lt;/p&gt;
&lt;p&gt;对于项目标题而言，同样也可以采用这种格式。但是由于一般项目都在实验室中完成，且大多数实验室的名气不大，并不会起到太多加分作用，所以建议不写，而改为项目级别等前缀，比如：国家863计划，国家973计划，以彰显项目的重要性：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="err"&gt;时间&lt;/span&gt;            &lt;span class="err"&gt;级别·项目&lt;/span&gt;                 &lt;span class="err"&gt;职位（可选）&lt;/span&gt;

    &lt;span class="mf"&gt;2016.7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2017.2&lt;/span&gt;  &lt;span class="err"&gt;国家&lt;/span&gt;&lt;span class="mi"&gt;863&lt;/span&gt;&lt;span class="err"&gt;计划·超厉害的项目&lt;/span&gt;    &lt;span class="err"&gt;软件工程师&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;对于实习和项目的内容，要求是一定要用无序列表分点写，而不是一大段一大段地写。&lt;/p&gt;
&lt;p&gt;错误示范：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="mf"&gt;2016.7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2017.2&lt;/span&gt;  &lt;span class="err"&gt;国家&lt;/span&gt;&lt;span class="mi"&gt;863&lt;/span&gt;&lt;span class="err"&gt;计划·超厉害的项目&lt;/span&gt;
    &lt;span class="err"&gt;项目简介：项目主要使用了&lt;/span&gt;&lt;span class="n"&gt;xx&lt;/span&gt;&lt;span class="err"&gt;库，采用了&lt;/span&gt;&lt;span class="n"&gt;xx&lt;/span&gt;&lt;span class="err"&gt;架构，巴拉巴拉，实现了&lt;/span&gt;&lt;span class="n"&gt;xx&lt;/span&gt;&lt;span class="err"&gt;。我一定要写一段，写不够一段我也要撑够一段来示范写成一段有多恶心。我很努力写了，但是还是没有到一段，我也没有办法，我也很绝望啊。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;正确示范：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="mf"&gt;2016.7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2017.2&lt;/span&gt;  &lt;span class="err"&gt;国家&lt;/span&gt;&lt;span class="mi"&gt;863&lt;/span&gt;&lt;span class="err"&gt;计划·超厉害的项目&lt;/span&gt;
    &lt;span class="err"&gt;·&lt;/span&gt; &lt;span class="err"&gt;采用&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;软件，搭建了&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;实验平台&lt;/span&gt;
    &lt;span class="err"&gt;·&lt;/span&gt; &lt;span class="err"&gt;基于&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;，实现了&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;功能&lt;/span&gt;
    &lt;span class="err"&gt;·&lt;/span&gt; &lt;span class="err"&gt;应用部署在&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;，成功运行&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;小时／提升了&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;性能。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;内容部分，“项目简介”以及一句话的项目介绍如“在XX公司XX部门参与XX工作，主要内容包括：”都是冗余的信息，均不需要出现。在项目标题之下的内容，自然就是项目相关的介绍，所以不需要任何额外的文字来过渡，直接接项目内容即可。&lt;/p&gt;
&lt;p&gt;所以如何将一件事分割成多个小点并写好是这部分的重点。&lt;/p&gt;
&lt;p&gt;将一件事划分为多个小点时，各点之间的逻辑关系基本上是承接和并列关系。按照逻辑承接顺序，大致的划分为三部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实验环境搭建&lt;/li&gt;
&lt;li&gt;实验实施&lt;/li&gt;
&lt;li&gt;实验结果&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以建议一个项目最好分三点写，最少两点最多四点。当然也可以根据项目的功能逐点列举。举例如下：&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx4.sinaimg.cn/mw690/7f593341ly1fi6wzbq3scj212q05k0vn.jpg" /&gt;&lt;/center&gt;
    &lt;center&gt;图8.分点写项目示意&lt;/center&gt;  &lt;/p&gt;
&lt;p&gt;从上例可以看出，第一点：调研了现有的解决方案，提出了自己的解决方案；第二点介绍了方案的设计与实现；最后一点介绍了实验结果。其写法和写论文的摘要很像：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;调研了别人的成果，找到了Gap&lt;/li&gt;
&lt;li&gt;设计了我们的解决方案，提供了新的解决思路&lt;/li&gt;
&lt;li&gt;部署实施了解决方案，提高了什么性能，解决了什么问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，也可以按照功能逐点介绍，前后顺序以功能的依赖顺序为准，比如：&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx1.sinaimg.cn/mw690/7f593341ly1fi6x3dcl3yj20y604e404.jpg" /&gt;&lt;/center&gt;
    &lt;center&gt;图9.顺序介绍功能&lt;/center&gt;  &lt;/p&gt;
&lt;p&gt;首先，探测发现了XX信息，实现了信息可视化，然后基于第一点功能得到的信息，做了信息分析，提供了什么解决方案。前后点的关系是依赖关系或承接关系。&lt;/p&gt;
&lt;p&gt;对于分点的书写要求是：可以顺畅地一行读完，信息清晰完整而不冗余。&lt;/p&gt;
&lt;p&gt;从语法上，应减少甚至不使用形容词和副词，从而减少主观形态对事实的影响，影响简历的专业性。也不能使用太长的定语和补语，避免影响阅读体验。一般的，语法结构为&lt;strong&gt;动宾结构&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;【采用／基于／部署】了&lt;/span&gt;&lt;span class="n"&gt;xx&lt;/span&gt;&lt;span class="err"&gt;【技术／语言／框架／实验平台／工具／算法】，【实现／提升／改善】了&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;【功能／效率／性能】。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在词语的选择上，建议采用以上示例中的词语。如果不知道选哪一个，查一查专业文档就知道哪些词语搭配更合适。比如应该用提升了效率，而不是增加了效率。&lt;/p&gt;
&lt;p&gt;时态方面，应选择完成时，所以必要的“了”字不能少。比如“提升了15%的性能”，而不是“提升15%的性能”，也不是表目的的“去提升15%的带宽利用率”。根据实际情况，也可以使用现在进行时。&lt;/p&gt;
&lt;p&gt;但是光知道句式还不能完全解决问题，还需要写得专业和高大上。两个小秘诀可以快速提高专业度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多使用直观的数字来取代模糊的形容词。比如“提升50%的计算性能”就要比“大幅提升计算性能”要直观而专业得多。&lt;/li&gt;
&lt;li&gt;使用专业英文缩写。比如“SDN”就要比“软件定义网络”要专业而且节省空间得多。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，如果有高质量的辅助材料比如GitHub repository、网站、博客、论文和书籍等的链接，请一定要加上。这些链接可以让HR快速验证简历内容的真实性。同时，这些材料也将加深HR的印象，给HR展现更全面的信息。&lt;/p&gt;
&lt;p&gt;最后，在写简历时需要注意高频字“并”字的使用。如果是明显的递进，或者并列的关系则可以使用“并”。如果是弱关系，因果关系，则不要使用“并”。具体看实际内容，以阅读舒适度为取舍标准。&lt;/p&gt;
&lt;p&gt;再拆分一件事的时候，如果分点太多，就需要摘取关键信息，忽略过程，强调结果。细节信息可以留到面试时再进行细致的交流和讨论。对于分点内容太少的情况则需要扩写。扩写的方法主要有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增加新内容&lt;/li&gt;
&lt;li&gt;润色原有内容，增加效果和影响&lt;/li&gt;
&lt;li&gt;拆分内容，细化。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;所获奖项&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;任何一个人都会或多或少得到一些奖励，比如“再来一瓶”。但不是所有的奖项都需要写到简历上，比如月度宿舍卫生大赛冠军。&lt;/p&gt;
&lt;p&gt;奖项的选择上需要按照相关度来选择。相关度越高优先级越高。奖项的优先级一般从高到低是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;专业相关&lt;/li&gt;
&lt;li&gt;学业相关&lt;/li&gt;
&lt;li&gt;管理等辅助技能相关&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;专业相关的奖项权重最大。比如对于研究大数据的同学而言，拿一个大数据比赛的奖对奖学金的含金量要高。然后是学业相关的奖项，比如三好学生，市级，校级奖学金等等。奖学金的含量需要考虑学校级别，以及学院、专业人数等因素，所以很多情况下不如跨学校的专业领域大赛奖项重要。最后是管理类等辅助技能相关奖项，可以从侧面反应一个人的综合素质。但是由于此类奖项含金量无法保证，所以一般放在最后。&lt;/p&gt;
&lt;p&gt;相关性不强的奖项不建议写，写上去反倒会分散注意力，有撑场面的嫌疑，往往会减分。比如我就不会把我十几张短跑奖状写上去，毕竟不是应聘体育老师。&lt;/p&gt;
&lt;p&gt;此外，多个同性质的奖项要合并写，会显得更专业。同性质的奖学金分几条写，有撑行数的嫌疑。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;个人技能&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;技能部分是一个简历中非常重要的一部分，也是最容易犯错的一部分。&lt;/p&gt;
&lt;p&gt;首先，每个人或多或少都会有很多技能，比如动耳朵。但不是每一个技能都可以加分，比如用口水吹泡泡。所以技能的选择有很大的讲究。选择的标准其实和个人奖项一样：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;专业相关&lt;/li&gt;
&lt;li&gt;学业相关&lt;/li&gt;
&lt;li&gt;管理等辅助技能相关&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如投前端同学，需要写前端相关的技能，例如熟练VUE和React等等。投后端开发的同学可能需要写掌握的编程语言以及所投岗位所需的专业能力。比如熟练Python，掌握Hadoop，熟悉OpenStack等等。&lt;/p&gt;
&lt;p&gt;完成内容选择之后，还需要注意表达方式。某些做前端的同学特别喜欢用饼图，柱状图和条形图等一些非常直观的表达形式来描述技能掌握程度。但是这是一种不太建议的方式。&lt;/p&gt;
&lt;p&gt;不建议的原因有以下几点。首先每一个人认为的100%都是自己的100%，并没有什么参考价值。然后掌握程度85%又是什么程度呢？3/4又是什么程度呢？这些都是没有办法用具体的指数描述的。而这都不是最致命的，最致命的是：很多时候，这样的图形表达的设计太难看，面积过大，信息表达效率过低。所以这种吃力不讨好的行为不值得提倡。&lt;/p&gt;
&lt;p&gt;从专业角度来看，只能用以下四个词来形容对技能的掌握程度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;了解&lt;/li&gt;
&lt;li&gt;掌握&lt;/li&gt;
&lt;li&gt;熟悉&lt;/li&gt;
&lt;li&gt;精通&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这四个词可以很好地描述对技能的掌握程度。当你使用“了解”的时候，别人知道你真的只是了解了概念；用“掌握”的时候，别人知道你大概就是入门的水平；用“熟悉”的时候，别人能大概猜到你已经比入门要高级一些，但是熟悉到什么程度，还需要面试才能确定；用“精通”的时候，别人就会疑惑你到底有多厉害，才会用“精通”，所以面试的时候一定会抓住这点问。所以如果你不是真的精通，请不要用精通。但是如果真的精通，请不要吝啬使用这个抓眼球的形容词。&lt;/p&gt;
&lt;p&gt;此外，在描述技能的时候，并不是简单地写“了解／掌握／熟悉／精通【技能】”就可以了。还需要要加上更多信息来佐证。比如，“熟悉Python，使用Python语言开发OpenStack两年”。所以推荐的句式是：“【掌握程度】【对象】，使用【对象】【做了什么】【多长时间】”。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;其他技能／社会实践&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当写完以上的内容之后，简历还不够充实，可以通过其他技能来展现自己的能力。一般的，其他技能分为两部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;领导能力（Leadership）&lt;/li&gt;
&lt;li&gt;团队协作（Teamwork）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;领导能力方面主要表现为对团队的领导以及管理方面的能力，需要通过具体事件来凸显，具体要求与项目与实习部分的要求一致。团队协作同理。这部分的内容不宜过多，两三点足矣。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx1.sinaimg.cn/mw690/7f593341ly1fi8xjdcgxhj219804awg5.jpg" /&gt;&lt;/center&gt;
    &lt;center&gt;图10.社会实践&lt;/center&gt;  &lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx3.sinaimg.cn/mw690/7f593341ly1fia3sxalhuj21dm0puwkb.jpg" /&gt;&lt;/center&gt;
    &lt;center&gt;图11.其他技能(中文版同理)&lt;/center&gt;  &lt;/p&gt;
&lt;h3&gt;内容编排&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;排序&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以上的内容介绍了如何书写简历的每一个部分。但是每一个人的情况都不一样，有的人学历高，有的人实习好，有的人项目做得很出色，也有的人大奖拿了一大堆等等。所以，在内容的编排上面就需要讲究一下策略，努力突出优势。&lt;/p&gt;
&lt;p&gt;首先，从阅读心理角度考虑，阅读的重点从左到右逐渐降低，从上到下逐渐降低。所以左上区域会得到最多的关注，应该放最重要的信息，而右下是最不被关注的区域。所以一般的，简历都选择左对齐，而且重要的内容需要放在最前面。这一点，基本属于废话（谁不知道把重要的放在前面）。&lt;/p&gt;
&lt;p&gt;所以，内容的排序非常重要。需要按照个人的实际情况，把内容进行重要性排序，重要的内容排在前面，无关紧要的放在后面，以此来突出自己的优势，抓住HR的眼球。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;针对性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果换位思考，假如你是HR，你想要看到什么简历？当然是和招聘需求符合的人，而这个需求可以清晰地从Job Description（JD，不是京东）得到。所以写简历，&lt;strong&gt;最重要的一点就是要根据JD的要求针对性地写简历&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;以华为杭州研究所招聘JD为例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;公司名称：华为杭州研究所&lt;/span&gt;
&lt;span class="err"&gt;工作地点：杭州&lt;/span&gt;

&lt;span class="err"&gt;岗位职责：&lt;/span&gt;
&lt;span class="err"&gt;对接全球各局点云平台的核心需求，支撑华为云计算在全球各公有云和私有云局点的交付，针对不同的客户场景进行优化，提升架构通用性、可靠性、可扩展性以及安全性等。&lt;/span&gt;

&lt;span class="err"&gt;岗位要求：&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;、&lt;/span&gt; &lt;span class="err"&gt;本科及以上学历&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;、&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;年以上的&lt;/span&gt;&lt;span class="n"&gt;Java&lt;/span&gt;&lt;span class="err"&gt;或者&lt;/span&gt;&lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="err"&gt;开发经验，&lt;/span&gt;&lt;span class="n"&gt;Java&lt;/span&gt;&lt;span class="err"&gt;或者&lt;/span&gt;&lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="err"&gt;基础扎实，对性能和安全性较为敏感；&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;、&lt;/span&gt; &lt;span class="err"&gt;具有大中型分布式系统开发及运维调优经验的优先；&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;、&lt;/span&gt; &lt;span class="err"&gt;对开源项目&lt;/span&gt;&lt;span class="n"&gt;openstack&lt;/span&gt;&lt;span class="sr"&gt;/XEN/&lt;/span&gt;&lt;span class="n"&gt;KVM&lt;/span&gt;&lt;span class="sr"&gt;/Zabbix/&lt;/span&gt;&lt;span class="n"&gt;ELK&lt;/span&gt;&lt;span class="err"&gt;有开发经验或者熟悉源代码的优先；&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;、&lt;/span&gt; &lt;span class="err"&gt;熟悉&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="err"&gt;、&lt;/span&gt;&lt;span class="n"&gt;Oracle&lt;/span&gt;&lt;span class="err"&gt;等数据库开发和管理的优先；&lt;/span&gt;
&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;、&lt;/span&gt; &lt;span class="err"&gt;有虚拟网络、物理网络工作经验者的优先；&lt;/span&gt;
&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="err"&gt;、&lt;/span&gt; &lt;span class="err"&gt;具有很强的团队意识和沟通能力，学习能力和工作主动向强，充满激情，乐于接受挑战；&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;首先，我们可以从岗位职责中了解到这份工作的具体内容，可以判断出这份工作是否符合我们的想象。然后岗位要求介绍了招聘部门需要拥有什么能力的人。有了这个明确的信息指导，接下来我们就需要针对岗位要求，逐条修改简历。比如针对本JD，简历中就需要强调对Java和Python的掌握。第3，4，5，6点是专业相关的要求，如果有对应的项目或实习，一定要优先排在前面，重点突出。这样修改出来的简历就是HR希望看到的简历。&lt;/p&gt;
&lt;p&gt;如果你修改出来的简历就是HR想要的简历，自然就容易得到面试机会。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;锦上添花or画蛇添足&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;想必看到这里的读者都很优秀，简历内容充实，有很多内容值得修改。对于类似于你这样的拥有很多亮点的人，想要表现的信息也必然很多，所以选择简历内容就显得尤为重要。有的信息加上去是锦上添花，而有的，就是画蛇添足。&lt;/p&gt;
&lt;p&gt;照片是否要加？这个需要按照JD的要求。如果对方不要求，那么就需要自己考虑一下所申请岗位对颜值的需求。对于那些不需要颜值的岗位，除非你的照片很好看，否则不建议加。&lt;strong&gt;如果加照片，请一定要用正装证件照&lt;/strong&gt;，而不是大头贴和生活照。&lt;/p&gt;
&lt;p&gt;简历的颜色方面，对于非设计类简历而言，黑白即可。除非对自己的设计很满意，否则不需要对简历的内容添加黑白以外的其他颜色。&lt;/p&gt;
&lt;p&gt;如果你的博客写得很好，Github账号质量很高，公众号、网站或者APP等质量很高的话，一定要在简历中体现。这些作品可以从很长的时间维度上展现你的实力，绝对是加分利器。&lt;/p&gt;
&lt;p&gt;除了以上提到的内容，基本上就不需要添加其他的内容了。以下列举千万不能出现的内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一大段的自我评价&lt;/li&gt;
&lt;li&gt;一小段的自我评价&lt;/li&gt;
&lt;li&gt;一句话的自我评价&lt;/li&gt;
&lt;li&gt;一个词的自我评价&lt;/li&gt;
&lt;li&gt;任何形式的个人宣言，求职口号等主观的内容。&lt;/li&gt;
&lt;li&gt;“主要负责”&lt;/li&gt;
&lt;li&gt;“项目简介”&lt;/li&gt;
&lt;li&gt;“个人简历”&lt;/li&gt;
&lt;li&gt;丑的照片（如果你没有办法客观地评价自己的照片的话，发到北邮人论坛或者虎扑上求打分，你就知道大概是什么水平了。）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不要出现自我评价和个人宣言的原因是因为：一封优秀的简历是专业的，客观的。希望看到的是事实和数据，不希望出现主观的信息，因为那是不专业的。&lt;/p&gt;
&lt;p&gt;不要出现“主要负责”等字眼的原因是因为这些词都是冗余的。不要出现丑的照片是因为你懂的。&lt;/p&gt;
&lt;h3&gt;简历之道&lt;/h3&gt;
&lt;p&gt;以上的内容均从“术”的角度来介绍如何完成一封优秀的简历的书写，这部分将从“道”的层面来介绍如何写好一封简历。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作品化思维&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;首先，我们要具有“作品化思维”。作品化思维就是要认真对待每一件“重要的事”，把它当作一件作品来完成，也包括自己本身这件最重要的作品。&lt;/p&gt;
&lt;p&gt;具体的表现为，认真完成一个项目，并且努力把它打磨成一个可以展示的作品。作品的形式可以有很多，可以是一篇论文，一篇专利，或者一个上线运营的网站，抑或是一个奖项。&lt;/p&gt;
&lt;p&gt;很多情况下，大多数人写完一个项目，并没有再往前走几步，对项目进行总结提升，也不会做任何的包装和美化。过一段时间之后，连自己都忘了怎么使用这个项目。但是如果当初认真修一下Bug，设计点人性化的用户界面，然后认真写一下项目文档，整理点项目材料，就可以将一个普通的项目变成一个作品。也许还可以放到Github上，写一份对人类友好的README来指导用户使用，那么这个项目就由一个普通的作品，变成了一个可以被广大互联网用户使用的作品。同样的，也可以再花点心思，把项目变成一篇论文，一篇专利，一个线上的服务或者拿去比赛得个奖，那也是极好的。&lt;/p&gt;
&lt;p&gt;但是就是这样简单的事情，很多人都不会去做。因为很多人觉得供用户界面工作量大，写文档太麻烦，所以就让已经花了许多心血的项目止步在一个半成品的阶段，特别浪费。&lt;/p&gt;
&lt;p&gt;同样的，平时的学习过程中，也需要将学习成果转化为作品，比如对技术的理解。只需要认真整理一下，也可以写出一篇不错的博客文章。不仅可以锻炼自己的逻辑表达能力，还可以备忘，帮助别人，何乐而不为。&lt;/p&gt;
&lt;p&gt;总之，拥有“作品化思维”可以让你的投入产出比最大化，同时也会给简历提供更多可用的素材。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;索引理论&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在坚持长期艰苦奋斗之后，你的作品应该可以撑起你的简历内容了。但是这还不够，故事虽好，还要会说。所以，还要掌握展示的技巧和理论。&lt;/p&gt;
&lt;p&gt;简历，突出一个“简”字，也即简历的内容应该是抽象之后的关键信息。所以整个简历应该是你个人重要信息的一个缩影，是关于你的信息的索引。所以简历中应该出现一些关键的链接，链接到你的线上作品，包括博客，Github，网站，APP等。这样别人就可以通过你的一封简历，展开对你的了解，从更多的维度上对你有更深刻的印象。当然，这所有的前提都是你的作品是优秀的。如果作品不够优秀，不如不放。比如我的博客：http://www.muzixing.com在我的找工作的过程中就提供了很多的帮助。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工匠精神&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当内容和表达技巧都具备之后，还需要我们拥有工匠精神。修改简历是一件很费时费力的事情，很多人不愿去修改简历。但是只有保持这种工匠精神，对简历的每一个细节都追求精益求精，才有可能得到一份优秀的简历。&lt;/p&gt;
&lt;p&gt;也许你去试试认真修改自己的简历，就发现你的简历可能已经变成了你第一个拿得出手的作品。&lt;/p&gt;
&lt;p&gt;这里拿我自己的简历来做一个示例。其必然存在很多可以提升的空间，但是基本满足我在文章中介绍的所有要求。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://wx2.sinaimg.cn/mw690/7f593341ly1fia6cv9ah8j20ye1ceqks.jpg" /&gt;&lt;/center&gt;
    &lt;center&gt;图12.简历示例&lt;/center&gt;  &lt;/p&gt;
&lt;h2&gt;Cover letter&lt;/h2&gt;
&lt;p&gt;在21世纪，就应该用21世纪的方式来投简历：电子邮件投递。&lt;/p&gt;
&lt;p&gt;如果简历接收方没有对邮件名称格式有要求，那么推荐使用简历名作为邮件名称。&lt;/p&gt;
&lt;p&gt;很多文章不推荐写Cover letter，我个人认为还是要写的。但是不需要写太多，只需将姓名，学校专业，求职信息以及信息来源说明即可。基本上格式如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;称呼：&lt;/span&gt;

&lt;span class="err"&gt;您好，我是哪个学校哪个专业的&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;，在哪里看到了招聘&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;的信息。我的简历在附件，请查收。&lt;/span&gt;

&lt;span class="err"&gt;祝好，&lt;/span&gt;
&lt;span class="err"&gt;李大招&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;当然，如果你能用一小段话把自己的优势介绍清楚自己在相关领域学习多久，有过什么实习和奖项等信息，来突出自己的优势，那也是极好的。示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;称呼：&lt;/span&gt;

&lt;span class="err"&gt;您好，我是哪个学校哪个专业的&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;，在哪里看到了招聘&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="err"&gt;的信息。我学习&lt;/span&gt;&lt;span class="n"&gt;XXX&lt;/span&gt;&lt;span class="err"&gt;多少年，掌握&lt;/span&gt;&lt;span class="n"&gt;XXX&lt;/span&gt;&lt;span class="err"&gt;。在&lt;/span&gt;&lt;span class="n"&gt;XXX&lt;/span&gt;&lt;span class="err"&gt;实习，完成了&lt;/span&gt;&lt;span class="n"&gt;XXX&lt;/span&gt;&lt;span class="err"&gt;。获得奖项&lt;/span&gt;&lt;span class="n"&gt;XXX&lt;/span&gt;&lt;span class="err"&gt;。相信我的技能能满足岗位的需求。我的简历在附件，请查收。&lt;/span&gt;

&lt;span class="err"&gt;祝好，&lt;/span&gt;

&lt;span class="err"&gt;李大招&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;发简历黄金时间&lt;/h3&gt;
&lt;p&gt;早上9点和下午1点半是发简历的黄金时间段，因为这两个时间点都是HR开始上班的时间，一般会习惯性check一下邮箱。如果能出现在未读邮件的前几封，那么大概率上，会被HR怀着美好的心情去阅读。&lt;/p&gt;
&lt;p&gt;但是这些因素并不会有太大的影响，简历质量才是最重要的。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;以上的内容，从“术”和“道”两个方面介绍了如何去编写一份技术简历。虽然修改简历的“术”有立竿见影的效果，但是巧妇难为无米之炊，最重要的还是要积累作品。所以啊，一个人的命运，当然要靠个人的努力，当然也要注意简历的书写。&lt;/p&gt;
&lt;p&gt;最后，Word版简历模版可以&lt;a href="https://github.com/muzixing/PatternOfResume"&gt;点击链接&lt;/a&gt;获取。&lt;/p&gt;
&lt;p&gt;希望这篇啰嗦的长文能给大家带来一点帮助。晚安（深夜写文，生活不易）。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 06 Aug 2017 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2017-08-06:pages/2017/08/06/jian-li-zhuan-ye-er-mei-de-zhu-yu-dao.html</guid><category>简历</category></item><item><title>《重构网络：SDN架构与实现》终于出版啦！</title><link>http://www.muzixing.com/pages/2017/04/05/zhong-gou-wang-luo-sdnjia-gou-yu-shi-xian-zhong-yu-chu-ban-la.html</link><description>&lt;p&gt;技术的海洋，波涛汹涌，暗流窜动，谁不想顺着洋流去远方。&lt;/p&gt;
&lt;p&gt;我是幸运的，跟随着SDN的发展大潮成长了多年，也有幸能有机会和杨泽卫前辈一起完成这本出自SDN学习者的书：&lt;a href="http://item.jd.com/12160066.html"&gt;《重构网络：SDN架构与实现》&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="重构网络：SDN架构与实现" src="http://wx3.sinaimg.cn/mw690/7f593341gy1fdyit3wty0j20ct0gvk8u.jpg" /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;无思辨不足以明理；无案例不足以求真；无细节不足以知端详。&lt;/p&gt;
&lt;p&gt;我们力争在历史的轨迹中翻找出积满灰尘的事件，打磨、分析并得出我们的结论；我们也努力抽象实践所需的技能，绞尽脑汁地尝试通过最简单、清晰的案例来帮助读者更好地实践。&lt;/p&gt;
&lt;p&gt;而我，总算没有撒谎，我真的还是一个在读研究生啊。&lt;/p&gt;
&lt;p&gt;最后，走过路过不要错过SDNLAB（全球最大的SDN中文网站，没有之一。 ——以上都是我自己说的）的&lt;a href="http://www.sdnlab.com/18761.html"&gt;试读活动&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;编辑推荐&lt;/h3&gt;
&lt;p&gt;久立潮头的先行者，携数年磨砺与反思，为SDN大时代领航、解惑；&lt;/p&gt;
&lt;p&gt;业务突破迎来网络重构的重大契机，用架构思想谋篇，用实现技术布局；&lt;/p&gt;
&lt;p&gt;架构深度与产业广度完美聚合，技能、思路、视野、境界尽收囊中；&lt;/p&gt;
&lt;p&gt;本书《重构网络：SDN架构与实现》宗旨：无思辨不足以明理|无案例不足以求真|无细节不足以知端详&lt;/p&gt;
&lt;h3&gt;内容简介&lt;/h3&gt;
&lt;p&gt;身处SDN发展浪潮，笔者真切地感受到了这场技术革命的到来。为了自我总结，也为了帮助他人，因此决定写《重构网络：SDN架构与实现》。《重构网络：SDN架构与实现》首先介绍了SDN的定义、SDN出现的原因、SDN发展的历史和标志性事件、SDN南向协议、SDN控制平面和数据平面等理论知识。然后进一步介绍了如何从零开始搭建SDN实验环境及SDN与网络虚拟化的结合等SDN应用案例内容。最后梳理了SDN对学术界和工业界产生的影响，探讨了我们该如何应对这场SDN变革。此外，附录中两篇拟人化的故事还从感性的角度对SDN进行了介绍。 《重构网络：SDN架构与实现》适合SDN初学者和进阶者。希望《重构网络：SDN架构与实现》的内容能够给读者带来一些帮助，成为SDN学习者相互讨论、学习的舞台。
　　&lt;/p&gt;
&lt;h3&gt;作者简介&lt;/h3&gt;
&lt;p&gt;杨泽卫：《零存整取NetFPGA开发指南》和《深入理解计算机网络系统设计》作者，SDN初创公司南京叠锶联合创始人，曾任中兴微电子高级主任工程师，有丰富的SDN行业产品经验。个人微信公众号：SDN学习与研究（zeweiTalk）。&lt;/p&gt;
&lt;p&gt;李呈：北京邮电大学未来网络理论与应用实验室在读研究生。学习SDN三年多，掌握SDN基础理论知识。目前在硅谷实习&lt;/p&gt;
&lt;h3&gt;精彩书评&lt;/h3&gt;
&lt;p&gt;现有网络面临体系封闭、缺乏开放性的巨大挑战。SDN技术的优势，为网络重构提供了一次新的机遇，不可否认，SDN的思想将在未来网络的发展中起到举足轻重的作用。想要深入认识SDN，迎接未来网络的新世界，这本书会是一个好的开始。 ——黄韬 北京邮电大学教授&lt;/p&gt;
&lt;p&gt;此著平衡了概念架构的深度和产业生态的广度，维度丰富，纵横捭阖，旁征博引的数据线索准确翔实，演绎提炼的逻辑观点犀利清新，工具平台的介绍实战易行，为产学研读者提供了非常实用的参考指南。 作者用心的系统批判思维在技术之外为读者呈现了产业、竞争、生态、资本等深邃洞察。又是一本难得的SDN桌面好书。  ——张宇峰 Brocade大中华区CTO&lt;/p&gt;
&lt;p&gt;软件定义网络正在对网络行业产生广泛而又深刻的影响，对我们广大的网络从业者也带来了知识更新的大挑战。本书对SDN理念、系统框架、工具及业界的典型应用案例都做了深入的介绍和分析，涵盖面非常广，相信本书的出版会对SDN技术的推广普及产生非常大的帮助。  ——邵华 腾讯网络平台部网络架构中心副总监、专家工程师&lt;/p&gt;
&lt;p&gt;这本书的宝贵之处在于清晰勾勒出SDN的成长和进化史，无论对于从零开始的学习者还是多年的网络工程师都能有各自的收获。作者的呈现方式也是耳目一新，相信读者读完之后，不仅能在技术方面有所收获，也能在商业视角上有所提升。  ——庞俊英 大河云联联合创始人&lt;/p&gt;
&lt;p&gt;本书作者是国内SDN技术的布道先锋，持续分享着他们的实践经验。如今他们将研究成果编撰成书，必将给大家带来新的启迪。本书从SDN的定义、南向接口协议、SDN控制平面、SDN数据平面、应用实践等角度入手，给出了清晰的SDN学习曲线，并着重介绍了SDN在数据中心、WAN网络、网络虚拟化等方向的应用。同时，通过总结思考SDN对学术界及产业界的影响，鼓励大家在SDN浪潮中乘风破浪。我相信SDN作为推动网络重构的关键技术，值得长期跟踪学习，因此推荐大家研读本书。  ——魏亮 江苏省未来网络创新研究院团队总监，SDNLAB联合创始人&lt;/p&gt;
&lt;p&gt;SDN技术发展多年，对网络影响巨大，内涵也更加广泛。本书对于SDN技术和解决方案进行了全面系统地介绍，同时提供了基于开源的SDN实例操作，这对于全面学习和掌握SDN是非常有帮助的，也是非常及时的一本参考书。  ——李振斌 华为SDN控制器首席架构师&lt;/p&gt;
&lt;p&gt;毫无疑问，SDN在近年来已经成为了推动网络发展的重要动力。此书在讲述SDN基本原理的基础上，着力从实践和应用案例方面展现了SDN的魅力。在介绍技术的同时，作者也在书中表达了对于技术的理解和感悟。文字表达方面行文老练，是一本适合SDN初学者和实战进阶学习者的读物。  ——胡成臣 西安交通大学
　　&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 05 Apr 2017 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2017-04-05:pages/2017/04/05/zhong-gou-wang-luo-sdnjia-gou-yu-shi-xian-zhong-yu-chu-ban-la.html</guid><category>SDN</category></item><item><title>2016总结：杀死那个天真的自己</title><link>http://www.muzixing.com/pages/2017/03/25/2016zong-jie-sha-si-na-ge-tian-zhen-de-zi-ji.html</link><description>&lt;p&gt;在大家都在发年终总结的那几天里，我还在美国西部的雪地、峡谷和沙漠里不断穿行。由于很多事情还没有做完，所以我也不打算以时间为节点写什么总结，只发了一条朋友圈：“2016年终总结：很多事情没完成，不总结”，就算应付过去了。&lt;/p&gt;
&lt;p&gt;一眨眼，就快四月了，很多事情尘埃落定之后，不由自主地想要写一篇总结向上一个阶段告别。&lt;/p&gt;
&lt;h3&gt;X计划&lt;/h3&gt;
&lt;p&gt;当KkBLuE前辈给我推荐北大光华的X计划的时候，我突然就发现了新天地。于是写申请，填材料，要推荐信。一切都很顺利，提交申请之后，不久就收到了获取参加体验营的通知，而MBA面试就在活动结束的时候。&lt;/p&gt;
&lt;p&gt;4月份，第一次租了正装去参加活动。报道的时候，发现60人里面绝大部分是经管类专业的，剩下的就是计算机相关专业的了，而其中很大一部分的学生来自对外经贸大学，剩下的基本来自中财，清华，北大等学校，而北邮的就我一个。更让我意外的是，我发现我真的已经好老了，因为来的人基本都是大三的学生，研究生基本没有。这是一种很糟糕的信号：我已经老了。&lt;/p&gt;
&lt;p&gt;三天活动非常的充实，参加体验营的小伙伴们都非常优秀。&lt;/p&gt;
&lt;p&gt;最后面试的时候，和我一样报社会公益方向MBA的人只有3个，我知道我基本上已经没戏了。我是所有人里面最后一个面试的。面试的前半部分还蛮正常，直到一个老师提出了一个非常尖锐的问题：“你们北邮的研究生出来工作工资是非常高的，你愿意放弃你的工作，去做公益吗？”。我知道，无论怎么回答，都很艰难。走出面试的小屋，我强烈地预感到我要挂了。&lt;/p&gt;
&lt;p&gt;后来好心的KkBLuE前辈主动给我打电话询问情况，午睡中迷迷糊糊的我告诉他我估计是挂了。他很着急，说我报方向怎么不问他。我也突然发现我自己有时候过于天真，过于固执。以为自己很善良，在公益组织工作过几年就会愿意投入全部去做公益，可是我还很稚嫩，对社会公益的理解，以及自己未来的规划并不清晰。&lt;/p&gt;
&lt;p&gt;后来他帮我打电话问了北大的老师，从老师那得知我被录取了。他很高兴地通知我这件事，然而我并不怎么相信，可能是知道自己并没有表现好吧。后来的结果自然是没有拿到保送资格。我花了很长的时间去接受这个事实，去消化这个事实，反思自己做得不好的地方。太天真是最主要的方面。我不应该刚愎自用地擅作主张去报社会公益方向。如果我咨询一下前辈们，成功的概率是不是会更大一些呢？&lt;/p&gt;
&lt;p&gt;但事情过去之后，我也开始思考，我到底需不需要去读MBA呢？也许我并不适合，也许我并不需要，岁月会给我答案。&lt;/p&gt;
&lt;h3&gt;SCI&lt;/h3&gt;
&lt;p&gt;在上研究生之前，我天真的以为，我会写很多很棒的论文，会在学术界产生一些影响。但是后来发现，我连毕业都要靠科技论文在线。&lt;/p&gt;
&lt;p&gt;在没有入学前，我对自己的期望是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;学会论文写作，发表SCI论文两篇，用硕士的时间，完成博士的毕业要求；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;学会完整的项目开发流程，可以独立开发项目。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而现实是我几乎花了一年的时间在上课和寻找研究方向上，直到去年才勉强选了一个方向。&lt;/p&gt;
&lt;p&gt;半年多之后，我完成了Open eXchange协议的设计，实现和性能测试，终于开始写论文。第一版本的中文版出来之后，修改了十多个版本才得到老师的一句：勉强算一篇论文吧。&lt;/p&gt;
&lt;p&gt;第一次，老师们把论文投到了一个SCI期刊，被拒了。我自然很受伤。但是看到修改意见的时候，发现确实是自己写得太差，只好继续修改。又过了几个月，总算修改完成了，投了另一个SCI期刊，却石沉大海。&lt;/p&gt;
&lt;p&gt;等待，是煎熬的。&lt;/p&gt;
&lt;p&gt;终于等到修改意见之后，又经过了周期漫长的几个修改，总算被接受了。再看看研究生所剩无几的时间，另一篇SCI？简直天方夜谭。&lt;/p&gt;
&lt;p&gt;回想发论文的事情，才发现做学术真的需要耐心，而我最缺乏的就是耐心，也不愿意等待，所以我大概是不合适，也没有什么做学术的天赋吧。而那个天真的我，在发水文求毕业的时候，已经死了。&lt;/p&gt;
&lt;h3&gt;CIIP&lt;/h3&gt;
&lt;p&gt;去年大年初二的时候，我收到了CIIP的Offer，这也是2016年春节最好的礼物，好几个月的准备和努力终于没有白费。回到学校，申请签证，学习英语，一直折腾到8月份才终于踏上了飞往硅谷的旅程。&lt;/p&gt;
&lt;p&gt;第一次坐十多个小时的飞机，简直生不如死。十多个小时之后，终于落地了。入境的时候，我连英语都说不利索，心里很忐忑，也很期待。第一天的我，被时差折磨得痛不欲生，走在去大华的路上的时候都差点睡着了。熬夜后的痛苦，毫无掩饰地表现在我的身上：心跳加速，脑袋沉重，头重脚轻，我不断告诉自己：坚持住。&lt;/p&gt;
&lt;p&gt;调时差的痛苦很快就被新生活的美好冲淡。&lt;/p&gt;
&lt;p&gt;这里有加州阳光，有盐水游泳池，有温泉，有漂亮宽敞的公寓和办公室，有蓝天，绿地和大海，还有满大街帅到爆的帅哥和漂亮的美女。我开始学会说：“Have a good day”, 开始学会吃沙拉，也开始天天自己做饭。但我过马路还是会提心吊胆，不习惯车让人，也听不懂Uber司机各种各样的口音。&lt;/p&gt;
&lt;p&gt;慢慢的，我开始习惯了这里的生活，过马路不再担心受怕，看见人会点头微笑，还有9点多上班，5点下班。&lt;/p&gt;
&lt;p&gt;差不多半年之后，新鲜感已经挥发得差不多了，生活开始变得无聊，极度的无聊。周一到周五的夜里，大家都没什么事做。刚开始的时候，赶着校招，我还在夜里去18楼刷题。后来工作找到了，就再也不去了。从此我的夜生活也开始变的寂寞而空虚。&lt;/p&gt;
&lt;p&gt;刚来的时候，我一直很纠结到底我要不要在硅谷找工作。但是慢慢的，我开始发现我不想留在这里，因为我不喜欢这里的寂寞。而且工作上，其实并没有什么高大上的，因为无论哪里，搞科学研究的人都是极少的，而大部分人都在搬砖。最后再结合在谷歌工作的本科舍友的生活状态，我终于下定决心回国。虽然这里有高大上的工作环境，有舒适宽敞的居住环境，还有美不胜收的自然景观，但是我还是更希望我能够回到一个需要我的地方，去贡献更多的价值。这边太发达了，不需要我。&lt;/p&gt;
&lt;p&gt;当然，CIIP的生活也不是一帆风顺，比如我丢过自行车，在Santa Monica海滩上的小店里买过40刀的浴巾，打球把眼镜打破了，在上眼皮留下小小的疤。还有在大年三十的时候，由于项目没钱以及其他原因，我在最后一天得到通知实习结束，要我搬出公寓，订机票回家。但震惊而失望的我并不会轻易放弃。&lt;/p&gt;
&lt;p&gt;当天下午，写简历，写邮件，发消息，找面试。终于在Yoel的帮助下，找到了愿意面试我的团队。连续四次面试，还和Manager打了一通电话聊了一些深刻的话题，才得到了口头的Offer。那是我这辈子最难忘的周末，也是最忐忑的春节。煎熬到周一，终于等到了下一季度的offer。&lt;/p&gt;
&lt;p&gt;塞翁失马，焉知非福。我遇到了现在这个近乎完美的组！这可能是我这辈子遇到的最完美的团队了。大家每天一起吃午饭，一起写代码，工作干劲十足，但是又没有什么条条框框约束，人性化到了极点。&lt;/p&gt;
&lt;p&gt;上周，我和Marc在一对一抱怨会上聊了聊未来计划，他问我想不想留下，我说我愿意留下来，因为我特别感谢这个团队对我这么好。他说：“你别着急做决定。你不要为团队想，为你自己想。周五之前，我等你答案”。我很感激，也很惊讶。&lt;/p&gt;
&lt;p&gt;经过冷静的SWOT分析之后，我最终决定五月回国。当我愧疚地告诉Marc我的决定的时候，他微笑的说：你不用道歉啊，我很高兴你做了一个对你好的决定。这一刻，我深刻地感觉到The Best Boss Ever的形象（我们实习生一起送给他一个杯子，杯子上印着The Best Boss Ever）。&lt;/p&gt;
&lt;p&gt;我觉得一个好的团队是那种每个人在团队中都能学习到很多，可以各自作出很多贡献，即使离开后，也都会有美好前途的团队。我们分工不同，个性鲜明，也各有追求，但我们都有美好的未来。就像“张华考上了北京大学；李萍进了中等技术学校；我在百货公司当售货员：我们都有光明的前途”那样。&lt;/p&gt;
&lt;p&gt;CIIP的生活让我学会了很多，学会了一个人在异国独立生活，打破了我对硅谷的幻想，对谷歌，Facebook等巨头的盲目崇拜，让我看清了自己想要什么样的生活，也让我学会了更多在职场丛林生存的法则。那个年轻而天真的我，在大年三十的那天，已经被无情地扼杀，取而代之的是一个更加沉着冷静，处事不惊的我。&lt;/p&gt;
&lt;h3&gt;书：&lt;a href="http://item.jd.com/12160066.html"&gt;《重构网络：SDN架构与实现》&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;从2015年开始写书，直到2016年7月左右，才把第一版内容的稿子完成。本以为疯狂修改的情况下，2个月能完成定稿。然而我又天真了。从保证内容的正确性，到整理思路逻辑，到表达方式，修饰手法，遣词造句等修改，再到最后的图表等格式的统一，前前后后我们总共花了快半年的时间来修改，每一章都经历了不止20遍的修改，直到12月底的时候才终于完成了书稿的修改。&lt;/p&gt;
&lt;p&gt;终于交稿之后的我以为出版社的流程应该很快就能走完，然而流程又因为春节暂停了。&lt;/p&gt;
&lt;p&gt;再重新开始走出版流程的时候，已经是2月份的事了。又经历了几轮审校，修改，还有封面设计，推荐序和推荐短语收集等等流程，最终定稿的时候已经3月了。本以为在我回去答辩的时候，书能上架销售，结果两会期间河北的印刷厂停止运行了，又一次拖延了。&lt;/p&gt;
&lt;p&gt;等待，是忐忑的。&lt;/p&gt;
&lt;p&gt;终于，功夫不负有心人， &lt;a href="http://item.jd.com/12160066.html"&gt;《重构网络：SDN架构与实现》&lt;/a&gt;总算是出版了。&lt;/p&gt;
&lt;p&gt;回顾往昔，发现自己以前真的蛮天真的，把所有事情都想象得很理想。比如我觉得我平时写博客和文章也不少，写书应该没问题。但直到自己写才发现根本不是那回事。首先语言风格就完全不一样，也要根据受众来精心搭配内容，最后还要语言流畅，逻辑清晰，难度相当高。而且并不是所有技术好的人都能写书，写书对文字驾驭能力有很高的要求。我觉得我自己还有很大的提升空间。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;2016年是在象牙塔的最后一年，也是我逐渐踏入社会的一年。经历了很多事，做了很多改变，也适应了很多新生活。曾经那个天真的自己，真的已经逐渐退出舞台了，取而代之的是一个纯真却勇敢的自己。&lt;/p&gt;
&lt;p&gt;这一年里最宝贵的事情其实是认清了自己是什么样的人，知道了自己想要做什么。打破了很多幻想，面对了很多现实。但我努力做一个知道世事险恶，却心存善良；了解人间疾苦，而热爱生活；深知前程未卜，却依然向往的人。即使我还很平庸。&lt;/p&gt;
&lt;p&gt;新的一年，我需要保持写作的习惯，记录一些思想，记录一些情感。希望有朝一日，我还能写一本书，去传达我的思想，帮助别人，影响别人。感谢爷爷给我培养的写作和阅读的好习惯。对美好世界的向往与期待，早已出现在躺床上捧着世界名著的男孩的脑海。&lt;/p&gt;
&lt;p&gt;等待，绽放的那天。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sat, 25 Mar 2017 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2017-03-25:pages/2017/03/25/2016zong-jie-sha-si-na-ge-tian-zhen-de-zi-ji.html</guid><category>story</category></item><item><title>Fluentd入门教程</title><link>http://www.muzixing.com/pages/2017/02/05/fluentdru-men-jiao-cheng.html</link><description>&lt;p&gt;最近发生了一些不可描述的故事，艰难之中换到了现在的组，主要的工作内容是数据挖掘。也终于有机会学习新的知识：Ruby和Fluentd。本文将总结开源软件Fluentd的入门知识，包括如何安装，配置文件语法，插件简介等内容。Fluentd的&lt;a href="http://docs.fluentd.org/v0.12/articles/quickstart"&gt;官网&lt;/a&gt;内容非常详尽，内容的组织也尤其清晰，所以网络上关于Fluentd的文档很少。本文主要用于学习记录，也希望能帮助到英语不好的读者。&lt;/p&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;Fluentd是一个完全开源免费的log信息收集软件，支持超过125个系统的log信息收集。其架构图如图1所示。 &lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="fluentd" src="http://docs.fluentd.org/images/fluentd-architecture.png" /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;图1. Fluentd架构图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;本质上，Fluentd可以分为客户端和服务端两种模块。客户端为安装在被采集系统中的程序，用于读取log文件等信息，并发送到Fluentd的服务端。服务端则是一个收集器。在Fluentd服务端，我们可以进行相应的配置，使其可以对收集到的数据进行过滤和处理，并最终路由到下一跳。下一跳可以是用于存储的数据库，如MongoDB, Amazon S3, 也可以是其他的数据处理平台，比如Hadoop。&lt;/p&gt;
&lt;h3&gt;Install&lt;/h3&gt;
&lt;p&gt;由于Fluentd的安装较为麻烦，所以业界流行的稳定安装版本其实是有Treasure Data公司提供的td-agent。本文将介绍的也是td-agent的安装和使用。&lt;/p&gt;
&lt;p&gt;官网&lt;a href="http://docs.fluentd.org/v0.12/articles/install-by-deb"&gt;安装文档&lt;/a&gt;介绍了针对不同系统的安装办法。本文介绍“Ubuntu 14.04 LTS / Trusty 64bit/32bit“系统的安装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt; &lt;span class="n"&gt;https:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;toolbelt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;treasuredata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/sh/i&lt;/span&gt;&lt;span class="n"&gt;nstall&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;trusty&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;agent2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;sh&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;安装完成之后，可运行以下的命令来启动Fluentd服务：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;etc&lt;/span&gt;&lt;span class="sr"&gt;/init.d/&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;restart&lt;/span&gt;

&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;etc&lt;/span&gt;&lt;span class="sr"&gt;/init.d/&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;  &lt;span class="mi"&gt;21678&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;通过start, stop, restart等命令可以启动、关闭和重启Fluentd服务。此时默认的Fluentd配置文件的目录是/etc/td-agent/td-agent.conf文件。&lt;/p&gt;
&lt;h3&gt;Post Sample Logs via HTTP&lt;/h3&gt;
&lt;p&gt;默认情况下，/etc/td-agent/td-agent.conf文件已经对td-agent进行了基本的配置。可以接收通过HTTP Post的数据，并将其路由、写入到/var/log/td-agent/td-agent.log中。&lt;/p&gt;
&lt;p&gt;可尝试通过以下curl命令来尝试post数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;json={&amp;quot;json&amp;quot;:&amp;quot;message&amp;quot;}&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost:8888&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;执行之后，可在输出log的最后一行找到我们输入的测试数据。&lt;/p&gt;
&lt;h3&gt;Syntax of Config&lt;/h3&gt;
&lt;p&gt;在Fluentd中，配置文件非常重要，它定义了Fluentd应该执行的操作。其语法很简单，详细内容可点击&lt;a href="http://docs.fluentd.org/v0.12/articles/config-file"&gt;配置语法&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;打开/etc/td-agent/td-agent.conf文件，可以看到配置文件的具体内容。配置文件中基本会出现的配置分为以下几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;source： 定义输入&lt;/li&gt;
&lt;li&gt;match：定义输出的目标，如写入文件，或者发送到指定地点。 &lt;/li&gt;
&lt;li&gt;filter：过滤，也即事件处理流水线，可在输入和输出之间运行。 &lt;/li&gt;
&lt;li&gt;system：系统级别的设置。&lt;/li&gt;
&lt;li&gt;label：定义一组操作，从而实现复用和内部路由。&lt;/li&gt;
&lt;li&gt;@include：引入其他文件，和Java、python的import类似。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;source&lt;/h3&gt;
&lt;p&gt;Fluentd支持多输入。每一个输入配置必须包含类型／type，比如tcp数据输入，或者http类型输入。type将指定使用的input plugin。以下的示例中就定义了两个输入源，一个是从24224端口进入的tcp数据流，另一个是从9880端口进入的http数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;# Receive events from 24224/tcp
# This is used by log forwarding and the fluent-cat command
&lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;
  @type forward
  port 24224
&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;

# http://this.host:9880/myapp.access?json={&amp;quot;event&amp;quot;:&amp;quot;data&amp;quot;}
&lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;
  @type http
  port 9880
&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Source指定的input插件将带有{tag, time,record} 三个属性的事件／event提交给Fluentd的引擎，完成数据的输入。&lt;/p&gt;
&lt;h3&gt;match&lt;/h3&gt;
&lt;p&gt;Match配置了数据流的匹配规则和匹配成功后所需执行的动作，和路由表项类似。比如以下的配置中就对匹配myapp.access标签成功的数据包执行file类型动作，将数据写入到路径为/var/log/fluent/access的文件中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;# Match events tagged with &amp;quot;myapp.access&amp;quot; and
# store them to /var/log/fluent/access.%Y-%m-%d
# Of course, you can control how you partition your data
# with the time_slice_format option.
&lt;span class="nt"&gt;&amp;lt;match&lt;/span&gt; &lt;span class="err"&gt;myapp.access&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  @type file
  path /var/log/fluent/access
&lt;span class="nt"&gt;&amp;lt;/match&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;标准的动作有file和forward等。File表明写入文件，而forward表明转发到下一跳。&lt;/p&gt;
&lt;p&gt;Match Pattern的设计与正常的正则匹配没有区别，具体的分类如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;匹配&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="err"&gt;的某一部分，比如&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.*&lt;/span&gt; &lt;span class="err"&gt;可以匹配&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;但&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="err"&gt;无法匹配成功。&lt;/span&gt;

&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;匹配&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;个或者多个&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="err"&gt;部分。比如&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.**&lt;/span&gt; &lt;span class="err"&gt;可以匹配&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;：匹配&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;或关系。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;此外，他们还可以混用，比如a.{b,c,d}.*等等。当&lt;match&gt;标签内，有多个匹配模式时，将支持或逻辑的匹配，即只要匹配成功人一个都执行对应的操作。比如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;匹配&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="err"&gt;和&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.**&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.*&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;匹配&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Logging&lt;/h3&gt;
&lt;p&gt;Fluentd支持两种类型的logging 配置，一种是全局的，另一种是针对插件的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;global&lt;/li&gt;
&lt;li&gt;Plugin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;支持的log的输出级别有如下几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fatal&lt;/li&gt;
&lt;li&gt;error&lt;/li&gt;
&lt;li&gt;warn&lt;/li&gt;
&lt;li&gt;info&lt;/li&gt;
&lt;li&gt;debug&lt;/li&gt;
&lt;li&gt;trace&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;介绍完Config file的语法之后，我们还需要了解config file配置的对象Fluentd的Plugin/插件。&lt;/p&gt;
&lt;h3&gt;Plugin&lt;/h3&gt;
&lt;p&gt;Fluentd有5种类型的插件，分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Input：完成输入数据的读取，由source部分配置&lt;/li&gt;
&lt;li&gt;Parser：解析插件&lt;/li&gt;
&lt;li&gt;Output：完成输出数据的操作，由match部分配置&lt;/li&gt;
&lt;li&gt;Formatter：消息格式化的插件，属于filter类型&lt;/li&gt;
&lt;li&gt;Buffer：缓存插件，用于缓存数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每一个类型都包含着多种的插件，比如input类型就包含了以下几种插件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;in_forward&lt;/li&gt;
&lt;li&gt;in_http&lt;/li&gt;
&lt;li&gt;in_tail&lt;/li&gt;
&lt;li&gt;in_exec&lt;/li&gt;
&lt;li&gt;in_syslog&lt;/li&gt;
&lt;li&gt;in_scribe&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于篇幅限制，本文将不会对插件进行展开介绍，读者可以自行阅读&lt;a href="http://docs.fluentd.org/v0.12/articles/input-plugin-overview"&gt;官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;Route&lt;/h3&gt;
&lt;p&gt;Route指的是数据在Fluentd中的处理流水线，一般的流程为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;input  -&amp;gt; filter  -&amp;gt;  output&lt;/li&gt;
&lt;li&gt;input  -&amp;gt; filter  -&amp;gt;  output with label&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;即由输入插件获取数据，然后交给filter做处理，然后交给output插件去转发。同时，也支持数据包／事件的重新提交，比如修改tag之后重新路由等等。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reroute event by tags&lt;/li&gt;
&lt;li&gt;reroute event by record content&lt;/li&gt;
&lt;li&gt;reroute event to other label&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Use case&lt;/h3&gt;
&lt;p&gt;此处将选择一个最简单的使用案例来介绍Fluentd的使用。&lt;a href="http://docs.fluentd.org/v0.12/articles/docker-logging"&gt;Fluentd收集Docker的登陆信息&lt;/a&gt;案例。&lt;/p&gt;
&lt;p&gt;首先创建一个config file, 用于配置Fluentd的行为，可命名为”in_docker.conf“。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;
  type forward
  port 24224
  bind 0.0.0.0
&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;match&lt;/span&gt; &lt;span class="err"&gt;*.*&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  type stdout
&lt;span class="nt"&gt;&amp;lt;/match&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后保存文件。使用以下命令运行Fluentd。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;fluentd&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;in_docker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;若运行成功则可见输出信息如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;$ fluentd -c in_docker.conf
2015-09-01 15:07:12 -0600 [info]: reading config file path=&amp;quot;in_docker.conf&amp;quot;
2015-09-01 15:07:12 -0600 [info]: starting fluentd-0.12.15
2015-09-01 15:07:12 -0600 [info]: gem &amp;#39;fluent-plugin-mongo&amp;#39; version &amp;#39;0.7.10&amp;#39;
2015-09-01 15:07:12 -0600 [info]: gem &amp;#39;fluentd&amp;#39; version &amp;#39;0.12.15&amp;#39;
2015-09-01 15:07:12 -0600 [info]: adding match pattern=&amp;quot;*.*&amp;quot; type=&amp;quot;stdout&amp;quot;
2015-09-01 15:07:12 -0600 [info]: adding source type=&amp;quot;forward&amp;quot;
2015-09-01 15:07:12 -0600 [info]: using configuration file: &lt;span class="nt"&gt;&amp;lt;ROOT&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;
    @type forward
    port 24224
    bind 0.0.0.0
  &lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;match&lt;/span&gt; &lt;span class="err"&gt;docker.*&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    @type stdout
  &lt;span class="nt"&gt;&amp;lt;/match&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ROOT&amp;gt;&lt;/span&gt;
2015-09-01 15:07:12 -0600 [info]: listening fluent socket on 0.0.0.0:24224
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后启动docker containner。如果之前没有安装过docker engine，请读者自行安装。由于docker 本身支持Fluentd收集信息，所以可以通过启动命令来启动Fluentd的client／客户端。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fluentd&lt;/span&gt; &lt;span class="n"&gt;ubuntu&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Hello Fluentd!&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;Fluentd&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上命令中的ubuntu为一个镜像，如果本地没有，docker engine会自动下载，并在此镜像上创建容器。启动容器后，查看默认的输出信息文件:/var/log/td-agent/td-agent.log,可在最后一行查看到输出的信息。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;Fluentd是一个优秀的log信息收集的开源免费软件，目前以支持超过125种系统的log信息获取。Fluentd结合其他数据处理平台的使用，可以搭建大数据收集和处理平台，搭建商业化的解决方案。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 05 Feb 2017 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2017-02-05:pages/2017/02/05/fluentdru-men-jiao-cheng.html</guid><category>Fluentd</category></item><item><title>探索西部世界：从2016走到2017</title><link>http://www.muzixing.com/pages/2017/01/06/tan-suo-xi-bu-shi-jie-cong-2016zou-dao-2017.html</link><description>&lt;p&gt;一转眼，来硅谷实习已经快半年了。半年来，都在不停地探索西部世界，但是除了优胜美地国家公园还不错以外，其他的都没有感觉太兴奋。。也许是因为我是一个岛民吧，对加州的阳光，沙滩，大海没有特别兴奋。&lt;/p&gt;
&lt;p&gt;终于等到圣诞节，公司shut down10天之久，不出去转一圈就太浪费时光了。所以在放假之前，就招齐了人马，做好了计划，万事具备，只欠放假。我们甚至还要拍一个视频。作为一个梦想当导演的码农，终于找到机会好好实践一把，分镜本写起来。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="分镜本" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbfquqgi73j20zq13gqej.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;分镜本&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;每一次我们都租车自驾旅行，因为在美国租车实在是太便宜了！&lt;/p&gt;
&lt;p&gt;从San Jose往南开，一路从阳光绿地，开到雪地，再到荒漠处，8小时后，终于到达第一个住处。路上还撞了一次车，还好只是轻轻亲了一下前车，没大碍就继续前行了。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="加油站" src="http://ww3.sinaimg.cn/mw690/7f593341gw1fbgza6ida5j21kw16oe0y.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;你站在车边看风景，看风景的人在高处看你，夕阳装饰了你的眼睛，你装饰了别人的梦&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="雪地行车" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbfr3wkl2mj21kw11x4jt.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;开，往城市边缘开，你就会看到雪地&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;第一个住处是一间沙漠里的小房子。虽然房子在沙漠里，但是竟然有热水！有网络！还有暖气！再一次感叹美帝农村的发达。&lt;/p&gt;
&lt;p&gt;旅行第一站是Joshua Tree国家公园。本以为树公园都是那些普通的树，没什么好看的。结果到了才发现，真的是树公园。但是树却是沙漠里面的树，长相很奇怪。在树公园里面基本上就是看树和石头了。傍晚的时候还去看了日落，简直冻成狗。比较印象深刻的是我在这里丢了我的银行卡。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbfr47whzrj21kw11x7wh.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;”真是树“公园&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341gw1fbfr3z3cntj21kw11x4qp.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;3人行，和一个跟拍的“十八线导演“和“爬行级摄影师”&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbfr450hrpj21kw11x4jz.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;别低头，皇冠会掉，而且随时会错过一张壁纸&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbgzawiv8hj216o1kw4qp.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;本想忍住，但是我控制不住自己啊！人物照一张的&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;看完日落之后，还需要开车5个小时到下一个住的地方，Arizona的一个小镇。在精疲力尽之后，我们终于抵达了第二个住的地方，也就是我丢洗面奶的地方。Arizona雪非常大，快二十厘米厚的积雪踩起来好舒服。所以，我们从沙漠来到了雪原。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="ARIZONA" src="http://ww3.sinaimg.cn/mw690/7f593341gw1fbgvxwulgwj21kw16oe81.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;Arizona小镇，雪的世界&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;第二个景点是大峡谷(The Grand Canyon),那个我丢书包，又找回来的地方。大峡谷雪很大，很冷，值得看的东西也不多，基本上就是在山上看地球母亲的伤疤。真的蛮惨的一道伤疤。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="grand canyon" src="http://ww3.sinaimg.cn/mw690/7f593341gw1fbfr4dw5rjj21kw2dc1ky.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;The grand canyon，地球的伤疤&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;看得忘乎所以的时候，也会幻想自己是蜘蛛侠，刺客，青蛙侠之类的，于是拍了一张信仰之跳。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="grand canyon" src="http://ww2.sinaimg.cn/mw690/7f593341gw1fbgzayty8bj21kw16odx7.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;信仰之跳&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;不满足的我们继续在公园里面瞎逛，踩着很厚的积雪，感觉到了东北一样。也是蛮新奇的。印象最深的事是我失而复得的书包和近距离遇见的野生鹿。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbfr3r8hxuj21kw0w07rx.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;雪与铁路更配哦&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbfr4jw0u5j21kw11x7wh.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;雪和车也配哦，总感觉帮车做广告了&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;当天，我们又开始了长途跋涉，开车到第三个地点：Page，也就是马蹄湾。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341gw1fbfr5z9urdj21kw16ob29.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;鱼眼中的马蹄湾&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341gw1fbgw6bsh2wj21kw149ng6.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;我眼中的马蹄湾&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;相比上面中规中矩的照片，我还是喜欢不经意间发现的美好。马蹄湾下面飘荡的游艇，船上有一对情侣在钓鱼。好惬意。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341gw1fbfr4rohhrj21kw11xqq1.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;画上开船&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbfr4uavnkj21kw11xawh.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;追寻光明&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341gw1fbfr623r7yj21kw16o4jn.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;舞者，和拍摄她的朋友，以及看她朋友拍她的另一个朋友&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;在不断尝试各种机（ti）位之后，发现用鱼眼镜头，以双腿为框架会找到一个很奇妙的世界。朋友圈最佳评论是“活在裆下”。&lt;/p&gt;
&lt;p&gt;在前往羚羊谷的路上，看到了三根烟囱。同样是烟囱，同样是开车（注意看图左上的方向盘），为什么人家的天空是蓝色的呢？我特别喜欢那三根烟囱。后来发现他们是可口可乐公司的，冒的是水蒸气。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbfr3oewt5j21kw11xqjr.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;汽车与烟囱&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbfr4xdlx7j21kw11x000.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;西部世界&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;不过我们没有预约羚羊谷，所以只能参加最后一趟。最后排队等了好久，太阳都快下山了才进去下羚羊谷，体验不够好。大家要去的话一定要记得预约，趁早。另外，不是摄影团是不能用三脚架的，可怜我拿了一路的三脚架，撑开当拐杖用了。这块地盘是印第安人的保留地，所以由他们管。导游就是一名印第安人。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbfr5wc0ohj21kw11x7pk.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;和你讲很多遍了，我虽然是chief，但是我也是普通人，你这样看我，我会乱想的&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbfr53umtyj21kw2dckjl.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;时间漏斗&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbfr570zm2j21kw2dc7wh.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;总说时间如白驹过隙，却也曾真切地留下痕迹&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;第四个地点是Zion国家公园，相比其他的，这个地方不算特别特殊。有雪，有峡谷，有沙漠，但是都不算特别典型。本想去看Zion Narrow的，结果时间不够就放弃了。留下印象的是在那里看到了好多只野生的羊或者鹿什么的。这也就是为什么特别喜欢下面那张照片的原因，因为我自己也不知道到底有多少只，有人说7只，那就7只吧。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341gw1fbgwmc2ex2j20xc1e0hdt.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;白天也数羊，只是要睁眼数&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341gw1fbfr64lxgaj211x1kw4qp.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;惊讶的瞎子：“为什么我看不到我的鼻子？”&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341gw1fbfr5a0zvgj21kw11x7wh.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;孤独的树和消失的雪&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;第五站是Las Vegas。经历5天之后，我们终于从农村回到了城市，也是我们旅程中唯一一个城市。赌城、罪恶之城就是不一样，现代化程度，热闹程度远不是洛杉矶，圣地亚哥，旧金山能比的。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbfr5nw79qj21kw11x18q.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;夜色不撩人&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;我们住在Flamingo街上的PALMS酒店。只要不是周末，四星级酒店的价格比Airbnb上租的城镇的房子还便宜，简直不敢相信。到处都是Casino(赌场)，每家大酒店门前都有非常独特的景观，室内都会有很酷炫的赌场。不过除了需要庄家主持的赌桌有点高大上以外，其他自己玩的游戏机看起来非常弱智，简直就是一个电玩城，还是只有弱智游戏的电玩城。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbgwsu2sqbj24002o0npo.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;赌城的夜，多希望你能在我身边，这样就可以赢你的钱了&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341gw1fbfr5qqxh2j21kw11x1kx.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;停车场，孤单的停车场，没有人停。&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;如果来游玩的话，建议晚上去The Strip大街。街道很长，需要很长时间才能看完，但是风景很美。BELLAGIO酒店的音乐喷泉非常赞。另外，如果有时间，有闲钱的话，来这里还是可以去赌场玩个20刀的。当然，Strip Club也是非常赞的选择。累了还可以去做做massage, 不过相比之下massage挺贵的。全身按摩一小时需要50刀，加Tip10刀就60刀了。但是这才是感受城市的正确方式。&lt;/p&gt;
&lt;p&gt;夜晚的Strip Street和我国大城市的夜市没有太大差别。我们还看到了基督教和伊斯兰教徒在街上开撕。在这里，你可以很安全的看到发达国家的浪荡。不像LA，晚上过Downtown都不敢停车，满大街的homeless。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbfr67u6tnj21kw2dckjl.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;婚纱时刻&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;第六站还是在LV，不过我们选择去看Hoover dam(胡佛大坝)。胡佛就是美国历史上大萧条时期的总统。说实话，这个大坝是我们一路上看的最没有意思的地方了。婴儿版三峡大坝。稍微有意思的是那座桥和不同时区的两个钟。图没有，太丑了！&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbfr6fxou0j21kw1107wh.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;胡佛大坝&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;第七站是Death Valley，顾名思义就是死亡谷。当天走的晚，就看了一个小小地方，感觉不错的是拍到了几张“寂寞照”。本想开车去山顶看风景，结果4点多天就黑了，我们开到一半觉得不太安全就回来了。夜里的死亡谷，有一种特殊的感觉，更恐怖，更冷。这也是别开生面的一种旅行方式吧。下车施肥之后，我们就打道回府了。这是2016年最后一天，我们在死亡谷的山路上，谨慎地前行着。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbfr6isxsbj21kw11x7wh.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;最寂寞的不是一个人旅行，而是一人一狗&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;在最后一个住的地方遇了The Best Host。一个典型的美国乡村家庭。一对中年夫妇，大过年的没有什么宴席，在火炉前看动画片，女儿和她的男朋友住在镇上不远处，有一个小女儿，他们还没结婚。还有一只超级可爱超级聪明的小小狗！女主人尤其健谈，对我们也超级好。不过精疲力尽的我们并没有嗨，只是默默洗澡上床睡觉。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341gw1fbgxg5b4k4j20zk0qpq6p.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;单身与狗&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341gw1fbgxg6jhnkj20zk0qo40r.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;不喜欢他摸我，你看得出来的，抱我走！&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;十二点的时候，躺在床上的我们竟然听到了烟花，爆竹的声音，颇有点家乡的感觉，然而打开朋友圈，元旦的氛围早就过去了。&lt;/p&gt;
&lt;p&gt;本打算去看湖的我们又打算重返死亡谷。后来证明我们的选择是正确的。&lt;/p&gt;
&lt;p&gt;2017年第一天，我们又回到了死亡谷。&lt;/p&gt;
&lt;p&gt;第一个景点是有流沙的沙漠，一块不大不小的真正的沙漠。行走在沙漠里，感受炎热的太阳，也算一种奇特的体验。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341gw1fbfr5iohaxj21kw11zkjl.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;假装拍到一个很大很大的沙丘&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;另一个叫“Bad water basin”，可以叫恶水谷吧。那里其实没什么水，全是盐碱化的石块和土地，是地壳运动导致的。走在那里感觉像是走在干涸的海底，脚底都是珊瑚礁状物体，能很明显看出是某些盐碱。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341gw1fbgyez4cwmj20zk0k0ad3.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;好像走在天上一般，云和地面一样低。只不过白色的都是盐碱物，其实黑色的也是&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;最后一个景点叫“Devil's golf course”，恶魔的高尔夫球场。这个地方值得一看，非常震撼的画面，满地的礁石，延绵不绝。就像高尔夫球场上一株株草一样。来死亡谷，感受寸草不生的绝望，比沙漠还要悲惨，令人印象深刻。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341gw1fbgyjoiiqqj21kw11x1kx.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;恶魔的高尔夫球场-死亡谷&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;经历了荒漠，雪地，峡谷，沙丘等多种地理环境以及城市之后，我们终于开始踏上归途。历经7个小时的长途行车，我们终于在夜里2点多，回到了圣何塞，回到了舒服的公寓。&lt;/p&gt;
&lt;p&gt;总结起来，这次road trip还是非常不错的。走过很多地方，感受过许多风景，也用手机和相机记录下了很多珍贵的素材。虽然在写分镜的时候就知道关于风景的部分必然会拍脱，但是能坚持拍完着实已经不容易了。期待第一个自导自演的视频。&lt;/p&gt;
&lt;p&gt;我还会去很多美好的，壮观的，可怕的地方，去感受，去探索这个星球。这也是人生的意义之一。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1fbfr5cycgvj21kw11xtsn.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;Run,Forrest run! Go, Distance go!&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;Finally, we made the video!&lt;/p&gt;
&lt;p&gt;&lt;center&gt;
&lt;embed src="https://imgcache.qq.com/tencentvideo_v1/playerv3/TPout.swf?max_age=86400&amp;v=20161117&amp;vid=z0381az2cdi&amp;auto=0" allowFullScreen="true" quality="high" width="480" height="400" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/center&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 06 Jan 2017 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2017-01-06:pages/2017/01/06/tan-suo-xi-bu-shi-jie-cong-2016zou-dao-2017.html</guid><category>trip</category></item><item><title>Solution: can not receive notification of OpenStack</title><link>http://www.muzixing.com/pages/2016/12/21/solution-can-not-receive-notification-of-openstack.html</link><description>&lt;p&gt;If you set up a AMQP connection to listen to Rabbit message queue, and can not receive any notification when connection is correct. Stucking queue may be the reason of this problem. As I proposed in &lt;a href="https://ask.openstack.org/en/question/100102/can-not-receive-neutron-notification-while-can-receive-nova-notification/"&gt;ask.openstack.org&lt;/a&gt;, you can purge the queue to clear all the message in queue. In this way, the new message won't be stucked in the queue.&lt;/p&gt;
&lt;p&gt;the command is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;rabiitmqctl&lt;/span&gt; &lt;span class="n"&gt;purge_queue&lt;/span&gt; &lt;span class="n"&gt;queue_name&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;please use the specified queue name like 'notifications.nova' to replace the 'queue_name'.&lt;/p&gt;
&lt;p&gt;It is recommended to restart the services if purging queue does not help. Command example like,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;/etc/i&lt;/span&gt;&lt;span class="n"&gt;nit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;neutron&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="n"&gt;restart&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;the command patern is,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;/etc/i&lt;/span&gt;&lt;span class="n"&gt;nit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;xxx&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
&lt;span class="sr"&gt;/etc/i&lt;/span&gt;&lt;span class="n"&gt;nit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;xxx&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;
&lt;span class="sr"&gt;/etc/i&lt;/span&gt;&lt;span class="n"&gt;nit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;xxx&lt;/span&gt; &lt;span class="n"&gt;restart&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Hope this blog can help you.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 21 Dec 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-12-21:pages/2016/12/21/solution-can-not-receive-notification-of-openstack.html</guid><category>Openstack</category><category>neutron</category><category>notification</category></item><item><title>Listen to OpenStack Notification</title><link>http://www.muzixing.com/pages/2016/09/30/listen-to-openstack-notification.html</link><description>&lt;p&gt;在许多应用场景下，需要监听OpenStack的消息来做一些操作，从而实现事件驱动／消息驱动的业务。本文将介绍如何使用&lt;a href="http://kombu.readthedocs.io/en/latest/introduction.html#installation"&gt;kombu&lt;/a&gt;库来监听OpenStack的消息，包括neutron，nova等相关类型的notification。&lt;/p&gt;
&lt;h3&gt;Kombu, AMQP, RabbitMQ&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/celery/kombu"&gt;Kombu&lt;/a&gt;是Python的消息库，封装来许多消息的报文，支持包括&lt;a href="https://www.amqp.org/"&gt;AMQP&lt;/a&gt;等多种消息协议。而在OpenStack端，Notification的发布系统由&lt;a href="http://www.rabbitmq.com/"&gt;RabbitMQ&lt;/a&gt;实现。为了监听OpenStack发出的Notification, 我们需要在本地用Kombu库建立一个connection, 连接到OpenStack的消息发布系统。&lt;/p&gt;
&lt;h3&gt;Terminology&lt;/h3&gt;
&lt;p&gt;在学习过程中，会遇到Exchange, Queue等术语，此处将简要介绍这些概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Producers&lt;/p&gt;
&lt;p&gt;消息生产者，产生消息，并发送到交换器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exchanges&lt;/p&gt;
&lt;p&gt;消息交换器，接受生产者发送过来的消息，根据对应的routing_key，来将消息路由到对应的队列。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Queues&lt;/p&gt;
&lt;p&gt;队列接收来自交换器发来的消息，队列由消费者定义，自然也为消费者使用，用于存储消息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consumers&lt;/p&gt;
&lt;p&gt;消费者从队列中读取消息，并进行处理。消费者声明和定义队列，并将队列绑定到对应的exchange上。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Routing keys&lt;/p&gt;
&lt;p&gt;每一种消息都有路由键（routing_key）,可以被exchange用来判定如何路由消息到对应的队列。根据交换的类型不用，routing_key的解析过程不同。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Exchange type&lt;/h3&gt;
&lt;p&gt;AMQP协议中主要定义了3种exchange type，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Direct exchange&lt;/p&gt;
&lt;p&gt;根据routing_key的值，将匹配成功的消息发送到指定的队列。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fan-out exchange&lt;/p&gt;
&lt;p&gt;将消息发送到所有队列，和交换机的flood操作类似。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Topic exchange&lt;/p&gt;
&lt;p&gt;根据给定topic以及匹配规则来实现消息的路由。比如匹配的pattern为*.muzixing.#, 则hello.muzixing.info匹配成功，而muzixing.info匹配失败。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="topic" src="http://www.rabbitmq.com/img/tutorials/python-five.png" /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;Kombu Example&lt;/h3&gt;
&lt;p&gt;首先，需要先&lt;a href="http://kombu.readthedocs.io/en/latest/introduction.html#installation"&gt;安装Kombu&lt;/a&gt;。安装之后，可以通过以下的示例代码来连接到OpenStack。注意需要将user，pwd，host和port修改成对应的OpenStack消息服务器的用户名，登陆密码，ip地址和传输层端口号。 完成之后，运行该python文件，即可监听OpenStack的通知。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;kombu&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Exchange&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;kombu.log&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_logger&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;kombu.mixins&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ConsumerMixin&lt;/span&gt;

    &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConsumerMixin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;event_queues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;notification.nova&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;Exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;nova&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;topic&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;routing_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;notifications.neutron&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;Exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;neutron&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;topic&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;routing_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_consumers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queues&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_queues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                             &lt;span class="n"&gt;callbacks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_task&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Receive message: &lt;/span&gt;&lt;span class="si"&gt;%r&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;kombu&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Connection&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;kombu.utils.debug&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;setup_logging&lt;/span&gt;

        &lt;span class="c"&gt;# setup root logger&lt;/span&gt;
        &lt;span class="n"&gt;setup_logging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;DEBUG&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loggers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;connect_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;amqp://&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;:&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pwd&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;@&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;:&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;//&amp;#39;&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connect_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Stopped&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上示例代码中有两个地方需要注意。首先是需要将用户名等信息修改正确，其次是Queue的定义。在Worker类中，定义了event_queues列表，列表中是对应的Queue，用来接收️Notification。为了接收nova的信息，需要构造一个Exchange instance作为Queue的参数，其中第一个参数‘nova’是exchange的名字，代表着这个队列将绑定到nova的消息exchange上。同样的，为了接受neutron的消息，我们还定义了另一个队列，队列绑定到了名字叫‘neutron’的exchange上。同理，若希望绑定到对应的exchange，继续添加Queue即可。Routing的参数类型这里设置为topic, durable参数表示消息数据的持久化特性。routing_key则是路由的键值。此处接受所有来自对应名称exchange的消息。event_queue将作为Consumer类初始化实例的参数，用于实例化消费者。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConsumerMixin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;event_queues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;notification.nova&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;Exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;nova&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;topic&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;routing_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;notifications.neutron&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;Exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;neutron&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;topic&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;routing_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;OpenStack目前在云环境中应用十分广泛，是非常值得喜欢云计算和SDN的同学去学习和研究的。作为一个大型的项目，OpenStack采用了AMQP来分发事件。作者在工作过程中需要使用OpenStack的事件，因此总结来这一篇文章。特别感谢谷歌给予的大力支持，没有谷歌我就查不到解决问题的正确姿势[1]。希望能给读者带来一些帮助。&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;[1] "Listen to OpenStack Neutron Messages from RabbitMQ using Kombu messaging library", http://thetaooftech.blogspot.com/2014/04/listen-to-openstack-neutron-messages.html&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 30 Sep 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-09-30:pages/2016/09/30/listen-to-openstack-notification.html</guid><category>OpenStack</category><category>kombu</category></item><item><title>在barefoot拜访Nick McKeown教授</title><link>http://www.muzixing.com/pages/2016/09/13/zai-barefootbai-fang-nick-mckeownjiao-shou.html</link><description>&lt;p&gt;自学习SDN以来已经三年多了。虽然依然是没有实际的商业产品开发经验，学术水平也是渣渣，但是多少掌握了一些基础知识，学会了一些技术。在学习SDN的过程中，不得不提的就是Nick McKeown教授，他发表过很多著名的论文，比如OpenFlow、Mininet、P4的论文等。他也创建了ONF和ONRC等组织，推动SDN开源的发展，可谓是SDN届的领头羊，大师。所以作为一个学习SDN的学生，自然十分敬仰。&lt;/p&gt;
&lt;p&gt;很幸运地得到了CIIP一年的实习机会，可以在思科美国总部实习一年，终于有机会在硅谷探索一翻，自然不能放过那些在书中和新闻里报道的地点和人物。在游览了斯坦福，berkeley等名校之后，就开始里知名创业公司和大师的拜访之旅。&lt;/p&gt;
&lt;p&gt;很高兴自己的博客被barefoot的ron前辈看到，然后我们就建立了联系。刚好他也回到里硅谷，微信一约就决定了时间去参观barefoot和拜访Nick教授，顺便一起吃个饭，聊一聊技术。&lt;/p&gt;
&lt;p&gt;一大早特别开心，直接就不去上班，uber过去拜访。手机号刚过期，在没有手机的情况下，利用xfinity的Wi-Fi让司机成功找到了我，太感谢xfinity和uber。&lt;/p&gt;
&lt;p&gt;终于来到了位于PALO ALTO的barefoot，它就在斯坦福校园边上。和ron前辈碰头之后，他就领着去见了偶像Nick教授。&lt;/p&gt;
&lt;p&gt;打开Nick教授的办公室门就看到了他，没想到他这么年轻，这么和善。没有那种官僚气息，更多的是一种工程师的感觉。见到偶像简直太开心了。我很高兴地自我介绍，然后接下来又聊了聊sdnlab和p4。最后教授建议多参加湾区的SDN活动，多参加P4的线下活动，参与到P4中。&lt;/p&gt;
&lt;p&gt;聊完之后，ron前辈提议拍个合照，正合我意，我可是连单反都带来了。很高兴地拍了几张和Nick教授的合影，高兴地快飞起了。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="Nick and Cheng Li" src="http://ww2.sinaimg.cn/mw690/7f593341gw1f7t372pp4kj21lz23ob2b.jpg" /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;告别教授之后，ron前辈带着去边上的饭店吃了顿饭，又一起聊了P4目前的状态，讨论P4如何和实验室合作和sdnlab合作的事，一切都很开心。后来刚从Princeton毕业的博士哥小舟也来一起聊技术，特别开心。&lt;/p&gt;
&lt;p&gt;PALO ALTO是好地方啊，比Cisco所在的Mipitas不知道好多少。还有十一个月，剩下的时间要好好学习，好好工作，多探索一下湾区，去感受科技的魅力，感受创业的魅力。&lt;/p&gt;
&lt;p&gt;来美帝一个多月来，基本生活适应来，浪了一个多月之后，开始进入了在国内学习的正常节奏。早上9点上班，下午5点多下班，然后去健身一个小时，再回来做饭，吃饭，然后8点左右飞奔去Building 18自习。那里还有几个准备GRE的本科生，他们也好努力。我也要加油努力。希望未来会更好，希望校招能快一些得到好的Offer。一切都会越来越好的。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 13 Sep 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-09-13:pages/2016/09/13/zai-barefootbai-fang-nick-mckeownjiao-shou.html</guid><category>silicon valley</category></item><item><title>Getting Started of MongoDB</title><link>http://www.muzixing.com/pages/2016/08/30/getting-started-of-mongodb.html</link><description>&lt;h3&gt;What is MongoDB&lt;/h3&gt;
&lt;p&gt;MongoDB is an open-source document database that provides high performance, high availability, and automatic scaling.[1]&lt;/p&gt;
&lt;p&gt;MongoDB（来自于英文单词“Humongous”，中文含义为“庞大”）是可以应用于各种规模的企业、各个行业以及各类应用程序的开源数据库。作为一个适用于敏捷开发的数据库，MongoDB的数据模式可以随着应用程序的发展而灵活地更新。与此同时，它也为开发人员 提供了传统数据库的功能：二级索引，完整的查询系统以及严格一致性等等。 MongoDB能够使企业更加具有敏捷性和可扩展性，各种规模的企业都可以通过使用MongoDB来创建新的应用，提高与客户之间的工作效率，加快产品上市时间，以及降低企业成本。&lt;/p&gt;
&lt;p&gt;MongoDB是专为可扩展性，高性能和高可用性而设计的数据库。它可以从单服务器部署扩展到大型、复杂的多数据中心架构。利用内存计算的优势，MongoDB能够提供高性能的数据读写操作。 MongoDB的本地复制和自动故障转移功能使您的应用程序具有企业级的可靠性和操作灵活性。[2]&lt;/p&gt;
&lt;h3&gt;About MongoDB&lt;/h3&gt;
&lt;p&gt;MongoDB is a No-SQL database. MongoDB server can maintain some databases, each database can maintain many collections. Collection is a concept like table in SQL database. Each Collection contain many documents. Each Document is a Json style object, which has many 'key':'value' pairs. For easy under stand, a table refered from [3] shows below.&lt;/p&gt;
&lt;table class="table-bordered table-striped table-condensed"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;SQL Term/Concept&lt;/th&gt;
&lt;th&gt;MongoDB Term/Concept&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;database&lt;/td&gt;
&lt;td&gt;database&lt;/td&gt;
&lt;td&gt;数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table&lt;/td&gt;
&lt;td&gt;collection&lt;/td&gt;
&lt;td&gt;数据库表/集合&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;row&lt;/td&gt;
&lt;td&gt;document&lt;/td&gt;
&lt;td&gt;数据记录行/文档&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;column&lt;/td&gt;
&lt;td&gt;field&lt;/td&gt;
&lt;td&gt;数据字段/域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;索引&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table joins&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;表连接,MongoDB不支持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;primary key&lt;/td&gt;
&lt;td&gt;primary key&lt;/td&gt;
&lt;td&gt;主键,MongoDB自动将_id字段设置为主键&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;h3&gt;Install MongoDB&lt;/h3&gt;
&lt;p&gt;For Mac OS, MongoDB can be installed by using command[4]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;mongodb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;if you want to install MongoDB with supporting TSL/SSL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;mongodb&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;openssl&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Install Pymongo&lt;/h3&gt;
&lt;p&gt;To use MongDB by Python, you still need to install pymongo&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;pymongo&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;if you use Python3, please use pip3 to install pymongo&lt;/p&gt;
&lt;h3&gt;Use MongoDB by CLI&lt;/h3&gt;
&lt;p&gt;After installing MonogoDB, you can start MongoDB by[5]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    ./mongo
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Because the CLI is a JavaScript shell, so you can execute code with it. For example, you can do some easy calculation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt;1+2
    &amp;gt;3
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;List database&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt; show dbs
    &lt;span class="nb"&gt;local  &lt;/span&gt;0.000GB
    &lt;span class="nb"&gt;test   &lt;/span&gt;0.000GB
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Use database&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt; use &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="nb"&gt;    &lt;/span&gt;switched to db &lt;span class="nb"&gt;test&lt;/span&gt;    
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Show database name of which is using&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt;db
    &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Create database&lt;/h4&gt;
&lt;p&gt;You can enter 'use database_name' to create a new database, if the database name is not existed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt; use milestone
    switched to db milestone
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Only when you add some documents into dababase's collection, can you see the database name by using 'show dbs'. However you can use 'db' to show the using database.&lt;/p&gt;
&lt;h4&gt;List collections&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    show collections
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Create collection&lt;/h4&gt;
&lt;p&gt;You can use createCollection method to create a collection for databse.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt; show collections
    &amp;gt; db.createCollection&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;muzixing&amp;quot;&lt;/span&gt;,&lt;span class="o"&gt;{&lt;/span&gt;size:100000&lt;span class="o"&gt;})&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt; : 1 &lt;span class="o"&gt;}&lt;/span&gt;
    &amp;gt; show collections
    muzixing
    &amp;gt; 
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Remove collection&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    db.collection_name.drop&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Add document into collection&lt;/h4&gt;
&lt;p&gt;You can insert data by insert method:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt; db.muzixing.insert&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;www.muzixing.com&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
    WriteResult&lt;span class="o"&gt;({&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;nInserted&amp;quot;&lt;/span&gt; : 1 &lt;span class="o"&gt;})&lt;/span&gt;
    &amp;gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Search document&lt;/h4&gt;
&lt;p&gt;Use find() method to find all documents or fill parameter to select documents.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt; db.muzixing.find&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c6102b4366cfc975563b94&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;www.muzixing.com&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c611d24366cfc975563b95&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;chengli&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c611d94366cfc975563b96&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;milestone&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &amp;gt; 
    &amp;gt; db.muzixing.find&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;:&lt;span class="s1"&gt;&amp;#39;www.muzixing.com&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c6102b4366cfc975563b94&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;www.muzixing.com&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &amp;gt; 
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Also, findOne method can be use to get one document.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt; db.muzixing.findOne&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c6102b4366cfc975563b94&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;www.muzixing.com&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &amp;gt; db.muzixing.find&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c6102b4366cfc975563b94&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;www.muzixing.com&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c611d24366cfc975563b95&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;chengli&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c611d94366cfc975563b96&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;milestone&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &amp;gt; 
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Update document&lt;/h4&gt;
&lt;p&gt;Update command's syntax shows below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    db.collection.update&lt;span class="o"&gt;(&lt;/span&gt;
       &amp;lt;query&amp;gt;,
       &amp;lt;update&amp;gt;,
       &lt;span class="o"&gt;{&lt;/span&gt;
         upsert: &amp;lt;boolean&amp;gt;,
         multi: &amp;lt;boolean&amp;gt;,
         writeConcern: &amp;lt;document&amp;gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &amp;gt; db.muzixing.update&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;licheng&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$set&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;chengli&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}})&lt;/span&gt;
    WriteResult&lt;span class="o"&gt;({&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;nMatched&amp;quot;&lt;/span&gt; : 0, &lt;span class="s2"&gt;&amp;quot;nUpserted&amp;quot;&lt;/span&gt; : 0, &lt;span class="s2"&gt;&amp;quot;nModified&amp;quot;&lt;/span&gt; : 0 &lt;span class="o"&gt;})&lt;/span&gt;

    &amp;gt; db.muzixing.find&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c615564366cfc975563b97&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;chengli&amp;quot;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;face&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;handsome&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &amp;gt; db.muzixing.update&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;chengli&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$set&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;licheng&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}})&lt;/span&gt;
    WriteResult&lt;span class="o"&gt;({&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;nMatched&amp;quot;&lt;/span&gt; : 1, &lt;span class="s2"&gt;&amp;quot;nUpserted&amp;quot;&lt;/span&gt; : 0, &lt;span class="s2"&gt;&amp;quot;nModified&amp;quot;&lt;/span&gt; : 1 &lt;span class="o"&gt;})&lt;/span&gt;

    &amp;gt; db.muzixing.find&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; : ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;57c615564366cfc975563b97&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;licheng&amp;quot;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;face&amp;quot;&lt;/span&gt; : &lt;span class="s2"&gt;&amp;quot;handsome&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &amp;gt; 
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Remove document&lt;/h3&gt;
&lt;p&gt;Syntax shows below&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    db.collection.remove&lt;span class="o"&gt;(&lt;/span&gt;
       &amp;lt;query&amp;gt;,
       &amp;lt;justOne&amp;gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;57c615564366cfc975563b97&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;licheng&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;face&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;handsome&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;57c617694366cfc975563b98&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;girl friend&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;face&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;beautiful&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;licheng&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;WriteResult&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;nRemoved&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;57c617694366cfc975563b98&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;girl friend&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;face&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;beautiful&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;For more info of learning MongoDB for Chinese, see &lt;a href="http://www.runoob.com/mongodb/mongodb-tutorial.html"&gt;MongoDB tutorial. &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For English speaker, see &lt;a href="https://docs.mongodb.com/"&gt;MongoDB Docs.&lt;/a&gt;and &lt;a href="http://www.tutorialspoint.com/mongodb/index.htm"&gt;tutorialspoint-MongoDB&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Pymongo&lt;/h3&gt;
&lt;p&gt;Actually, people always use some coding language libs to use MongoDB instead of CLI. After learning MongoDB and CLI usage, it is completely easy to understand how to use pymongo to manipulate MongoDB[7]. &lt;/p&gt;
&lt;p&gt;First of all, you should start a MongoDB server, such as we can start MongoDB at localhost, the default port of MongoDB is 27017.&lt;/p&gt;
&lt;p&gt;Example shows below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pymongo&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pymongo&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MongoClient&lt;/span&gt;


    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;# get client&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mongodb://localhost:27017/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;client&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# get database, if the database has existed.Otherwise, create it&lt;/span&gt;
        &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;db:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# get collection, if it has existed, otherwise, create it.&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chengli&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;collection name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collection_names&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;collection: &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# get document&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;find one: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_one&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="c"&gt;# post data item&lt;/span&gt;
        &lt;span class="n"&gt;new_man&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;age&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;oo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;sex&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;male&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_man&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="c"&gt;# get multi items&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# find data&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_one&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;chengli&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="c"&gt;# update data&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;haha&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;$set&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;employee&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;employee&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_index&lt;/span&gt;&lt;span class="p"&gt;([(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;age&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pymongo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ASCENDING&lt;/span&gt;&lt;span class="p"&gt;),])&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;age&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pymongo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ASCENDING&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Note that&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;This is Python3 code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some code is Non-idempotent, such as insert data and remove data, so different results will generate when run code in different round.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More info of pymongo, see &lt;a href="http://api.mongodb.com/python/current/tutorial.html"&gt;Mongo API Doc&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;p&gt;[1]https://www.mongodb.com&lt;/p&gt;
&lt;p&gt;[2]https://www.mongodb.com/cn&lt;/p&gt;
&lt;p&gt;[3]http://www.runoob.com/mongodb/mongodb-databases-documents-collections.html&lt;/p&gt;
&lt;p&gt;[4]https://docs.mongodb.com/manual/installation/&lt;/p&gt;
&lt;p&gt;[5]http://www.runoob.com/mongodb/mongodb-linux-install.html&lt;/p&gt;
&lt;p&gt;[7]http://wiki.jikexueyuan.com/project/start-learning-python/232.html&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 30 Aug 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-08-30:pages/2016/08/30/getting-started-of-mongodb.html</guid><category>MongoDB</category><category>pymongdb</category></item><item><title>坏演员和好演员</title><link>http://www.muzixing.com/pages/2016/08/26/pi-yan-yuan-he-hao-yan-yuan.html</link><description>&lt;p&gt;空荡荡的房间，只剩下一盏昏黄的灯和我。门外的灯光，从门口探了进来，却慢慢消失在地毯上。就剩我一个人。&lt;/p&gt;
&lt;h3&gt;坏演员&lt;/h3&gt;
&lt;p&gt;心里突然有些不安，多了一些慌张，想起了遥远的地方，遥远的她。&lt;/p&gt;
&lt;p&gt;不能说是错，不能说是过，也许我还没有醒来，也许我不会醒来，也许心里还有期待，也许我只是寂寞难耐。&lt;/p&gt;
&lt;p&gt;“如果从来，我不会说我们试试看，我希望我没有去兼职，没有去玉渊潭，没有认识你”，这是她发给我的最后一句话。&lt;/p&gt;
&lt;p&gt;多么可爱的姑娘，你曾经让我幸福，也曾让我牵挂。我们憧憬过美好的未来，说过可以浪迹天涯。我们都曾努力会适应对方，相互妥协，去成全对方的梦想。但一切都过去了，就算有时候忍不住会努力寻找你的消息，努力假装忘记。&lt;/p&gt;
&lt;p&gt;曾几何时，我一直很挣扎，很纠结，很抓狂，很沮丧。岁月悄悄抹去了爱恋，困难慢慢爬上了心头，我思虑，我怀疑，我坚定，我失望，但我不曾背叛。相爱总是简单，相处最难。从曾经紧紧相拥，到后来同床异梦，希望渐渐淡出来我的眼眶。我们曾试过沟通，我们曾试过妥协，我们都试过。你依然是个天真可爱的姑娘，但我却有了一个现实而残忍的模样。&lt;/p&gt;
&lt;p&gt;她是个好姑娘，值得更好的人好好爱她，让她觉得自己很好，很幸福，这是我做不到的。&lt;/p&gt;
&lt;p&gt;在想提出分手的那些日子，我每天都像一个演员一样，很痛苦、很累地扮演着很开心的自己。我内心的压抑和需求，我想告诉她，但是没有用。但人不能一直口是心非，自欺欺人，带着面具生活。&lt;/p&gt;
&lt;p&gt;第一次提分手的晚上，我不应该去她，因为我知道我肯定会失败，因为我怎么都想不出来我会这么残忍地去伤害一个无辜的姑娘。我去见她了，我失败了。&lt;/p&gt;
&lt;p&gt;离开前的一段日子，我想着，打算着，自责着，放弃着，坚持着，自我伤害着。还好我回到了小岛，一个没有她的地方。我可以安静地思考，我到底要什么样的未来。她说过，最残忍的事情就是：你爱他，但是他的未来没有你。可是我怎么也假想出我们未来的模样。&lt;/p&gt;
&lt;p&gt;我25岁生日前一天，她竟然在工作的时候主动给我打电话，我很吃惊。电话那头的她，小心翼翼地试探着我的态度，最终还是说出了要辞职的想法。不怪她，确实这份工作不适合她。她说怕我骂她，就像以前她换工作那样骂她，但是我没有。她很开心，因为只要我不骂你，她就已经没有什么压力了，工作可以再找。她总是那么可爱。我说：“怎么会，我这么善解人意的人，怎么会骂你，我能理解你”。但其实，我知道，当初我骂你，是因为我觉得她可以，但是她放弃了，我不甘。现在我不骂她，是因为我理解她，这份工作让她的生活特别难堪，不高的收入，频繁的加班，看不到的希望。我说没事，好好休息，再想想办法找新工作。她说想回郑州，那里是她的家乡。我说好，都可以试试。我知道北京不适合她，她也不适合北京。过了夜里12点，她并不记得我的生日到了，我可以理解，也不觉得忧伤。只希望她能过得好一些，再好一些。&lt;/p&gt;
&lt;p&gt;那天是我25岁生日，说来我已经好老了。陪着爸妈回去外婆家，一个真正的小山村。到了家里发现大伯家的女儿不太正常，别人都当她是智障，打她，骂她。我看着心疼，就试着接近她。她情绪容易激动，爱哭，爱笑，但是没有暴力倾向。她记得我，记得我们家所有的人，记得小学上学的时候谁家的孩子打过她，记得村里哪一个小孩欺负过她，记得她爸爸总是打她骂她，记得为什么她从福利学校逃出来。她老是问我：“哥哥，你不会打我吧？哥哥，你不会骂我吧？”我每一次都耐心地告诉她不会，但是过不了几分钟，她又回问我同样的问题。每一次都很心酸。我试着问题一些问题，测试她的逻辑反应能力怎么样，发现她的逻辑反应是正常的。而且她可以自己通过看电视学会唱歌，学会识别若干文字两个字，但是她没有受过教育，所以让她写字的时候，简直就是在画画。&lt;/p&gt;
&lt;p&gt;别人都在用语言暴力欺负她，凶她，骂她，她很怕。我想就算一条小狗，从小这么打骂，它也会怕人吧，何况一个可爱的小姑娘。我努力向亲戚们解释为什么她会这样，也许她没有太大的问题，吃点镇定剂什么的控制一下就会和正常人一样。我告诉亲戚们她是从小被吓到大，所以怕人，因为没有受过教育所以笨，因为妈妈有癫痫，她小时候还发过高烧，所以精神有些问题，所以吃点药，控制一下情绪就好了。大伯母是比较开明的人，她也心疼这个孩子，也试过送去福利学校，但是她自己跑出来。所以她想带她去做安宁医院做鉴定，可是没有钱。我说我带她去，你们不知道手续，我去尝试。就这么约好了下周带她去医院，也算不让良心受到谴责，也算是一份特殊的生日礼物吧。年纪大了，过生日什么的早就没激情了，反倒是为年龄增长而感到忧伤。&lt;/p&gt;
&lt;p&gt;在她办离职的那一天，也就是我生日的那天，我想着办法陪着她，一起聊天，聊以后，聊郑州。她回郑州去，压力会小一点，会有很多朋友，可以很快回家。我也跟她说了那个小姑娘的事情，说了我的打算。傍晚的时候，我们打了最后一通电话。&lt;/p&gt;
&lt;p&gt;不知为何，我觉得我自己特别残忍，特别贱，特别不负责任。我一只在暗示着她我想分手，一直在提起这件事，可是我从来不说，因为我根本说不出口，我没有勇气割舍，哪怕心里再多不满，也总有许多留恋。我怕我伤害她，我就这么挣扎着，但感情最怕的就是拖着。&lt;/p&gt;
&lt;p&gt;终于电话那头的她忍不住说出了分手，我笑着说别啊，但是心里已经接受，我很懦弱。但最终我还是勉强说了同意。分明是我想分手，到最后却弄得好像我很勉强接受一样，我恶心这样的自己。这也算一种生日礼物嘛？许多年之后，再回头看，也许算吧。一种回忆，不论好坏，它总会让我成长。&lt;/p&gt;
&lt;p&gt;我不是一个好演员，从来不会掩饰忧伤。&lt;/p&gt;
&lt;h3&gt;好演员&lt;/h3&gt;
&lt;p&gt;第一次坐十多个小时的飞机，是痛苦的。但一个没有她的地方，也许可以慢慢疗伤。幸运的是，新生活的开始，充斥着各种新的信息：新的朋友，新的语言，新的环境。我开始应接不暇，也好，正好可以慢慢放下。&lt;/p&gt;
&lt;p&gt;新的朋友都很酷，同事都很nice。住的地方很赞，工作也很忙，突然不用去思考过去的生活，全身心投入当下，很幸福。我来到了一个没有雾霾，环境优雅，却也人烟稀少的地方，孤独而不寂寞。&lt;/p&gt;
&lt;p&gt;一年的实习，就这么开始了。在google工作的好朋友见我的第一面就蛊惑我留下来。我知道他，知道他一个人的孤独。&lt;/p&gt;
&lt;p&gt;平时的生活都很好，肉很便宜，蔬菜有点贵，但总体而言，吃的都很便宜。微薄的实习工资虽然发不了大财，但是吃好玩好还是无压力的。工作上，逐步进入了正轨，来自俄罗斯的mentor是个天生的喜剧演员，和我很搭，虽然很多时候我听不太懂他的俄式英语，但也还是可以从颜艺上判断出大概意思。每个周都有party，中国的小伙伴明显就是比较保守拘谨的，所以一般也不参加。偶尔我会去参加一下不喝酒的party，练练口语，听听各种口音，认识一下朋友。&lt;/p&gt;
&lt;p&gt;每天下班回来和印度室友去健身房，然后回来自己做饭。周末生活比较丰富，刚来的第一周去了google参观，满足一下对google的崇拜。这周去爬了mission peak， 去斯坦福膜拜sdn开山鼻祖 nick教授的办公室，下周又要去redwoods park，一切都安排得很好，很紧凑，这才是新生活应该有的样子。&lt;/p&gt;
&lt;p&gt;实习之余，还会关注一下校招的事情，虽然极有可能我延期毕业，但是校招还是要参加一下的。不过比较幸运的是，投了几家公司反响还不错，期待后续的进展吧，渴望自己能拿到想要的offer。&lt;/p&gt;
&lt;p&gt;书的事已经拖了很久了，终于完成了签约，不管怎么样11月底之前都要出版了。幸好我的部分早已完成，就等前辈的了。哎，创业的人的时间真是难挤，希望一切顺利吧。论文发了，可以毕业了，了却心头大事。sdn大赛，没办法去答辩，失约了，也再也不会出现了，收获一张优胜奖。&lt;/p&gt;
&lt;p&gt;相比情感上的路人演技，在学习工作方面，我想我很好地扮演了自己的角色。也许是因为我是一个专业的业余即兴表演演员吧。&lt;/p&gt;
&lt;h3&gt;岁月静好&lt;/h3&gt;
&lt;p&gt;大伯家的小孩确诊为精神病加智商不育迟缓，得到诊断后，挣扎的年头也彻底断了。但这下她可以办一些手续，得到一些政府的帮助吧。&lt;/p&gt;
&lt;p&gt;我曾有一个梦想，要当一个导演，把自己的故事展现给别人看。然而生活中并不是所有人都可以很好地导演自己的生活，更多是妥协和隐藏。为了更好的生活，我更像一个演员。谁不爱粉墨登场，却不知暗自心伤。我总是把美好的东西展现出来，把黑暗，负面的信息自己消化，也曾想有个人，相互扶持，呵护对方。那个人应该还没有出现吧。虽然最近连续被一个男生和一个女生表示想睡我，但是也许，我还需要时间来疗伤。幸好有李健，支撑我走过高潮，低谷，灿烂与迷醉。&lt;/p&gt;
&lt;p&gt;繁花散尽，夜梦初醒，心中无羁绊。大幕落下，粉妆卸去，何处是人生。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 26 Aug 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-08-26:pages/2016/08/26/pi-yan-yuan-he-hao-yan-yuan.html</guid><category>演员</category></item><item><title>我是怎么丢掉饭碗的</title><link>http://www.muzixing.com/pages/2016/07/26/wo-shi-zen-yao-diu-diao-fan-wan-de.html</link><description>&lt;p&gt;我出门名门，骨骼精奇，身怀绝迹，独步武林多年，凭着祖传的无影手和行走江湖多年练就的一套安检基本法，我房霍强当上了桃花镇的城门护卫队的队长，也算不负家族期望。&lt;/p&gt;
&lt;p&gt;桃花镇自古以来就是兵家必争之地，又有许多桃花盛开，所以也是一个远近闻名的旅游胜地。为保证桃花镇的安全，又要保证桃花镇的游客流量，我房某人必须要快速地做好安检工作。多亏我祖传的无影手绝技和总结的安检基本法，我才能应对每天如此多的人流。&lt;/p&gt;
&lt;p&gt;身居要位的我身价自然不会太低，多少也要个20W年薪吧。我要价高也是有道理的，自古以来，能做安检工作的都是像我这样骨骼精奇又身怀绝学的人，软硬实力俱佳啊。先说软实力，我行走江湖十余载，见过采花、毛贼、刺客少说上百，多了上千，早已掌握了一套基本法，练就了一副火眼金睛，一眼就能看出蹊跷。只要学会了这套安检基本法，就可以做到像我这样的火眼金睛。硬实力上，与普通骨架的人不同，我们家族的人骨骼精奇，手速极快，有无影手之称。无影手是我们家族的祖传技能，到我已经19代有余。即使软件方面其他人可以做到，但是别人做不到我的速度，所以我身价才这么高。&lt;/p&gt;
&lt;p&gt;事业成功不算什么，我房霍强还是和镇长女儿慕容翠花定了亲的男人，那可是要迎娶白富美的节奏。&lt;/p&gt;
&lt;p&gt;我的工作内容无非就是禁止一些黑名单上的人进城，限制人流等等，早已轻车熟路。我还可以防止DoS恶意攻击。比如有时会有同一拨人在不断假装去桃花庙上香，但他们不为了上香，只是为了占用每日庙里的游客数目，然后让真正上香的人无法进去。我需要把这类型的人堵在门外，不让他们捣乱。&lt;/p&gt;
&lt;p&gt;就因为上个月我搞定了125次DoS攻击，绩效加倍，所以昨天镇长大人决定将我和翠花的婚事提前到本月，并把彩礼减一半，只需20W。我心里窃喜，赶忙连喊了三声“谢谢岳父大人！”，把镇长大人乐得都合不拢嘴。&lt;/p&gt;
&lt;p&gt;今天上班的时候，我都快飞起来了。首先是因为马上我就可以结婚了，然后因为最近是桃花盛开的时候，从各地慕名而来的游客们把城门挤得水泄不通。一天忙下来，我有点应付不过来。我突然想到家中还有那不争气的弟弟可以来帮忙，于是就跟镇长大人提起了招新的需求。镇长大人作为我未来的岳父，自然也不愿意看到我累坏，但他无权招新，只好把需求上交给了有关部门。&lt;/p&gt;
&lt;p&gt;我盘算着镇长还有一个小女儿叫慕容淑芬，就比我弟弟小两岁，正值豆蔻年华，但发育得很着急！。我弟弟虽然蠢了一点，但是做这个安检的工作还是绰绰有余的。若是弟弟有20W年薪，和那城中的程序员差不多的收入水平的话，娶了镇长小女儿岂不美哉。&lt;/p&gt;
&lt;p&gt;我一边准备着婚礼的事，一边通知弟弟来帮忙的事，也没落下手头的工作，忙得焦头烂额。&lt;/p&gt;
&lt;p&gt;那天星期五，艳阳高照，微风和煦。弟弟已经来帮我三天有余了。今天应该是有消息的日子，镇长大人，哦不！岳父大人应该要来才对！我正思索着，回头一看，果然，岳父大人来了。我赶忙放下手头工作迎接上去。&lt;/p&gt;
&lt;p&gt;“房霍强啊，你过来，我跟你说件事。”岳父大人好像有什么难为情的事情不好当众说，把我拉到了城墙根。&lt;/p&gt;
&lt;p&gt;“你房霍强一直都是我最信任的好帮手，我一直很喜欢你这个小伙子！”听到岳父大人这么一说，我不好意思地咧开嘴笑，手都不知道放哪里好。&lt;/p&gt;
&lt;p&gt;“那个，招人的事啊，这个。恩，是这样的”，岳父大人欲言又止。&lt;/p&gt;
&lt;p&gt;“没事，都听组织安排！”我只能应和，但脸上早已没有了笑容。&lt;/p&gt;
&lt;p&gt;“上头觉得你要的工资太高了，所以派来了一个新的员工，工资低得很，但也能胜任你做的安检啊。最近经济形势不景气，上头已经开始采用新的工种来节省各种开支了。不仅仅是你们安检员，还有快递员都要改革，深化改革嘛。” 岳父大人语重心长地看着我，拍了拍我的肩，安慰地说。&lt;/p&gt;
&lt;p&gt;我回头看了一眼，才发现确实来了一个年轻的小伙子，他正对着我傻笑。&lt;/p&gt;
&lt;p&gt;“岳父大人，没事，没事。我让我弟弟回去就好了。”我尴尬地找台阶。&lt;/p&gt;
&lt;p&gt;“恩，那就好。我走了，你自己处理一下吧。”岳父大人说完，冲我无奈地点了点头，然后就转身回去了。&lt;/p&gt;
&lt;p&gt;那天特别尴尬，我还记得弟弟惊愕的眼神，那个新人傻傻的笑，还有站在中间尴尬的我。&lt;/p&gt;
&lt;p&gt;“你是怎么找到这个工作的啊？”送走弟弟之后，我疑惑地问他。&lt;/p&gt;
&lt;p&gt;“哦，前辈，我是菲卓.派尔沃，我是安全管理学院毕业的学生，学会了安检基本法，就找到了这个工作。” 他说完傻傻地看着我笑，很傻，很天真。&lt;/p&gt;
&lt;p&gt;“什么？你就是一个普通的人？不会无影手？”我十分惊讶地追问。&lt;/p&gt;
&lt;p&gt;“不会啊。我们学校的毕业生都是普通人，身体都是x86架构的，主要是因为我们学会了基本法就能找到工作了。其他学校的人还会去当快递员，他们也没有前辈您的无影手绝活，所以干活慢一点。但是我们工资低啊，所以工作容易找。” 还是那个傻傻的微笑，我觉得他的微笑有点烦。&lt;/p&gt;
&lt;p&gt;虽然他有点傻，但是工作确实一丝不苟，是比我慢一些，但他的收入是我的五分之一，少得有点可怜。要不是他抢了我弟弟的工作，把我的双联姻美梦打碎了，我还真挺喜欢他的。&lt;/p&gt;
&lt;p&gt;一个周之后，岳父大人又带过来一个新人，和菲卓.派尔沃一样的，一个普通人的身体，只是学会了基本法罢了。但是和上次不同的是，岳父大人告诉我一个噩耗：为了节省开支，选择了懂基本法，但工资低的普通人来干活，所以我的工资被减了一半！&lt;/p&gt;
&lt;p&gt;“岳父大人！你要帮帮我！工资减掉一半，我这个月没办法凑够20W彩礼啊！”我扑通一下跪在地上，抱着岳父大人的大腿恳求道。&lt;/p&gt;
&lt;p&gt;“别叫我岳父大人。我也没有办法。我觉得城里那个程序员更适合我女儿，你另寻高就吧。”岳父大人，哦不！镇长把我狠狠甩开，转身头也不回地走了。
“不！翠花不会同意的！”我跪在地上朝着离去的镇长哭着喊，但他只是停顿了一下，摇摇头，又继续走远了。&lt;/p&gt;
&lt;p&gt;翠花嫁给了那个程序员。&lt;/p&gt;
&lt;p&gt;我每天忧郁地做着我的工作。有了其他人的帮忙，身体不那么累了，心却很累。我每天都希望翠花能出城一趟，这样我还能见见她，但她从来没有！&lt;/p&gt;
&lt;p&gt;那些新人确实要比我好。他们只需要普通的x86骨架，可以学习很多知识，做快递员，安检员，而我只能当安检人员。他们对工资要求好低！像菲卓.派尔沃那样的安检员越来越多，他们可以被替换，可以进修新知识，能快速地上岗，也能随意调度，但我不能。我的身体是特制的，我只会学习基本法，而且我不会放低我的要求的。我不甘心！&lt;/p&gt;
&lt;p&gt;终于，来了第6个普通安检员，我终于失业了。再也不需要我了。他们可以完成我的工作，而且他们加起来的工资还没有我当初的一半。&lt;/p&gt;
&lt;p&gt;我没有脸面回家，但我离开了桃花镇，永远地离开了桃花镇，再也没有回来。
其实丢掉饭碗的何止我房霍强一人，那些拥有仰仗着特殊身体的人而索取高价的人，好多都丢了饭碗。比如我的快递员好哥们阿基，即使他的步伐快如闪电，转发包裹的效率又很高，也没有扛住…&lt;/p&gt;
&lt;p&gt;都是那群拥有x86骨架的“软包子”抢了我们的饭碗。在我眼里他们都是软包子，还起了英文名，“vRouter、vSwitch、vFW、vEPC、vADC……”好像自己很洋气一样。&lt;/p&gt;
&lt;p&gt;其实我的真实身份是防火墙，是传统的网元设备，而菲卓.派尔沃就是virtual firewall, 虚拟防火墙，是可以部署在通用的x86架构服务器上的VNF（虚拟网络功能）。随着网络功能虚拟化（NFV：Network Function Virtual） 的发展，这样的趋势将越来越明显。我苦思冥想，终于知道为什么受伤害的总是我？我明白了网络功能虚拟化以及它的特别之处。&lt;/p&gt;
&lt;p&gt;在传统网络中，网络元件一般是由专用硬件加定制的软件绑定，耦合度极高，无法分离，比如防火墙设备、DPI设备和路由交换设备等。但采用专用硬件的传统网元价格昂贵，而且定制网元软硬件紧密结合，不易升级，无法灵活部署应用，维护成本也很高，大大阻碍了部署新业务的进程。随着互联网的发展，云计算场景等多种新场景的出现，对网络提出了更多、更灵活的要求。运营商等网络基础设施提供商急需灵活的网络来满足新业务的需求。所以运营商们提出了NFV来解决这一问题。NFV主张将网元的软硬件分离，然后通过将软件部署在通用硬件平台上实现具体的网络功能。如防火墙、DNS和NAT等网络功能均可以由软件交付，然后在普通的x86服务器上运行，从而实现传统网元的功能。&lt;/p&gt;
&lt;p&gt;采用NFV解决方案可以减低投资成本（CapEx）和运维成本（OpEx），同时还可以提供更好的弹性和敏捷性，从而满足网络业务的需求，并加快新业务部署的速度。&lt;/p&gt;
&lt;p&gt;采用价格更优的通用架构的硬件，势必将大大减少企业的投资成本。而且存储和计算资源等均采用通用硬件架构，使得不同的服务可以共享同样的基础设施，增加系统的通用性，降低运维难度。此外，专用硬件升级换代周期过长，无法快速更新迭代，而相对低廉的通用硬件的升级周期比专用硬件短，所以可以缩短硬件设备升级的周期，从而提供更好的网络性能。&lt;/p&gt;
&lt;p&gt;采用部署VNF软件的方式，也会明显地降低管理运维成本。首先，通过修改软件功能可以快速支持新功能，而无需对复杂的专用设备进行维护和升级。其次，目前已有的云管理平台等管理系统可以提供自动化的部署和运维，从而极大地提升管理运维效率。而且，通过管理平台可实现VNF软件随业务迁移到任意通用架构的服务器上，从而实现网络业务随动的功能。&lt;/p&gt;
&lt;p&gt;由于NFV软硬件分离，软件可以在通用的硬件架构上随需迁移，所以NFV可以带来更多的弹性和敏捷性。因为NFV支持通过修改软件快速实现网络功能以及自动化部署等优点，所以采用NFV方案将极大地缩短新业务上线周期。&lt;/p&gt;
&lt;p&gt;虽然NFV相比传统网元有以上提到的明显优势，但是采用存在性能瓶颈的通用硬件使其在性能方面远不如采用专用硬件的传统硬件，就像故事中的派尔沃的安检速度远比不上有无影手的房霍强一样。尤其在对性能要求极高的电信网络、以及核心网络中，NFV和昂贵的专用设备相比并没有优势。而NFV性能不足的关键因素在于通用硬件的CPU在处理转发上的性能远不如专用硬件采用的NPU(Network Processing Unit)，所以目前NFV仅能部署在对性能要求不高的网络场景。如何才能解决NFV性能不足的问题呢？&lt;/p&gt;
&lt;p&gt;英特尔为网络转型提供了必要的构建模块,首当其冲的是英特尔架构(IA)处理器。例如, 英特尔至强E5系列处理器家族具备专为虚拟化环境优化的卓越性能。除处理器之外，英特尔还提供了其他多种关键技术，其中英特尔QuickAssist 加速技术能够为最多14个单独的虚拟化实例提供加速器服务(加密、压缩和算法卸载)；英特尔虚拟化技术为虚拟化软件提供了硬件辅助支持，可显著降低其规模、成本与复杂性；具备英特尔流量导向器和网络覆盖功能的 10/40/100 Gbit/秒的英特尔以太网技术能够在虚拟化环境中带来最高吞吐率。&lt;/p&gt;
&lt;p&gt;在性能补强上，英特尔还提供了一组快速处理数据包的开发平台及接口：DPDK(Data Plane Development Kit)。DPDK则采用轮询方式实现数据包处理过程，无中断，并通过零拷贝技术直接从内存读取数据包。这种处理方式节省了CPU中断时间、内存拷贝时间，并向应用层提供了简单易行且高效的数据包处理方式，使得网络应用的开发更加方便，最多可提升处理器10倍的性能。由于DPDK的存在，NFV的性能问题得到了有效的解决，极大地推动了NFV的工业化发展进程。目前，基于DPDK的解决方案是解决NFV性能不足问题的最普遍的做法。&lt;/p&gt;
&lt;p&gt;我叫房霍强，我出门名门，骨骼精奇，身怀绝技，独步武林多年。我丢了工作，走出桃花镇，但我不信没有我房某人的立身之处。我向牡丹县的方向走去，因为只有健硕的体魄才能胜任哪里的护卫，走到城墙不远处，我依稀看到了几个影子：x86的骨骼、英特尔的“芯”……&lt;/p&gt;
&lt;p&gt;Note That:本文章是ZDNET编辑私人约博主完成的稿件，更多约稿合作可邮件联系。联系方式可查看About me.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 26 Jul 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-07-26:pages/2016/07/26/wo-shi-zen-yao-diu-diao-fan-wan-de.html</guid><category>nfv</category></item><item><title>基于跳数\时延\带宽的最短/优路径和负载均衡</title><link>http://www.muzixing.com/pages/2016/07/08/ji-yu-tiao-shu-shi-yan-dai-kuan-de-zui-duan-you-lu-jing-he-fu-zai-jun-heng.html</link><description>&lt;p&gt;对于SDN初学者而言，最短路径转发应用和负载均衡应用是最常见，也是最适合学习的经典应用。根据链路权重参数的不同，主要有基于跳数、时延和带宽的几种最短\最优路径转发应用。根据链路可用带宽实现的最优路径转发本质上也是一种网络流量负载均衡的简单实现。本文将介绍笔者在学习过程中开发的网络感知模块以及基于跳数、时延和带宽三种最优路径转发应用。&lt;/p&gt;
&lt;h3&gt;基于跳数的最短路径转发&lt;/h3&gt;
&lt;p&gt;基于跳数的最短路径转发是最简单的最优路径转发应用。我们通过&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_awareness/network_awareness.py"&gt;network_awareness&lt;/a&gt;应用来实现网络拓扑资源的感知并计算最短路径。首先控制器通过下发LLDP报文来获取网络链路信息，然后再利用网络信息，生成网络拓扑图。网络感知应用使用networkx的有向图数据结构存储拓扑信息，使用networkx提供的&lt;a href="http://networkx.readthedocs.io/en/stable/reference/generated/networkx.algorithms.simple_paths.shortest_simple_paths.html"&gt;shortest_simple_paths&lt;/a&gt;函数来计算最短路径。shortest_simple_paths函数支持在图上找出源交换机到目的交换机的K条最短路径，其函数参数信息如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;shortest_simple_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在给定图G，源交换机source，目的交换机target以及链路权重类型weight的情况下，会返回一个路径生成器。通过K次调用生成器可以生成K条最短路径。&lt;/p&gt;
&lt;p&gt;获得最短路径之后，&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_awareness/shortest_forwarding.py"&gt;shortest_forwarding&lt;/a&gt;应用将完成流表下发等工作，实现基于跳数的最短路径转发应用。&lt;/p&gt;
&lt;h3&gt;基于时延的最优路径转发&lt;/h3&gt;
&lt;p&gt;基于时延的最优路径转发应用原理和基于跳数的最短路径转发应用类似，只是链路权重类型变成了时延。关于计算链路时延的原理，读者可以阅读&lt;a href="http://www.muzixing.com/pages/2016/05/24/ryuwang-luo-shi-yan-tan-ce-ying-yong.html"&gt;Ryu:网络时延探测应用&lt;/a&gt;。&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_awareness/network_delay_detector.py"&gt;Network_Delay_Detector&lt;/a&gt;是一个网络时延探测应用，其在获取到链路时延之后，将时延数据存储到Networkx的图数据结构中，以供其他模块使用。&lt;/p&gt;
&lt;p&gt;通过设置链路权重参数，Shortest_forwarding应用可以基于时延数据计算最优的转发路径。&lt;/p&gt;
&lt;h3&gt;基于带宽的最优路径转发/负载均衡&lt;/h3&gt;
&lt;p&gt;基于带宽的最优路径相比以上两种应用相对要复杂一些。为了降低计算复杂度，我们采用先计算基于跳数的K条最短路径，再从中选取可用带宽最大的那条路径最为最优解。链路可用带宽的数据由&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_awareness/network_monitor.py"&gt;nework_monitor&lt;/a&gt;应用提供。该应用周期地获取链路的剩余带宽，并将带宽数据存储到networkx的图结构中，提供给其他模块使用。此外，network_monitor模块还实现了基于链路可用带宽的最优转发路径的计算，为其他模块提供最优路径信息。&lt;/p&gt;
&lt;p&gt;通过设置链路权重参数，Shortest_forwarding应用可以基于带宽数据计算最优的转发路径。本质上，network_monitor基于当前流量，为新数据流选择最佳转发路径，也是一种网络流量负载均衡的实现，只是其调度算法相对简单。&lt;/p&gt;
&lt;h3&gt;使用方法&lt;/h3&gt;
&lt;p&gt;为解析权重和最短K路径的参数，还需要在Ryu中注册全局的启动参数。注册参数的方法十分简单，只需要在Ryu顶级目录下的flags.py文件中添加如下的代码即可：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_cli_opts&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="c"&gt;# k_shortest_forwarding&lt;/span&gt;
        &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;k-paths&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;number for k shortest paths&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StrOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;weight&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;hop&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;type of computing shortest path.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成以上修改后，将&lt;a href="https://github.com/muzixing/ryu/tree/master/ryu/app/network_awareness"&gt;Github仓库&lt;/a&gt;中的代码下载到本地，然后放置到Ryu目录下合适的位置，比如Ryu/app目录下。&lt;/p&gt;
&lt;p&gt;最后还需要重新安装Ryu：进入到ryu/的根目录，运行setup.py文件，并添加install参数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;重新安装完成之后，启动shortest_forwarding应用，并添加observe-links，链路权重和最短路径条数等重要参数,示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="sr"&gt;/app/&lt;/span&gt;&lt;span class="n"&gt;network_awareness&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;shortest_forwarding&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;observe&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bw&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;启动Ryu之后，启动任意的SDN网络，如Mininet模拟的网络，并连接到Ryu控制器。最后可以在Mininet输入框中输入pingall进行测试。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;mn&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;为了方便使用，读者可以通过修改&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_awareness/setting.py"&gt;setting.py&lt;/a&gt;中的信息来修改应用的重要参数，比如获取链路信息的周期，是否打印网络信息等等。setting信息具体如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;DISCOVERY_PERIOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;MONITOR_PERIOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;DELAY_DETECTING_PERIOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="n"&gt;TOSHOW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;281474976710655&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;读者可以通过修改对应的周期数值，来修改对应模块获取信息的周期，其单位为秒。TOSHOW是一个布尔值，用于设置是否在终端打印网络信息。MAX_CAPACITY值为链路最大可用带宽值，可根据实际情况进行修改。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;本文介绍了基于跳数、时延和带宽三种权重类型的最优转发应用，同时，基于带宽的最优转发也是一种简单的网络流量负载均衡应用。以上的代码其实在很久以前就已经写出来了，其是OXP（Open eXchange Protocol）应用的基础，但是由于某些原因，一直无法公开发布。前段时间在博客上发布了时延应用的原理，并没有把代码公布。但后来有若干读者发邮件询问代码，所以就趁着6月份的尾巴，把压在箱底的陈年应用发表出来，希望给大家带来一些帮助。在使用过程中建议读者先仔细阅读本文或README。如果遇到问题，可以通过电子邮件的方式和我沟通，我会很快把BUG修改好，不影响程序的使用体验。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 08 Jul 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-07-08:pages/2016/07/08/ji-yu-tiao-shu-shi-yan-dai-kuan-de-zui-duan-you-lu-jing-he-fu-zai-jun-heng.html</guid><category>shortest_forwarding</category><category>load_balance</category></item><item><title>SDN最新研究进展</title><link>http://www.muzixing.com/pages/2016/06/28/sdnzui-xin-yan-jiu-jin-zhan.html</link><description>&lt;p&gt;自SDN出现以来，关于SDN的研究一直没有停止，只是不同的阶段关于SDN的研究的重点不同。比如最开始的时候，探讨最多的是SDN的可行性，以及如何将SDN应用到对应的网络场景中。本文是笔者在最近阅读2015年至今的若干SDN论文后总结的SDN最新研究进展，希望对读者提供一些帮助。&lt;/p&gt;
&lt;h3&gt;SDN/NFV&lt;/h3&gt;
&lt;p&gt;SDN和NFV都是当下网络界研究的热点，而如何将两者整合部署，也是研究的热点之一。设计SDN/NFV整合部署框架的研究是这个研究方向的主要研究切入点之一，比如参考文献[1]中就提出了一个SDN/NFV的整体架构。框架中的NFV协调器可以和云管理平台配合使用，SDN控制器也支持与云平台结合。由于此类方案是SDN与其他技术/框架的集合，本身没有太多创新性，论文中也仅仅介绍了其实现方案，所以此处不加赘述。&lt;/p&gt;
&lt;p&gt;SDN/NFV结合还可以部署在很多场景，比如WiFi场景。OpenSDWN[2]就是一种软件定义的家庭/企业WiFi架构框架。 将SDN与其他技术结合并应用在特定网络场景是一种主要的研究方向之一。&lt;/p&gt;
&lt;h3&gt;流表优化&lt;/h3&gt;
&lt;p&gt;OpenFlow所支持的细粒度流管理是SDN最大的优势之一，但是细粒度的管理是需要付出代价的。为满足细粒度的管理，则需要更粒度的流表项。但是像OpenFlow协议这种细粒度的管理会带来一定的时延，对于时延敏感的短流业务而言，这个时延带来的影响是不可忽视的，这很可能会抵消了SDN带来的好处。所以如何通过流表来匹配流，从而减少流表项下发次数，是降低时延影响的有利手段。&lt;/p&gt;
&lt;p&gt;此外，当网络流数目过多时，交换机的流表空间就无法满足需求。当流表满时，为了下发新的流表项，就需要将其他活跃的流表项删除，这会让更多的数据包转发给控制器，从而增加了控制器的负担，还也带来了更大的时延，也会发生数据包丢弃现象。对于大象流而言，等待下发流表项的时延并没有太大的影响。但是，对于短流而言，特别是对时间敏感的短流而言，时延的影响就很明显。为了避免这种情况出现，很有必要对流表项进行聚合优化。&lt;/p&gt;
&lt;p&gt;OpenFlow协议支持通过通配符的方式来将数据流进行聚合，从而将多条流聚合成一条流来进行处理，比如交换机可以将目的IP为10.0.3.0/16的数据包都统一处理，发送到端口1，而不是对每一个IP都下发一条流表项。这种通配符的方式大大减少了流表项的数目。但是，通配的方式也存在问题，比如使用通配符会提高编程复杂度。为了降低使用通配流表项的难度，也为了提高性能，ReWiFlow[3]提出了限制型通配符。限制型通配符定义了完整的匹配域排序规则，使得匹配域不能任意搭配，必须按照顺序搭配。低优先级的匹配域需要在高优先级的匹配域被填充使用时才可以被使用。这样的排序限制了匹配域组合的自由度，但是却让管理流表项更容易。由于匹配域是固定顺序的，所以可以通过前缀属性来更简单地管理流表项集合。&lt;/p&gt;
&lt;p&gt;此外，为满足更多的流表项需求，ReWiFlow还支持使用多维度、不同匹配域优先序列的流表项。在实验中，可以通过5组ReWiFlow的规则就可以描述超过1600条的ACL表项。这样的流表空间压缩率是非常可观的。&lt;/p&gt;
&lt;p&gt;关于流表项的优化一直都是SDN/OpenFlow领域研究的热点和重点，读者可以通过ReWiFlow的参考文献顺藤摸瓜进行深入研究。&lt;/p&gt;
&lt;h3&gt;数据分类/流表查找&lt;/h3&gt;
&lt;p&gt;本质上，交换机将数据分类的过程也就是流表查找的过程。目前的OpenFlow支持的匹配域已经超过了40个，所以数据分类是一个漫长的过程。而且随着新技术的出现，这个匹配域将会继续增加。所以如何设计一个更高效、更具有可拓展性的分类算法来解决数据分类过程中的问题是下一阶段SDN领域的研究方向之一。&lt;/p&gt;
&lt;p&gt;数据分类的关键问题在于提升数据查找的速度。面对超过40维度的查找，如果简单的逐维度，顺序匹配，那会带来十分高的时间复杂度。许多网络业务对时延很敏感，这种低效率的做法无法适应网络设备的要求。从算法的角度来讲，通过多次模糊查找，逐渐分类并缩小查找范围，最后再精确查找是一种可行的思路。&lt;/p&gt;
&lt;p&gt;”Many-Field Packet Classification for Software-Defined Networking Switches“[4]论文就提出了一种可拓展的多域数据分类算法，其由选择性位连接的多维度划分来实现数据分类算法（A scalable many-field packet
classification algorithm using multidimensional-cutting via selective bit-concatenation (MC-SBC) for OpenFlow-based SDN switches）。其核心的思路是通过获取多个域的不同比特位，并将其连到一起作为key，然后具体有相同key的流规则放在一个集合中。不同的比特位选取的结果左右不同的样本空间，从而形成多维度的样本空间。在查找时，通过取不同比特位组合的key可以快速地找到样本空间，然后取样本空间的交集即为对应的分类，也就是对应的流表项。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341jw1f55bvh3gohj20ft0hzmyk.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1. 分类器架构图&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;Policies Composition/Consistency&lt;/h3&gt;
&lt;p&gt;网络中存在着许多网络策略，比如ACL和SFC。同时，网络中的策略往往是由不同人群制定的，他们可能是网络的管理员或用户，也可能是虚拟租户网的租户。不同网络使用者的决策是相互独立的，也是动态的，所以很多时候不同的策略之间会产生策略冲突。目前的策略冲突解决方案仅仅实现了运行态的冲突检测，即只有当策略被部署之后，网络在运行时发生故障，性能出现恶化时，安全漏洞等问题才暴露出来。而这只是一种冲突检测，其无法实现冲突的预防，更不能实现策略的编排，解决策略冲突。&lt;/p&gt;
&lt;p&gt;为解决这个问题，PGA（Policy Graph Abstraction）[5]提出了使用图结构来检测来自多个用户之间的策略冲突，并实现冲突解除。PGA支持在策略下发到底层设备之前完成策略冲突检测和冲突解除，且其提供的抽象模型实现了策略与底层网络之间的解耦合，从而降低了用户在制定网络策略时的压力。PGA支持ACL以及SFC等多种策略的冲突检测和协调，其关注点只是部署策略前的检测和协调，并不关注运行态的冲突检测。通过使用大型企业网数据的测试，验证了PGA其可行性，证明了PGA不仅支持大量数据的处理，同时时延表现还很好。&lt;/p&gt;
&lt;p&gt;此外，多控制器在协同工作的时候，还需要对数据进行同步。在没有数据同步的情况下，相互独立的控制器对交换机安装的策略都是没有经过冲突检测的，可能存在竞争和冲突，所以多控制器系统的信息同步非常有必要。交换机上发生策略冲突主要是因为控制器没有办法获取到交换机上的策略状况，无法进行策略冲突检测，所以如果能在交换机上进行策略冲突检测，就可以解决这个问题。相比通过带外方式实现的控制平面的数据同步和策略冲突检测，在交换机上实现冲突检测的办法更简单，消耗的资源更少。&lt;/p&gt;
&lt;p&gt;“In-Band Synchronization for Distributed SDN Control Planes”[6]论文提出了通过带内方式实现的分布式控制平面的同步机制。其核心的思想是使用交换机的部分配置内存来做冲突检测，然后保证所有的事务都是原子操作，从而保障数据的一致性。当多控制器同时并发给交换机写入策略时，很可能带来竞争和冲突，所以很有必要通过加锁来实现策略写入的原子性，从而保障数据读取和修改的一致性。论文中提出了使用部分交换机的内存作为冲突检测所需的内存，用于存储那些等待执行的指令。论文还设计了“compare and set”原语集，支持命令执行的冲突检测等行为。在安装FlowMod等操作时，需要检测是否有策略冲突，若无冲突，则可以安装，否则放弃。控制器也可以通过读取状态原语来获取交换机上的配置信息，以便作出没有冲突的策略。本质上，这是一种在数据平面上保证数据一致性的解决方案。&lt;/p&gt;
&lt;p&gt;但是，就算控制器策略计算正确，多控制器之间操作也没有冲突，也无法保证数据包在数据平面按照控制器制定的策略去处理。目前关注于控制器平面的策略正确性的研究已经很多，他们普遍努力于如何解决策略冲突，但是控制平面的正确策略不能保障数据平面的正确，所以还需要对数据平面进行监控，来保证数据平面的策略一致性。&lt;/p&gt;
&lt;p&gt;VeriDP[7]提出了监控数据平面策略一致性的解决方案。其核心思想十分简单：控制器在计算数据转发路径的时候，将数据包头和转发路径信息映射关系存储起来；在数据平面上，交换机需要对转发的数据打标签，从而记录数据转发的路径；当数据离开网络之前，将数据包头和标签上报给VeriDP服务器；VeriDP服务器可以将报头信息和控制器存储的映射关系进行对比，若匹配成功则说明数据平面的实际表现和策略一致，否则数据平面出现了故障。选择集中式的服务器进行检验是因为单节点的交换机无法感知全局的策略，所以在数据包丢失等情况时，并不知道这是策略指导还是发生了故障，但集中的控制器掌握全局的策略，所以它的信息可以用来进行判断策略一致性。&lt;/p&gt;
&lt;p&gt;当然，除了以上的问题，流表一致性问题也是值得研究的课题。控制器给多个交换机下发新流表时，没有办法做到同时修改，所以必然存在一个时间段，使得有的交换机的流表项已经更新，而其他的交换机还保留了原有的流表项，这就可能造成环路或者丢包的现象。为解决这一问题，“Monitoring Dynamic Modification of Routing Information in OpenFlow Networks”[8]论文提出了一种监控和分析解决方案，可以对路由信息改变时网络的行为进行监控，并对其行为进行系统整合分析，从而进行优化，减少丢包率等现象。&lt;/p&gt;
&lt;h3&gt;安全相关&lt;/h3&gt;
&lt;p&gt;SDN的集中控制给解决网络安全问题提供了很多方便。一直以来，网络安全都是研究的课题，当SDN出现之后，如何利用SDN去更好地解决网络安全问题成为了新的研究课题。此外，SDN本身的安全成为了新的研究课题。比如攻击者可以通过数据包返回的时间来获取到什么样的数据包会上交控制器，进而利用这一信息攻击控制器[9]。&lt;/p&gt;
&lt;h3&gt;Debugging/Trouble Shooting&lt;/h3&gt;
&lt;p&gt;网络与软件不同，其调试和故障排查十分复杂，所以SDN的调试和故障排查一直是研究热点。&lt;/p&gt;
&lt;p&gt;“One Tool to Rule Them All”[10]这篇论文主要提出的是一个轻量级的框架，可以灵活组合现有的故障排查工具来实现复杂而多样的故障排查功能。由于计算机网络的分布和异构，在网络中进行故障排查一直以来都是非常困难的事情。而SDN的到来也带来了更多的问题，不仅需要检查网络的故障，控制器/VNF/交换机等软件的实现是否存在BUG也成为新的需要解决的问题。&lt;/p&gt;
&lt;p&gt;面对这么多的问题需要排查，目前已经有了许多解决方案，比如NICE[11]等。但是这些解决方案都是针对特定的网络问题，无法全面地解决网络故障。然而在解决一个网络故障时，往往需要到多个软件组合才能完成。所以还需要一个整合平台来实现多个工具之间的灵活组合，这就是“One Tool to Rule Them All”论文的主要切入点和贡献。论文中设计了故障排除的图（Trouble Shooting Graph）来给故障排除建模。然后针对故障模型，可以配置对应的故障排除信息，从而通过调用多个工具来实现复杂的网络故障排除。&lt;/p&gt;
&lt;p&gt;在很多网络业务场景中，需要掌握数据包的转发路径信息，从而更好地诊断网络。原有的转发路径跟踪解决方案的思路主要有带外和带内两种。基于带外的解决方案需要消耗大量的流表空间，也产生大量的带外数据，但是带外方式节省了报头的空间，没有对数据包进行额外的修改。基于带内的解决方案则对数据包头进行了修改，从而节省了大量的流表空间，也不会产生带外的开销。极端的带内解决方案是给网络中的链路独立的编号，然后将编号插入到数据包的报头，从而实现数据包转发路径的追踪，但是这样产生了过大的报头开销。&lt;/p&gt;
&lt;p&gt;CherryPick[12]则在现有带内解决方案的基础上进行了改进。由于数据中心网络Fattree拓扑的规律性，可以通过计算关键链路来映射出完整的转发路径，从而节省报头开销。CherryPick的主要贡献是设计了一套算法，从而将报头开销降到最小，其规则如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ToR: 如果ToR收到了Agg发来的数据包，而且数据包的源地址与目的地址都在同一个pod内，则ToR记录连到Agg的入口链路的ID。如果源地址和目的地址都在同一个pod内，而且不经过Agg,也即在一个ToR上，将忽略入端口。其他情况下，均不记录链路。&lt;/li&gt;
&lt;li&gt;Agg: 如果Agg从ToR收到数据包，且数据包的终点在同一个pod内，则入链路被选中，其他情况将不记录链路。（有的时候，数据包会在ToR和Agg中转圈，然后再到达真正的目的地）&lt;/li&gt;
&lt;li&gt;Core: 核心层交换机始终只挑选入链路。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在此算法之下，可以通过记录路径上的关键链路来映射出完整的数据包的转发路径，从而将报头开销降到最小。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="cherrypick" src="http://ww1.sinaimg.cn/mw690/7f593341jw1f55bvhqp32j20nj088jue.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图2.CheeryPick选取关键链路示意图&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;SDN应用到WiFi无线场景， IOT，ADHOC等场景&lt;/h3&gt;
&lt;p&gt;SDN作为一种新的网络模式，目前正在被用于如5G网络，IOT，Ad-Hoc等网络场景，也产出了OpenSDWN等研究成果[2]。将新技术框架放在不同场景的做法是研究中最常见的做法之一，但这和SDN本身的研究并没有太大关系，所以此处不再展开，有兴趣的读者可以自行研究。&lt;/p&gt;
&lt;h3&gt;Scalability&lt;/h3&gt;
&lt;p&gt;SDN的控制平面能力是有限的，当SDN的规模扩展到足够大的时候，就需要对其进行分域治理。而且出于业务场景的要求，许多大的网络的子网络分别使用着不同的网络技术，使用着不同的控制平面，所以就需要实现多控制器之间的合作。多域控制器的协同工作一直是SDN研究领域的一个大方向，但同时也是一个很艰难的方向。&lt;/p&gt;
&lt;p&gt;STRAUSS[13]项目提出了一个解决方案。其设计了一个“控制器的控制器”作为Domain控制器的协调者，从而实现跨域端到端的通信。由于各个域采用的技术不同，所以这些异构的域在相互协同时就需要进行抽象，从而消除具体技术带来的差异性，进而让网络编排控制器统一管理。为实现控制器之间的通信，论文设计了一种COP协议（Control Orchestration Protocol）。&lt;/p&gt;
&lt;p&gt;同样的解决思路还有OXP协议，其协议内容目前还无法公开。OXP实现的多域异构控制器之间的协调工作，提升了SDN的可拓展性。此外，其还提供了多种模式，可适应多种网络场景的具体需求。&lt;/p&gt;
&lt;p&gt;更多的关于SDN可拓展行的研究[14]，读者可以阅读相关调研[15]。&lt;/p&gt;
&lt;h3&gt;Fault Tolerance/Consistency&lt;/h3&gt;
&lt;p&gt;由于SDN是一种集中式的架构，所以单节点的控制器成为了整个网络的中心。当控制器产生故障或者错误时，网络就会瘫痪。为了解决控制器故障给网络带来的故障，分布式控制器等多控制器方案早就已经被提出。相比单控制器而言，多控制器可以保证高可用性(High Availability)，从而使得在某个控制器实例发生故障时，不影响整体网络的运行。另外，为保障业务不终端、不冲突，多控制器之间信息还需要保持一致性，才能实现Fault Tolerance。&lt;/p&gt;
&lt;p&gt;当故障发生时，多控制器之间的信息一致性能为接管的控制器提供正确管理交换机的基础。然而，当前的一致性研究内容还仅仅关于控制器状态信息方面，而没有考虑到交换机的状态信息，这将导致交换机重复执行命令等问题。然而，许多操作并非幂等操作，多次操作将带来更多问题，所以不能忽略命令重新执行的问题。而且由于没有关于交换机状态的记录，交换机也无法回退到一个安全的状态起点，所以简单状态回退也是不可取的。更好的办法是记录接收事件的顺序以及处理信息的顺序及其状态。此外，还需要利用分布式系统保持全局的log信息一致性，才能让交换机在切换控制器时不会重复执行命令。&lt;/p&gt;
&lt;p&gt;因此Jennifer教授团队提出了Ravana[16]，设计了一个拥有两个阶段的协议，用于记录事件接收顺序和事件处理顺序。当事件从交换机上报给主控制器时，主控制器会将这个事件的顺序信息记录下来，然后与从控制器同步。当交换机执行完事件的处理命令时，会返回执行完成信号给主控制器。主控制器从而结束整个事件/事务处理的周期，并将处理完成的状态信息同步给所有的从控制器，从而完成数据同步。通过这种方式，控制器可以收集到事件处理的具体状态，从而使得当控制器发生故障时，其他控制器可以精确地了解到事件处理的状态，从而继续完成事件处理。这种设计不但保障了控制器状态的一致性，也同步了交换机的状态数据，使得无论控制器还是交换机发生故障时，都不会影响到业务的正常进行，从而实现无故障的应用运行。  &lt;/p&gt;
&lt;h3&gt;SDN与大数据&lt;/h3&gt;
&lt;p&gt;SDN与大数据等其他技术的结合也是一个研究方向。当大数据和SDN[17]结合时，SDN可以提高大数据网络的性能，而大数据的数据处理能力也可以给SDN决策提供更好的指导。由于这种研究属于应用范畴，不加赘述。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;在笔者阅读论文的时候，发现目前主要的SDN研究方向有：多控制器协同的可拓展性问题，网络调试和故障排查，策略编排，流表优化等方向。当然SDN与NFV、大数据等其他技术的结合也是一个研究方向。此外，SDN应用在各种网络场景中的研究依然层出不穷。在2015年到2016年这段时间内，还没有更多关于SDN数据平面可编程性的研究成果，其主要原因在与2014年左右的POF和P4已经走在前列，而更多的研究还来不及发表。但笔者坚信，SDN数据平面可编程性以及SDN编程语言等研究将是未来研究的一个大方向。但是这个方向门槛较高，所以研究的人员比其他方向少一些。本文是笔者最近调研成果，希望可以给读者带来一些帮助。&lt;/p&gt;
&lt;p&gt;作者简介：&lt;/p&gt;
&lt;p&gt;李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：http://www.muzixing.com&lt;/p&gt;
&lt;h3&gt;参考文献&lt;/h3&gt;
&lt;p&gt;[1] Muñoz, R., Vilalta, R., Casellas, R., Martinez, R., Szyrkowiec, T., Autenrieth, A., … López, D. (2015). Integrated SDN/NFV Management and Orchestration Architecture for Dynamic Deployment of Virtual SDN Control Instances for Virtual Tenant Networks [Invited]. Journal of Optical Communications and Networking, 7(11), B62. http://doi.org/10.1364/JOCN.7.000B62&lt;/p&gt;
&lt;p&gt;[2] Schulz-Zander, J., Mayer, C., Ciobotaru, B., Schmid, S., &amp;amp; Feldmann, A. (2015). OpenSDWN: Programmatic Control over Home and Enterprise WiFi. Sosr, 16:1–16:12. http://doi.org/10.1145/2774993.2775002&lt;/p&gt;
&lt;p&gt;[3] Shirali-Shahreza, S., &amp;amp; Ganjali, Y. (2015). ReWiFlow. ACM SIGCOMM Computer Communication Review, 45(5), 29–35. http://doi.org/10.1145/2831347.2831352&lt;/p&gt;
&lt;p&gt;[4] Hsieh, C.-L., &amp;amp; Weng, N. (2016). Many-Field Packet Classification for Software-Defined Networking Switches. Proceedings of the 2016 Symposium on Architectures for Networking and Communications Systems - ANCS ’16, 13–24. http://doi.org/10.1145/2881025.2881036&lt;/p&gt;
&lt;p&gt;[5] Prakash, C., Zhang, Y., Lee, J., Turner, Y., Kang, J.-M., Akella, A., … Sharma, P. (2015). PGA: Using Graphs to Express and Automatically Reconcile Network Policies. Proceedings of the 2015 ACM Conference on Special Interest Group on Data Communication - SIGCOMM ’15, 29–42. http://doi.org/10.1145/2785956.2787506&lt;/p&gt;
&lt;p&gt;[6] Schiff, L., Schmid, S., Kuznetsov, P., Argyraki, K., Schmid, S., &amp;amp; Kuznetsov, P. (2016). In-Band Synchronization for Distributed SDN Control Planes. ACM Sigcomm Computer Communication Review, 46(1), 37–43. http://doi.org/10.1145/2875951.2875957&lt;/p&gt;
&lt;p&gt;[7] Zhang, P., Li, H., Hu, C., Hu, L., &amp;amp; Xiong, L. (2016). Stick to the Script: Monitoring The Policy Compliance of SDN Data Plane. Proceedings of the 12th ACM/IEEE Symposium on Architectures for Networking and Communications Systems (ANCS 2016), 81–86. http://doi.org/10.1145/2881025.2881038&lt;/p&gt;
&lt;p&gt;[8] Yamaguchi, S., Nakao, A., Oguchi, M., Goto, A., &amp;amp; Yamamoto, S. (2016). Monitoring Dynamic Modification of Routing Information in OpenFlow Networks. Proceedings of the 10th International Conference on Ubiquitous Information Management and Communication - IMCOM ’16, 1–7. http://doi.org/10.1145/2857546.2857574&lt;/p&gt;
&lt;p&gt;[9] Sonchack, J., Aviv, A. J., &amp;amp; Keller, E. (2016). Timing SDN Control Planes to Infer Network Configurations. Proceedings of the 2016 ACM International Workshop on Security in Software Defined Networks &amp;#38; Network Function Virtualization, 19–22. http://doi.org/10.1145/2876019.2876030&lt;/p&gt;
&lt;p&gt;[10] Pelle, I., Lévai, T., Németh, F., &amp;amp; Gulyás, A. (2015). One tool to rule them all. Proceedings of the 1st ACM SIGCOMM Symposium on Software Defined Networking Research - SOSR ’15, 1–7. http://doi.org/10.1145/2774993.2775014&lt;/p&gt;
&lt;p&gt;[11] M. Canini, D. Venzano, P. Peresini, D. Kostic, J. Rexford, et al. A nice way to test openflow applications. In NSDI, volume 12, pages 127–140, 2012.&lt;/p&gt;
&lt;p&gt;[12] Tammana, P., Agarwal, R., &amp;amp; Lee, M. (2015). CherryPick. Proceedings of the 1st ACM SIGCOMM Symposium on Software Defined Networking Research - SOSR ’15, 1–7. http://doi.org/10.1145/2774993.2775066&lt;/p&gt;
&lt;p&gt;[13] Muñoz, R., Vilalta, R., Casellas, R., &amp;amp; Martínez, R. (2015). SDN orchestration and virtualization of heterogeneous multi-domain and multi-layer transport networks: The STRAUSS approach. 2015 IEEE International Black Sea Conference on Communications and Networking, BlackSeaCom 2015, 142–146. http://doi.org/10.1109/BlackSeaCom.2015.7185103&lt;/p&gt;
&lt;p&gt;[14] Lange, S., Gebert, S., Zinner, T., Tran-Gia, P., Hock, D., Jarschel, M., &amp;amp; Hoffmann, M. (2015). Heuristic Approaches to the Controller Placement Problem in Large Scale SDN Networks. IEEE Transactions on Network and Service Management, 12(1), 4–17. http://doi.org/10.1109/TNSM.2015.2402432&lt;/p&gt;
&lt;p&gt;[15] Blial, O., Mamoun, M. Ben, &amp;amp; Benaini, R. (2016). An Overview on SDN Architectures with Multiple Controllers, 2016.&lt;/p&gt;
&lt;p&gt;[16] Katta, N., Zhang, H., Freedman, M., &amp;amp; Rexford, J. (2015). Ravana. Proceedings of the 1st ACM SIGCOMM Symposium on Software Defined Networking Research - SOSR ’15, 1–12. http://doi.org/10.1145/2774993.2774996&lt;/p&gt;
&lt;p&gt;[17] Cui, L., Yu, F. R., &amp;amp; Yan, Q. (2016). When big data meets software-defined networking: SDN for big data and big data for SDN. IEEE Network, 30(1), 58–65. http://doi.org/10.1109/MNET.2016.7389832&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 28 Jun 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-06-28:pages/2016/06/28/sdnzui-xin-yan-jiu-jin-zhan.html</guid><category>sdn</category></item><item><title>Ryu:网络时延探测应用</title><link>http://www.muzixing.com/pages/2016/05/24/ryuwang-luo-shi-yan-tan-ce-ying-yong.html</link><description>&lt;p&gt;之前，笔者已经发布了网络感知应用和基于跳数的最短路径转发应用。本文将介绍笔者开发的网络时延探测应用。该应用通过LLDP数据包的时延和Echo数据包的时延计算得出链路的时延数据，从而实现网络链路时延的感知。详细原理和实现步骤将在文章中详细介绍。&lt;/p&gt;
&lt;h3&gt;测试原理&lt;/h3&gt;
&lt;p&gt;网络时延探测应用利用了Ryu自带的Switches模块的数据，获取到了LLDP数据发送时的时间戳，然后和收到的时间戳进行相减，得到了LLDP数据包从控制器下发到交换机A，然后从交换机A到交换机B，再上报给控制器的时延T1，示例见图1的蓝色箭头。同理反向的时延T2由绿色的箭头组成。此外，控制器到交换机的往返时延由一个蓝色箭头和一个绿色箭头组成，此部分时延由echo报文测试，分别为Ta，Tb。最后链路的前向后向平均时延T=（T1+T2-Ta-Tb）/2。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="link delay" src="http://ww1.sinaimg.cn/mw690/7f593341jw1f40i7d39ouj20fr09lgm6.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1. 测量链路时延原理图&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;获取LLDP时延&lt;/h3&gt;
&lt;p&gt;获取T1和T2的逻辑一样，均需要使用到Switches模块的数据。计算LLDP时延的处理逻辑如下代码所示。首先从Packet_in中解析LLDP数据包，获得源DPID，源端口。然后根据发送端口的数据获取到portdata中的发送时间戳数据，并用当下的系统时间减去发送时间戳，得到时延，最后将其保存到graph数据中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="nd"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPPacketIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;packet_in_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;src_dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src_port_no&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lldp_parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
            &lt;span class="n"&gt;in_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;in_port&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw_module&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lookup_service_brick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;switches&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw_module&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;src_dpid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;src_port_no&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;port_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw_module&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;
                        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_save_lldp_delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;src_dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                              &lt;span class="n"&gt;lldpdelay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LLDPUnknownFormat&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;获取Echo时延&lt;/h3&gt;
&lt;p&gt;之后，我们还需要测试控制器到交换机之间的echo往返时延。其测量方法是通过在控制器给交换机发送携带有时间戳的echo_request报文，然后解析交换机返回的echo_reply，并用当下时间减去data部分解析的发送时间，获得往返时间差。所以我们需要完成echo_request的定时发送和解析的实现，详细示例代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_measure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_send_echo_request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SLEEP_PERIOD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_send_echo_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapaths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%.6f&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;echo_req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPEchoRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;echo_req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPEchoReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;echo_reply_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;echo_latency&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;latency&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成echo时延的计算之后，将其保存到echo_latency字典中，已备后续计算使用。&lt;/p&gt;
&lt;h3&gt;计算链路时延&lt;/h3&gt;
&lt;p&gt;完成时延数据获取之后，还需要基于这些数据，计算出链路的时延，公式就是T=（T1+T2-Ta-Tb）/2。所以编写计算方法，示例代码如下。其中get_delay方法用于计算对应交换机之间的链路时延，_save_delay_data可以用于计算和存储lldp的时延和链路时延，其功能根据传入参数而定。而calculate_link_delay方法则用于调用计算方法，并将时延结果存储到networkx图数据结构中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_dalay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;fwd_delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;lldpdelay&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;re_delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;lldpdelay&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;src_latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;echo_latency&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;dst_latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;echo_latency&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fwd_delay&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;re_delay&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;src_latency&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;dst_latency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;inf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_save_lldp_delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lldpdelay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;lldpdelay&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldpdelay&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;network_aware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lookup_service_brick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;network_aware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;network_aware&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_link_delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;delay&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                        &lt;span class="k"&gt;continue&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;delay&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_dalay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;network_aware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lookup_service_brick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;network_aware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;network_aware&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;至此关于网络拓扑中链路时延的获取应用开发完成。需要注意的是，本应用需要依赖Ryu的topology/switches.py模块，所以如果单独使用时，需要配套启动switches.py。另外，与前面发表的应用相互结合，此应用中的graph是之前的network_aware模块感知的网络拓扑数据graph。&lt;/p&gt;
&lt;p&gt;时延探测应用运行结果截图如图2所示。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1f3ye9xt1nuj20o90fjgr4.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图2.时延监控应用运行结果&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;网络时延数据是网络重要数据，是许多网络决策的重要依据，所以网络时延数据测量非常重要。本文介绍了如何在Ryu中开发时延探测应用，并粘贴了关键的代码，希望对读者的学习提供一定的帮助。此外，还需要注意两点：（1）此时延探测模块十分初级，并没有精确性方面的考虑，比如需要将其放在核心层实现，在发送的最后时刻才添加时间戳，收到数据包的第一时刻马上解析时间戳等等，所以精确性不足。在Mininet模拟场景下，最开始的几组数据将会异常，但很快就可以恢复正常。（2）此处的拓扑数据均基于两个交换机之间仅有单链路存在的假设。若存在多链路，则数据会被最后获取的链路覆盖。解决这一问题的办法就是采用Neworkx的MultiGraph图结构来存储数据。最后希望本文能给读者带来一定的帮助，完整代码将于6月发布，敬请期待。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 24 May 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-05-24:pages/2016/05/24/ryuwang-luo-shi-yan-tan-ce-ying-yong.html</guid><category>ryu</category><category>delay</category></item><item><title>Ryu:如何在LLDP中添加自定义LLDPDU</title><link>http://www.muzixing.com/pages/2016/05/20/ryuru-he-zai-lldpzhong-tian-jia-zi-ding-yi-lldpdu.html</link><description>&lt;hr /&gt;
&lt;p&gt;在许多实验场景中，都需要使用链路发现协议（LLDP）来发现链路，从而构建网络拓扑。然而LLDP协议不仅仅可以用来发现拓扑，也可以用于时延检测等业务。LLDP通过添加对应的TLV格式的LLDPDU（LLDP数据单元）来携带对应的信息，从而为上层业务提供信息支撑。为实现LLDP数据单元的拓展，本文将以Ryu控制器为例，介绍如何添加自定义的LLDPDU，从而满足多种业务的需求。&lt;/p&gt;
&lt;p&gt;添加自定义LLDPDU其实只需修改ryu/lib/packet/lldp.py即可，但是由于该文件仅定义了LLDP的相关类，如何使用还需要其他文件去调用，所以还需要其他的修改步骤。具体步骤将在文章后续介绍。&lt;/p&gt;
&lt;h3&gt;修改lldp.py文件&lt;/h3&gt;
&lt;p&gt;ryu/lib/packet/lldp.py文件是Ryu控制器中关于LLDP协议数据类的描述，其中定义了如LLDPBasicTLV类等重要的报文类。 以添加发送时间戳的TLV为例，我们需要完成TLV类型号的声明，以及TLV类的定义。&lt;/p&gt;
&lt;p&gt;在文件开头处有关于LLDP TLV类型的声明，所以首先我们需要添加一个新的类型：LLDP_TLV_SEND_TIME，其类型号为11。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="c"&gt;# LLDP TLV type&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_END&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;                        &lt;span class="c"&gt;# End of LLDPDU&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_CHASSIS_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;                 &lt;span class="c"&gt;# Chassis ID&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_PORT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;                    &lt;span class="c"&gt;# Port ID&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_TTL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;                        &lt;span class="c"&gt;# Time To Live&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_PORT_DESCRIPTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;           &lt;span class="c"&gt;# Port Description&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_SYSTEM_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;                &lt;span class="c"&gt;# System Name&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_SYSTEM_DESCRIPTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;         &lt;span class="c"&gt;# System Description&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_SYSTEM_CAPABILITIES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;        &lt;span class="c"&gt;# System Capabilities&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_MANAGEMENT_ADDRESS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;         &lt;span class="c"&gt;# Management Address&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_DOMAIN_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;                  &lt;span class="c"&gt;# Domain id for Open Exchange Protocol&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_VPORT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;                  &lt;span class="c"&gt;# vport_no for Open Exchange Protocol&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_SEND_TIME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;                 &lt;span class="c"&gt;# Time stamp for sending LLDP packet,&lt;/span&gt;
                                            &lt;span class="c"&gt;# using for delay measurement.&lt;/span&gt;
    &lt;span class="n"&gt;LLDP_TLV_ORGANIZATIONALLY_SPECIFIC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;  &lt;span class="c"&gt;# organizationally Specific TLVs&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后设计此类型的LLDPDU格式，其格式仅包含一个长度为8字节的Double类型的时间戳数据。如何完成类的描述，可以参考TTL类，具体代码如下。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="nd"&gt;@lldp.set_tlv_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLDP_TLV_SEND_TIME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TimeStamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLDPBasicTLV&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;_PACK_STR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;!d&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;_PACK_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;calcsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_PACK_STR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;_LEN_MIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_PACK_SIZE&lt;/span&gt;
        &lt;span class="n"&gt;_LEN_MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_PACK_SIZE&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeStamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_PACK_STR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tlv_info&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_PACK_SIZE&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;timestamp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_PACK_SIZE&lt;/span&gt;
                &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_len_valid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typelen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tlv_type&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;LLDP_TLV_TYPE_SHIFT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;!Hd&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typelen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;TimeStamp类中定义了该LLDPDU的格式，初始化函数以及序列化函数。&lt;/p&gt;
&lt;h3&gt;修改switches.py&lt;/h3&gt;
&lt;p&gt;完成LLDPDU的定义之后，还需要在某文件中对其进行初始化构造。如果另外重新编写一个LLDP的构造、发送以及接受解析模块，那么则需要重新写许多代码，所以此处推荐直接修改Ryu/topology/switches.py文件。&lt;/p&gt;
&lt;p&gt;switches.py文件中的LLDPPacket类完成了LLDP数据包的初始化和序列化实现。&lt;/p&gt;
&lt;p&gt;该类的lldp_packet方法可以构造LLDP数据包，并返回序列化之后的数据。在此函数中，我们需要添加timestamp的TLV。&lt;/p&gt;
&lt;p&gt;在lldp_parse方法中，需将获取到的字节流的数据解析为对应的LLDP数据包。由于在发送之前，我们加入了一个timestamp的TLV，所以解析时需要完成这个TLV的解析，并将TimeStamp作为返回值返回。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LLDPPacket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c"&gt;# make a LLDP packet for link discovery.&lt;/span&gt;

        &lt;span class="n"&gt;CHASSIS_ID_PREFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;dpid:&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;CHASSIS_ID_PREFIX_LEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CHASSIS_ID_PREFIX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;CHASSIS_ID_FMT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CHASSIS_ID_PREFIX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;

        &lt;span class="n"&gt;PORT_ID_STR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;!I&amp;#39;&lt;/span&gt;      &lt;span class="c"&gt;# uint32_t&lt;/span&gt;
        &lt;span class="n"&gt;PORT_ID_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

        &lt;span class="n"&gt;DOMAIN_ID_PREFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;domain_id:&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;DOMAIN_ID_PREFIX_LEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DOMAIN_ID_PREFIX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;DOMAIN_ID_FMT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DOMAIN_ID_PREFIX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;

        &lt;span class="n"&gt;VPORT_ID_STR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;!I&amp;#39;&lt;/span&gt;      &lt;span class="c"&gt;# uint32_t&lt;/span&gt;
        &lt;span class="n"&gt;VPORT_ID_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

        &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LLDPUnknownFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RyuException&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%(msg)s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;

        &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lldp_packet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dl_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;vport_no&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_NONE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;pkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LLDP_MAC_NEAREST_BRIDGE&lt;/span&gt;
            &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dl_addr&lt;/span&gt;
            &lt;span class="n"&gt;ethertype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ETH_TYPE_LLDP&lt;/span&gt;
            &lt;span class="n"&gt;eth_pkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ethertype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_protocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eth_pkt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;tlv_chassis_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChassisID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;subtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChassisID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUB_LOCALLY_ASSIGNED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;chassis_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHASSIS_ID_FMT&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;
                &lt;span class="n"&gt;dpid_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

            &lt;span class="n"&gt;tlv_port_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PortID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PortID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUB_PORT_COMPONENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                      &lt;span class="n"&gt;port_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                          &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT_ID_STR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                          &lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

            &lt;span class="n"&gt;tlv_ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TTL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tlv_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimeStamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tlv_end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;End&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="n"&gt;tlvs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tlv_chassis_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tlv_port_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tlv_ttl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tlv_timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tlv_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;lldp_pkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tlvs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_protocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lldp_pkt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;


        &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lldp_parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;pkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;eth_pkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eth_pkt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;

            &lt;span class="n"&gt;lldp_pkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lldp_pkt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LLDPUnknownFormat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="n"&gt;tlv_chassis_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp_pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tlvs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tlv_chassis_id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subtype&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChassisID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUB_LOCALLY_ASSIGNED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LLDPUnknownFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;unknown chassis id subtype &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;tlv_chassis_id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subtype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;chassis_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tlv_chassis_id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chassis_id&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;chassis_id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHASSIS_ID_PREFIX&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LLDPUnknownFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;unknown chassis id format &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;chassis_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;src_dpid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;str_to_dpid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chassis_id&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHASSIS_ID_PREFIX_LEN&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;

            &lt;span class="n"&gt;tlv_port_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp_pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tlvs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tlv_port_id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subtype&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;lldp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PortID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUB_PORT_COMPONENT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LLDPUnknownFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;unknown port id subtype &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;tlv_port_id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subtype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;port_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tlv_port_id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_id&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT_ID_SIZE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LLDPUnknownFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;unknown port id &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;port_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src_port_no&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT_ID_STR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;tlv_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lldp_pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tlvs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tlv_timestamp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;src_dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src_port_no&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;到此为止，完成了LLDP的构造和解析的定义。但是由于修改了构造函数的参数列表，和解析函数的返回值，所以在构造LLDP数据包和解析LLDP数据包时，均需要做一些改动。示例代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_port_added&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;lldp_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lldp_packet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                           &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hw_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEFAULT_TTL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;div class="highlight"&gt;&lt;pre&gt;        &lt;span class="nd"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPPacketIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;packet_in_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link_discovery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;

            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;src_dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src_port_no&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lldp_parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;LLDPPacket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LLDPUnknownFormat&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c"&gt;# This handler can receive all the packtes which can be&lt;/span&gt;
                &lt;span class="c"&gt;# not-LLDP packet. Ignore it silently&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;此处需要提醒读者的是，在Ryu的Switches模块中，被发送的LLDP都是一次构造之后保存起来，发送时直接发送的，所以添加的时间戳会固定在第一次构造时的时间。所以如果希望正确地插入发送时间戳，还需要进行额外的逻辑修改。但是这也许就破坏了Ryu设计的完整性，所以如何操作还需要读者自行斟酌。&lt;/p&gt;
&lt;p&gt;然而，像VPort_ID之类的不随时间而改变的TLV，则可以直接使用。添加VPort_ID的步骤和以上的例子同理，其VPort_ID类的示例代码如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="nd"&gt;@lldp.set_tlv_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLDP_TLV_VPORT_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VPortID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLDPBasicTLV&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;_PACK_STR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;!B&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;_PACK_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;calcsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_PACK_STR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# subtype id(1 octet) + port id length(1 - 255 octet)&lt;/span&gt;
        &lt;span class="n"&gt;_LEN_MIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;_LEN_MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;

        &lt;span class="c"&gt;# VPort ID subtype&lt;/span&gt;
        &lt;span class="n"&gt;SUB_INTERFACE_ALIAS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;     &lt;span class="c"&gt;# ifAlias (IETF RFC 2863)&lt;/span&gt;
        &lt;span class="n"&gt;SUB_PORT_COMPONENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;      &lt;span class="c"&gt;# entPhysicalAlias (IETF RFC 4133)&lt;/span&gt;
        &lt;span class="n"&gt;SUB_MAC_ADDRESS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;         &lt;span class="c"&gt;# MAC address (IEEE Std 802)&lt;/span&gt;
        &lt;span class="n"&gt;SUB_NETWORK_ADDRESS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;     &lt;span class="c"&gt;# networkAddress&lt;/span&gt;
        &lt;span class="n"&gt;SUB_INTERFACE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;      &lt;span class="c"&gt;# ifName (IETF RFC 2863)&lt;/span&gt;
        &lt;span class="n"&gt;SUB_AGENT_CIRCUIT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;    &lt;span class="c"&gt;# agent circuit ID(IETF RFC 3046)&lt;/span&gt;
        &lt;span class="n"&gt;SUB_LOCALLY_ASSIGNED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;    &lt;span class="c"&gt;# local&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VPortID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_PACK_STR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tlv_info&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_PACK_SIZE&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vport_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tlv_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_PACK_SIZE&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subtype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;subtype&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vport_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;vport_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_PACK_SIZE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vport_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_len_valid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typelen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tlv_type&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;LLDP_TLV_TYPE_SHIFT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;!HB&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typelen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subtype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vport_id&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;LLDP协议可添加自定义TLV格式的特性，使其可以灵活地被修改，进而应用到不同的业务场景中，十分方便。本文就以Ryu控制器为例，介绍了如何添加自定义LLDPDU的详细流程，希望对读者有一定的帮助。此外，为计算时延，还可以通过switches模块中的PortDatak类的发送时间戳来实现，无需修改LLDP数据包格式。如何在Ryu中完成时延测试的内容将在下一篇文章中详细介绍，敬请关注。&lt;/p&gt;
&lt;h3&gt;作者简介&lt;/h3&gt;
&lt;p&gt;李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：http://www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 20 May 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-05-20:pages/2016/05/20/ryuru-he-zai-lldpzhong-tian-jia-zi-ding-yi-lldpdu.html</guid><category>sdn</category></item><item><title>我是一个SDN交换机</title><link>http://www.muzixing.com/pages/2016/05/03/wo-shi-ge-sdnjiao-huan-ji.html</link><description>&lt;p&gt;我叫阿飞，是大柳树村的快递小哥。阿飞是我的外号，因为我送货很快。&lt;/p&gt;
&lt;p&gt;我做着普通的工作，拿着普通的工资，买不起房子，一直单身。但我知道，只要努力，就能出人头地。在因特奈特国，识字的人并不是很多，幸亏我还读过小学，才能成为一名光荣的快递员。很多时候，大家更喜欢叫我交换机，因为我每天都像机器一样机械地交换着包裹，日复一日，年复一年。不过很多快递员也和我一样机械地交换包裹，但我知道：我和普通快递员不一样。&lt;/p&gt;
&lt;p&gt;老一辈的快递员学的东西很多，包括传统的OSPF和IS-IS等语言。但是随着经济的发展，新业务不断诞生，对物流系统的挑战也越来越大，前辈们也开始应接不暇。为了应付这种挑战，物流系统的深度改革终于展开了。新生代的我们只需要学会OpenFlow语言基本就可以找到工作。学习压力是减轻不少，但是我们却需要快递主管来指挥物流的转发，才能更好的工作。&lt;/p&gt;
&lt;p&gt;还记得我当快递员的第一天，那是6月19号，星期五，阳光明媚，室外温度28摄氏度。上班路上，空气中竟有种淡淡的清香，像极了我在华为学院读书时女同桌阿楚的发香。她学习不太好，只学会了二层转发的知识，毕业之后就杳无音信了。要是能再见一面就好了，就算见不到，写写信也挺好的。&lt;/p&gt;
&lt;p&gt;第一次推开办公室的木门，指尖触到还未干透的露水，还有朝阳的温度。隐隐约约，还能闻到橡树的芳香。一切都是新的，房子是新的，快递窗口是新的，快递单是新的，工作手册是新的，我是新的，生活，也是新的。&lt;/p&gt;
&lt;p&gt;走进房间之后，我拿起桌子上的工作手册，发现里面记录着快递主管的相关信息。原来我的快递主管是Ryu族人，在城里114.255.40大街2号办公大楼的6633房间工作。工作的第一件事情就是给主管发了一封hello信，告诉主管我学会的OpenFlow语言级别。我和主管通信的信件和包裹都是重要信息，所以一般需要由专门的快递员转发，但有时候也可以作为普通信件对待。&lt;/p&gt;
&lt;p&gt;一转眼的功夫，主管就给我回复了一封Hello信。就这样，我们就约好了使用1.0版本的OpenFlow语言通信。没等我读完，又收到控制网络快递员铁柱大哥给我送来的信件。主管在信里让我发简历给他，好给我配置工作内容。&lt;/p&gt;
&lt;p&gt;我赶紧从我的书包中拿出修改了250遍的简历放在features_reply信封中，然后发给了主管。我想：第一天上班，一定要好好表现，以后才能升职加薪，迎娶白富美，走上机生巅峰。脑海里不禁浮现我成为机生赢家的画面：那是一片充满生机的草地，我拉着美丽新娘的手，肉肉的，也暖暖的，但我却看不见她的脸。我慢慢靠近她，企图看清她的脸，似乎有些熟悉，又有些神秘。就在我马上要看清的时候，一阵敲门声把我从幻想中拉了回来。又是主管来的信。
这次是配置信。我按照配置信的内容配置完我的办公室之后，满意地坐在桌子前，傻笑着准备继续幻想。&lt;/p&gt;
&lt;p&gt;谁知第一窗口马上就传进来一件快递，我迫不及待地查看了起来：是10.0.0.8发给10.0.0.28的快递。我翻开快递转发本子，却发现转发本子上空空荡荡，正如当时我的脑海一样，一片空白。&lt;/p&gt;
&lt;p&gt;“怎么办？第一件快递就不会处理，太丢人了！怎么办！怎么办！”我着急地一直跺脚。突然我醒悟过来OpenFlow语言的规范里面提到过：如果遇到不知道怎么处理的快递就给快递主管发Packet_in信，附带上快递包裹。&lt;/p&gt;
&lt;p&gt;“怎么这么笨！”，把Packet_in信和包裹送出去之后，我轻轻地抽着嘴巴自责。说时迟那时快，转眼间，快递主管的包裹又到了。那是一个Packet_out包裹，让我赶忙把数据包给进货窗口以外的所有发货窗口都发一份。虽然不知道为什么，但是我还是照做了。&lt;/p&gt;
&lt;p&gt;很快的，我又收到了10.0.0.8发给10.0.0.28的另一件快递。因为上次没在记录怎么处理这类型的包裹，所以我只能再一次请快递主管帮忙了。眨眼的功夫，主管就给我回复了一个Flow_mod信，信里提到把10.0.0.8发给10.0.0.28的快递都统一送到3窗口。之后我的工作就简单了很多，不用再询问主管怎么处理这类包裹。&lt;/p&gt;
&lt;p&gt;初来乍到，几乎所有快递都需要主管指导才能完成转发，所以我也忙得不可开交，分身乏术。幸运的是，我很快就记录了那些快递包裹的处理动作。所以只要不是新的包裹，我都可以自己处理。&lt;/p&gt;
&lt;p&gt;还记得第一天下班的晚上，忙碌了一天的我又激动又难过。激动是因为我终于当上了一名光荣的快递员。在大柳树村，我可是学历最高的人，那些寄信的小姑娘都会对我笑，大妈们也会询问我有没有对象。难过是因为我几乎什么都要请教主管，自己什么都不会。&lt;/p&gt;
&lt;p&gt;时间如白驹过隙，转眼间，我已经成为一个老司机。我学会了很多快递处理的规则，基本上都不需要请快递主管帮忙了。时光就这样静静地流淌，从我忙碌的指缝中穿过，流过堆积如山的包裹，一去不返。&lt;/p&gt;
&lt;p&gt;在没有新货物要处理的时候，我每一天都在机械地把货物从这个窗口收进来，发到另一个窗口。偶尔转发规则过了有效时间，我就把它删了，重新请教主管大人。有时遇见了新的快递，我也会喜出望外，因为我可以和主管写信沟通，哪怕是工作上的事。有个人搭搭话，总比一个人孤独工作舒服一些。虽然经常会忙得忘记时间，但偶尔闲下来，也会觉得一个人有些寂（jí）寞。&lt;/p&gt;
&lt;p&gt;除了寂寞以外，主管待人处事的温润如玉也是我喜欢和他写信的原因。他回信很快，而且每次看主管发来的信总有种莫名的熟悉，总感觉好像是阿楚写的，无论是字迹，还是语气。不知道阿楚现在过得怎么样，只会二层算法的她是不是找不到工作，还单身吗。&lt;/p&gt;
&lt;p&gt;忙碌的生活就像墙上简陋的日历，除了日期不一样，其它好像都差不多。生活就这么不断地重复着，直到有一天......&lt;/p&gt;
&lt;p&gt;那是一个星期五，印象中那天我最后一次看墙上的钟是下午17点47分，就快就下班了。屋外乌云密布，电闪雷鸣，眼看着暴风雨就要来了。当最后一丝日光终于被黑云吞噬，屋外开始狂风大作，雷雨交加。狂风像愤怒的狮子一般呼啸着冲向我的办公室，而那些如弹珠般的雨滴就像狮子的攻击一样，疯狂地敲击着我的玻璃窗，似乎想要冲进来摧毁一切。&lt;/p&gt;
&lt;p&gt;忙碌的我可管不了太多，我依然认真地转发着快递。但就在这时，我发现有一个送往33:33:00:00:00:01地址的包裹不断从3窗口进来。按照转发手册的处理规则，我把它发往第5窗口。但转眼间，它又回来了，我只能再一次把它转发出去。我逐渐意识到它在不断重复出现，而且我发得越快，它回来得就越快，就像我在和一面墙在打排球一样。我不断往返与3窗口和5窗口之间，已经无暇顾及其它的快递。堆积在窗外的包裹被雨水打湿了，开始漂浮起来，被冲走了。渐渐的，我发现我开始上气不接下气。我突然意识到，如果继续这样不断转发下去的话，我一定会倒下的。但是我不能停止，转发快递是快递员的职责，是快递员的使命！&lt;/p&gt;
&lt;p&gt;我依然坚持工作，纵使步履开始缓慢，呼吸也渐渐变得急促。我觉得有点晕，感觉整个房间也开始旋转，跳跃。我闭着眼，就像进入了一个奇幻的梦境。我觉得我开始飘了起来，昏昏欲睡的双眼看见椅子也飘了起来，桌子也飘了起来，还有那些转发本子和笔，都飘了起来。屋外还是狂风大作，狂风夹裹着沉重的雨点疯狂地敲击着玻璃窗，砸出无数的水花，让我看不清窗外的景象。突然，一声炸雷，把我从梦境之中拽出来。透过窗户，隐约中我只能看见窗外的树枝被劈断，断裂处开始着火。但很快，火就被雨水无情地浇灭了。&lt;/p&gt;
&lt;p&gt;我还在转发那个从3端口进来的包裹，不知道为什么它到达的速度越来越快，快到我还没有发送它，另一个它又进来了。往返于3窗口和5窗口之间的我，脚底越来越轻，脑海里闪过许多儿时的画面：最后一次尿床、亲隔壁小红的脸、偷老爸的那根香烟......&lt;/p&gt;
&lt;p&gt;我突然好像失聪了似的，听不到狂风的呼啸，也听不见雨水攻击窗户的声音，世界突然变得很安静，只剩下呼吸和心跳的声音，每一次都和我的脚步一样沉重。不知为何，脑海中闪现出阿楚的模样，还有她的发香。&lt;/p&gt;
&lt;p&gt;“我不能倒下！” 我暗示自己，我知道这疯狂出现的包裹肯定有问题，肯定有问题！&lt;/p&gt;
&lt;p&gt;“我还没有女朋友，我一直努力工作，我不能就这么简单的走了！”我一手扶着墙支撑着自己的身体，一手颤抖着托着快递，挣扎着把它推到第5窗口。&lt;/p&gt;
&lt;p&gt;就在包裹马上要被送到窗口时，我滑倒了，身体重重地砸到地板上。但我已经听不到倒地的声音，只觉得房子里的光线又暗了一度，让我觉得有点困。我挣扎着在地板上蠕动，努力把货物推向第5出货口。我使尽了最后一丝力气，把快递顶了出去。就在这时，一阵强光伴随着一声巨响，我又被震到了地上。&lt;/p&gt;
&lt;p&gt;我尝试站起来，但是四肢已经没有了感觉。寒风一次一次从我的脸上划过，带走仅剩的一丝温度。我感觉好冷，好冷！又是一次闪电，劈在很近的地方，我失去了知觉。&lt;/p&gt;
&lt;p&gt;那是一个幽暗的森林，没有路，没有风，没有闪电，只有安静伫立着的树，也没有声音。茂密的树叶相互遮挡着，看不到一丝天空，幽暗中，我看见不远处的草丛里有一头美丽的鹿。身上的花纹和母亲最喜欢的衣裳花纹一样。它看着我，眼里都是温柔，就像母亲看我时的模样。我试图靠近，鹿却向森林深处走去，时不时还回头看我，好像在召唤我一样。我一步步靠近，却感觉不到青草的柔软，感觉不到树叶刮到手臂的疼痛，感受不到一丝痛苦。&lt;/p&gt;
&lt;p&gt;突然一阵电流把我从梦境中惊醒！我以为我很痛，但是我没有。我还是那个我，充满活力，我被重启了。&lt;/p&gt;
&lt;p&gt;暴风雨过去了。透过干净透亮的窗口，可以看到温暖的阳光洒在充满生机的大地上，一切都和以前一样，只是那个被雷劈断的树枝显得格外的刺眼。&lt;/p&gt;
&lt;p&gt;我重新开始我的工作，联系我的快递主管Ryu大人，商量通信的语言版本，这次用的是OpenFlow1.3版本的语言。Ryu主管不仅给我发了配置信，还给我发了一个miss-table的处理规则，告诉我把匹配失败的数据包交给他。&lt;/p&gt;
&lt;p&gt;使用OpenFlow1.3语言时，我需要使用三种类型的规则小本子，分别叫Flow Table, Group Table和Meter Table。以前我的Flow Table册子就只有一本，所有货物只要查一次就可以完成处理了。但现在不一样，现在我需要查多本Flow Table的本子，才能完成一个包裹的处理。我这里目前只有2本，听说最多可以支持255本。分成多种本子是因为这样可以做聚类，节省规则数目。Group Table本子里记录着很多的处理动作集合，大约有select, all, indirect和fast failover四种。Select类型的组表能做负载均衡，all可以做组播indirect可以做聚合，而fast failover能做容灾备份。Meter Table用于计量，虽然有这个规则本子，但是一半都不用，因为太麻烦了。&lt;/p&gt;
&lt;p&gt;除了以上的差别以外，重启之后的我和之前并没有太大区别，每天都在办公室里忙着转发快递，忙着忙着也快忘记了那个黑色星期五发生的事情。后来听说那天是大风暴，好多个同事都和我一样疯狂地在转发一个数据包，到最后竟活活累死了7个快递小哥，惨绝人寰！还好我身体好才幸免于难。原因竟然只是因为一个新人把送货渠道连成了环路，然后把不知如何处理的数据包给泛洪了，结果就产生了包裹风暴！因为这起事故，主管办公室还换掉了一些员工。&lt;/p&gt;
&lt;p&gt;风暴之后的工作和往常差不多，只不过主管大人每个周都会询问我们的业务状况，包括每个端口收发货物的详情，还包括客户之间的快递转发详情。听说收集这个是为了让我们压力均衡一些，不至于出现累死员工的事故。一切好像都比之前要好了，但写信的人好像换了，我不太喜欢他，不论是笔迹，还是语气。没有了当初那种青涩的感觉，多了一些严谨，多了一些犀利，听说写信的是个美丽的姑娘。&lt;/p&gt;
&lt;p&gt;自从换了人之后，我再也没有收到要把包裹发送给所有窗口的要求了，每一次都是直接发送到指定窗口。其他的快递小哥都喜欢这个新来的人，把她当梦中情人，但我没有。我怀念之前的信，无论是字迹，还是语气，因为很像阿楚写的。但世界这么大，哪有这么巧的事情，是我自作多情罢了。&lt;/p&gt;
&lt;p&gt;“她还好吗？”每个寂寞的夜晚，业务不忙的时候，我总会想起她，想象着她路过我的窗，正如当年读书的模样。但我并没有遇见她，我遇见的只是跳广场舞的大妈，还有那些艳俗的姑娘，她们只是找我取快递而已。&lt;/p&gt;
&lt;p&gt;我做着普通的工作，拿着普通的工资，买不起房子，一直单身， 我坚信，只要努力，就能出人头地。但风暴之后的我面对那些转发规则信，却再也找不到那种当初的悸动。我觉得我失去了工作的热情，我只是在工作而已，麻木而机械地工作而已。&lt;/p&gt;
&lt;p&gt;终于有一天，我却再也收不到主管给我的回信了。我不断地请求主管，但发出去的信却一封封石沉大海。听控制网络的铁柱说，主管的房间里面没人了。&lt;/p&gt;
&lt;p&gt;无奈之下，我只能按照工作手册的指导，切换到了Standalone模式。在这个模式下，我再也不需要主管控制，我可以用二层MAC自学习算法来完成我的工作。二层算法是和阿楚同桌的时候学的，当时我教了她24遍她才会，但就算教会了，第二天她还是过来问我这个算法，好像永远学不会一样。但我知道，她只是假装不会，而我只是尽力在表演 。&lt;/p&gt;
&lt;p&gt;生活翻开了新的篇章，相比之前的工作，工作简单多了，也无聊多了。再也没有人和我聊天，写信也没有。每个周我都让铁柱转发给Ryu主管一封信，但是始终有去无回，至今已经18年了。&lt;/p&gt;
&lt;p&gt;我做着普通的工作，拿着普通的工资，买不起房子，一直单身。我还惦记着那个叫阿楚的姑娘，不知道现在她是什么模样，是否还有那种发香。&lt;/p&gt;
&lt;h3&gt;作者简介：&lt;/h3&gt;
&lt;p&gt;李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：http://www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 03 May 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-05-03:pages/2016/05/03/wo-shi-ge-sdnjiao-huan-ji.html</guid><category>SDN</category></item><item><title>我是一个SDN控制器</title><link>http://www.muzixing.com/pages/2016/04/18/wo-shi-ge-sdnkong-zhi-qi.html</link><description>&lt;p&gt;“醒醒！”朦胧中有一个人叫醒了我。&lt;/p&gt;
&lt;p&gt;“跟我走”，那个身穿Linux制服，胖得像企鹅一样的大叔拉着我就走。&lt;/p&gt;
&lt;p&gt;“你谁啊？去哪里？”， 我惊恐的问，完全不知道到底发生了什么。&lt;/p&gt;
&lt;p&gt;“我是操作系统，负责给你安排工作。你是一个SDN控制器，是Ryu族人，就给你分配代号9527吧。”，那大叔显得有些不耐烦地回答。&lt;/p&gt;
&lt;p&gt;“看到没有，前面办公楼里的6633房间就是你的办公室，你的工作就是处理信件和包裹，门房的卡大爷负责收发信件，你记得找他取信就可以了，过期他会丢掉的”。大叔边走边说，一转眼已经到了门口。门房果然有一个大爷，正在忙着处理堆积如山的包裹，胸口的工作证沾了好多灰尘，不过隐隐约约还是可以辨出“网卡”两个字。&lt;/p&gt;
&lt;p&gt;但我依然不知道我要具体做什么，所以忍不住又问：“操作系统大哥，我来这里干什么啊？”&lt;/p&gt;
&lt;p&gt;“你这么叫不累？叫我Linux就好了。你是新来的员工，要做什么可以看你胸前的说明书”。&lt;/p&gt;
&lt;p&gt;我低头一看，我的天啊！我贴着这么大的说明书和路过的5个美女打了招呼，她们还对我笑了。我拿下说明书，发现上面赫然写着“README”，怪不得刚才有个小孩一直跟着我，还碎碎念着什么SDN，我还以为他只是脑子发育有些迟缓。羞愧之余，我慢慢往下读。&lt;/p&gt;
&lt;p&gt;原来我被任命为因特奈特国金银岛的快递主管。因特奈特国很贫穷，民众普遍文化水平都不高，识字的人并不多。为了实现远距离的通信和物流，快递业务急需文化水平高的员工。所以快递员们都是从培训机构里面毕业出来的，都是读书人。&lt;/p&gt;
&lt;p&gt;培训机构的培训项目五花八门，有数据链路层语言和网络层语言等多种项目。但是学习语言需要天赋，有的人智商高，CPU更强大，能理解和运用三层甚至更高层级语言的语法， &lt;/p&gt;
&lt;p&gt;能找到更好的工作，一般都在关键物流节点上工作。而那些只会普通二层语言的快递员，也就勉勉强强能在村里当一个邮递员，业务能力差强人意。&lt;/p&gt;
&lt;p&gt;培训学院课程特色十分鲜明，有时不同机构对同一件货物的处理流程截然不同，所以不同机构的快递员之间很难合作。为了和其他学院毕业生合作，学生要学好几套技能，所以学费也相应增加了。但掌握多项技能的毕业生，可以找到很好的工作。但对于快递公司而言，人力成本就水涨船高了。快递公司希望所有培训机构的课程都一样，或者他们能快速接受入职培训重新学习，这样就可以节省很多成本了。&lt;/p&gt;
&lt;p&gt;在工作中，快递员学员们都各自为战，并不清楚整体的物流情况。所以就有可能出现这样的情况：发货地点和收货地点之间有多条物流通道，但是物流都拥挤在一条通道上，处理不过来的包裹不断被丢弃，但有的通道却门可罗雀，快递员在岗位上打盹，导致整体资源的利用率很低。而且随着因特奈特国推行改革开放，经济快速发展，信息和物资开始大量流通，也对物流系统提出了更高的要求。&lt;/p&gt;
&lt;p&gt;后来，遥远的西方传来了“深度改革”的呼声，他们对快递公司进行了改革，聘请了一个特别聪明的人担任快递业务主管来统一管理物流业务。而快递员的学习标准也都统一了，他们不需要学习多种语言，只需要识字，能按照工作手册转发货物就行。 遇到不懂处理的货物时，快递员们只需要按照语法书的规则把问题提交给快递主管。快递主管就会利用他聪明才智指导快递员处理包裹，给快递员一条转发类似货物的指令，这样快递员就可以查手册直接处理类似的货物，而不必再问主管。西方的快递主管都是牛仔，很忙的。&lt;/p&gt;
&lt;p&gt;再后来，改革的春风吹到了因特奈特国，所以我就成了因特奈特国金银岛的第一任快递主管。&lt;/p&gt;
&lt;p&gt;“你不识字？读这么久？” Linux一脸鄙视地看了我一眼。&lt;/p&gt;
&lt;p&gt;“赶紧开始工作，不然我就把房间没收了，送你去垃圾场处理掉！”Linux突然面露杀气， 吓得我三步并作两步跑进了6633房间，关上房门。&lt;/p&gt;
&lt;p&gt;还没等我观察房间内部的摆设，门被敲开了，进来了几个穿着工服的人。&lt;/p&gt;
&lt;p&gt;“领导好！我们是帮你完成工作的协程”那个大众脸的人，一脸憨厚地开始自我介绍，“我是帮您取快递的小曲，她是帮您处理二层包裹的阿楚，他是帮您检查包裹安全的大健。”&lt;/p&gt;
&lt;p&gt;我定睛一看，小曲还好，长相正常，3分吧。阿楚倒是还挺可爱的，但拿着盾和大宝剑的大健实在让气氛有些尴尬。&lt;/p&gt;
&lt;p&gt;“那开始干活吧。”我假装经常当领导的样子，不动声色地抛下一句，然后拿起桌子上的工作手册独自读了起来，深藏功与名。&lt;/p&gt;
&lt;p&gt;小曲的工作比较简单，只是不断地检查房门口有没有包裹。突然，他兴高采烈地抱进来一堆信件，放在我桌子上之后像发现新大陆一样兴奋地说：“还有其他信，您等着。”&lt;/p&gt;
&lt;p&gt;打开信件一看才发现，原来都是一些来自快递员们的hello信件，看来他们开始工作了。Hello信的内容很简单，无非就是和我商量一些要采用那个版本的语法进行通信。我给他们发了Hello回信，然后再写了一封要求他们发简历的Feature_request信。作为领导，了解员工能力是很有必要的。&lt;/p&gt;
&lt;p&gt;很快，小曲又抱着一堆新的信件进来了。这次的信有点厚，打开才发现是快递员们的Features_reply，这些信里面有他们的简历，可以知道他们都会些什么技能。我查了一下工作手册，并没有什么要特殊设置的，就按照标准的流程，给他们回复了标准的配置信。&lt;/p&gt;
&lt;p&gt;一转眼，小曲又大汗淋淋地扛着一个大包裹进来了。我忙不迭地打开查看，这次是一个Packet_in包裹。“阿楚，赶紧处理一下”。我冲一直在边上无聊抠脚的阿楚喊。&lt;/p&gt;
&lt;p&gt;阿楚驾轻就熟地把包裹打开，把上面的信息记录到小本子上，比如包裹是哪个快递员送过来，从他的哪一个快递窗口进来的，还有一些包裹里的具体内容。阿楚也是上过小学的人，在培训学校里学过二层语言。她是这里唯一的实习生。&lt;/p&gt;
&lt;p&gt;“我不知道这个怎么处理，没有见过这种包裹，在我的小本本上没有记录，就让他给所有出口都发一份吧。”阿楚面露难色地告诉我。我最开始是拒绝的，但又只能无奈接受。“那就这样吧。” &lt;/p&gt;
&lt;p&gt;很快的，其他快递员也把这个包裹的处理请求上报给我了，但阿楚依然不知道怎么办，只能继续泛洪发送。&lt;/p&gt;
&lt;p&gt;可喜的是，阿楚的小本子上面很快就记录了很多记录。我仔细一看，小姑娘还挺聪明，还学会数据结构了。她画了个表格，每条数据项有三列数据：快递员的工作证号：dpid，从哪一个快递窗口送到快递员手里的和包裹的主人地址。&lt;/p&gt;
&lt;p&gt;“这个包裹我知道怎么处理耶！”阿楚兴奋地跳了起来，面色潮红。根据之前的记录，阿楚知道寄给这个“66：66：66：66：66：66”的包裹是应该要从一号快递员的快递窗口3发送出去的。她赶忙写了一封Flow_mod挂号信，信里告诉快递员关于这个特别6的客户的包裹都往3端口发。&lt;/p&gt;
&lt;p&gt;“啊，糟了！我忘记给他发一个Packet_out信了！Packet_in消息里有提到buffer_id是NO_BUFFER的。”阿楚还没有坐稳就惊呼了一句。她赶紧写了一封Packet_out信，里面提到了要把Packet_out中的包裹发到3端口，然后把信贴到包裹上，交给了小曲。&lt;/p&gt;
&lt;p&gt;工作就这么有条不紊地进行着，大家都低头忙着自己的事情。仿佛时间并没有流动，只是在不断地重复播放，没有什么波澜。每次包裹到的时候，大健也会机械地抬头看一眼是不是给自己的。他总是恶狠狠地盯着盾牌上记录的坏人名字和处理规则，咬牙切齿的样子让气氛格外尴尬。无聊地时候，大健也喜欢在空中比划着什么。听阿楚提起过，大健好像是情意绵绵剑的传人，只是一直加班，没时间找女朋友，所以一直找不到搭档练剑。&lt;/p&gt;
&lt;p&gt;“终于等到你！还好我没放弃！”大健两眼放光地盯着手中的信件。原来大健收到了程序员上帝写给他的一封规则信，信里提到要把IP是192.168.8.24的包裹全部丢掉。大健面露杀气地举起手中的大宝剑，在盾上深深地刻下了这行规则。然后他立刻写了几封Flow_mod信，把这个丢包规则发送给那些相关的快递员。作为一名安检员，大健始终保持着警惕，尽职尽责地保护着金银岛的物流安全。&lt;/p&gt;
&lt;p&gt;工作的日子总是单调的，像一次函数那样单调而笔直地前行着。大家都机械地处理着手上的业务。阿楚还是那么萌，大健还是疾恶如仇，而小曲还是像流行歌曲的高潮部分那样，不断地周期往返着。&lt;/p&gt;
&lt;p&gt;平静而平凡的生活终于被打破，犹如平静的贝加尔湖面丢进了一个石头。原因是新来的快递员的传递路线和其他快递员的传递路线形成了环路。&lt;/p&gt;
&lt;p&gt;那一天，乌云密布，雷雨交加。快递员收到了一个新用户的包裹，他查半天规则手册都不知道怎么处理这个新用户的包裹，只能请求我。我让阿楚处理，结果她按照自学习那一套，让大家泛洪发送，结果就产生了广播风暴。&lt;/p&gt;
&lt;p&gt;那是黑暗的一天，我记得是星期五，我目睹了5起交通事故和3次情侣吵架，但都没有广播风暴带来的结果严重。所有环路上的快递员都不断转发着那个货物，最后竟活活累死了！在快递行业中，丢个包已经是工作事故，而累死多名员工的事，已经不能算事故，它是灾难！&lt;/p&gt;
&lt;p&gt;因为这件事，差一点让我们快递部门倒闭了。还好问题发现得及时，切断了快递业务路线。处理完后事之后，公司开始追究责任。可怜的阿楚，就这么被开除了。到离开她都不知道为什么会把快递员活活累死，毕竟她只上过小学，只知道自学习转发，并不了解这个做法在环路中可能产生致命的环路风暴。&lt;/p&gt;
&lt;p&gt;阿楚离开后的第二天，快递系统还没有恢复运作，办公室堆积着好多事没人处理，我并没有打算处理它们，只想放空自己，从噩梦中走出来。
突然Linux敲开了我的房门，还带着一个漂亮的姑娘。&lt;/p&gt;
&lt;p&gt;“9527，程序员托我给你带新人来了”。程序员上帝发现这个惨案之后，很快让操作系统把这个新员工安排过来。&lt;/p&gt;
&lt;p&gt;“谢谢Linux。那个，你自我介绍一下吧。”“谢过操作系统大哥之后，我转头问这个很有御姐范儿的姑娘。&lt;/p&gt;
&lt;p&gt;“Ryu领导好，我叫露露，我读过本科，专业是大数据处理，后来去思科学院学习了快递技术。我会收集快递员的连接信息，然后做数据分析，可以计算出最短路径来转发或者路由快递包裹，绝对不会累死人！”露露语速很快，很自信，是我喜欢的类型。&lt;/p&gt;
&lt;p&gt;“啊，小露露很厉害啊！听你这么一说我就放心了。快上班吧，不然你没响应要被带回去了。”我满脸堆笑地对露露说。眼前这个聪明又漂亮的员工，比那个小学生不知道高到哪里去了。&lt;/p&gt;
&lt;p&gt;露露果然雷厉风行。上班之后就周期让快递员们发送携带dpid和出货窗口的LLDP报给邻居。 收到包裹的邻居快递员会按照规则把这个包裹上报给我。露露利用上报包裹外面的Packet_in信的快递员的dpid和收货窗口以及包裹中的信息，可以建立两个快递员之间的连接。然后她把所有的连接组织起来，竟然把全局的物流拓扑图画出来了。我不由心里一惊：小露露不仅长得漂亮，还很能干啊。哦不！我怎么能这么想呢！应该是小露露不仅能干，还长得这么漂亮呢！&lt;/p&gt;
&lt;p&gt;正在我神游的时候，小曲不识趣地打开门，扯起嗓子热情地说：“露露妹妹，你的包裹”。我注意到小曲放下包裹的时候比阿楚在的时候多停留了3ms，也比之前干活更精神了。&lt;/p&gt;
&lt;p&gt;露露很熟练地解开包裹，然后提取出里面的关键信息。“是从绿茂花园的王大爷家到大柳树村老刘婶的包裹。绿茂花园到大柳树村需要先经过西土城站，然后去西直门站，再经过国家图书馆站，最后到万泉河站的大柳树村。”露露照着手中的Dijkstra书和物流图，竟然把快递转发路径给计算出来了。&lt;/p&gt;
&lt;p&gt;“干得好，露露，午饭加一个鸡腿！”我激动得语无伦次，却也不敢多说，怕她知道我读书少。&lt;/p&gt;
&lt;p&gt;但是就算有最短路径转发，我还是发现快递员的工作强度差异太大。有的快递员无所事事，而其他快递员加班加点。明明有的快递员可以帮忙的，但是货物总是到不了他那里。我仔细观察了一下，终于发现了问题。露露计算的路径虽然是最短的，但是当所有货物都按照最短的路径发货的话，可能就拥堵了，而另一条次优的路径并没有使用到。所以我应该还需要了解物流的压力情况。怎么才能了解呢？&lt;/p&gt;
&lt;p&gt;正在我百思不得其解的时候，年度优秀快递员张伟终于不堪重负，病倒了。他那个快递收发点的货物已经堆积如山。我查遍了所有的手册都没有解决办法，只能给发出一个警告，没想到程序员很快就派来了新员工来处理这件事。&lt;/p&gt;
&lt;p&gt;他叫夏留，听名字估计是父母喜欢夏天，希望夏天能停留，应该是一种美好的希冀，只是读音让人浮想联翩。&lt;/p&gt;
&lt;p&gt;“我学过数据挖掘，但是没找到工作，后来去学挖掘机，但是没学成，所以就去学快递技术了”。这是我印象最深的自我介绍词。我对他毫无理由的没有好感，也许是因为他比较帅吧。&lt;/p&gt;
&lt;p&gt;他和露露一样聪明，他专门整理快递网中的物流流量信息，然后和露露合作。露露其实也去学习进修了，掌握了基于物流流量信息计算最优货物转发路径的方法。所以快递员们的负载才得到了均衡，才少了许多抱怨。&lt;/p&gt;
&lt;p&gt;但是我总觉得夏留和露露整天黏在一起不太好，年轻人在办公室还是要克制一些。传数据快一些，多一些产出，少一些对视，少一些寒暄。&lt;/p&gt;
&lt;p&gt;生活又恢复了平静，就像经过暴风雨洗礼的早晨。每天的工作都大同小异，因为新流量不多，所以大家都不是很忙。但是夏留需要不断收取一些快递员送上来的快递收发货统计报表，露露也周期地和所有的快递员联系着。集智慧和美丽一身的露露是所有快递员的梦中情人。&lt;/p&gt;
&lt;p&gt;遇到节假日的时候，大家就会忙得不可开交，有时候难免会病倒。这时候我就会特别羡慕临省新上任的ODL和ONOS。ODL家族的人声势最浩大，它多才多艺，精明能干，部门员工也很多。而ONOS也比我要先进，他们是多胞胎共同作战，不像我Ryu族人还在孤军作战。ONOS他们家有好多孪生兄弟姐妹，一起管理他们省的快递物流，资源和信息都共享，每个人分别只负责区域的管理。如果其中一个兄弟生病了，可以把他的业务交给其他兄弟代理，等病好了再接着干。这样就不用担心快递主管病倒导致业务中断的事了。&lt;/p&gt;
&lt;p&gt;不过我听说有个叫Distance的程序员上帝开发了Open eXchange语言，可以架设一个层级式的部门架构。有了这样的语言，我不但可以我的族人一起工作了，还可以和不同家族的人一起工作。希望改革快一些，我知道其他人的办公室还有欣欣和丽丽。&lt;/p&gt;
&lt;p&gt;我坐在桌子前，一手撑着下巴，一手握着桌子上的杯子，幻想着美好的未来。耳边是露露和夏留的窃窃私语、小曲忙碌的脚步声，还有大健那频率不变的磨剑声，自然而和谐。&lt;/p&gt;
&lt;p&gt;突然，大门被撞开了，进来了Linux和几个凶神恶煞般的人。&lt;/p&gt;
&lt;p&gt;“大、大哥……怎么了？”我吓得唰一下站起来，杯子也被碰掉，碎了一地。&lt;/p&gt;
&lt;p&gt;“这些人都带走，那个姑娘轻点抓，挺好看的”。Linux并没有理会我，指挥小弟们把我的露露，夏留和小曲，还有一直在角落磨剑的大健五花大绑了起来。&lt;/p&gt;
&lt;p&gt;“我收到程序员上帝的通知，由于业务整改，你们部门所有资源回收，都给我去垃圾回收站，走！” &lt;/p&gt;
&lt;p&gt;Linux露出我从未见过的凶狠眼神。我明白了，我不该对未来充满幻想，我不该有任何怨念。但是我要做完我该做的事，我转身写在最后一封告别信：“Ryu is going down!”&lt;/p&gt;
&lt;p&gt;“交给程序员，告诉他我干得很好”，我把信交给操作系统，慢慢闭上了眼睛。在去往垃圾回收站黑暗而崎岖的路上，我听到露露拼命的呼喊，还有夏留，还有……&lt;/p&gt;
&lt;p&gt;“我想我没有做错”，我想到这里，嘴角颤了一下，掠过一丝转瞬即逝的微笑。&lt;/p&gt;
&lt;p&gt;黑暗中，我睁开眼睛，仿佛看见了未来。&lt;/p&gt;
&lt;h3&gt;作者简介：&lt;/h3&gt;
&lt;p&gt;李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：http://www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Mon, 18 Apr 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-04-18:pages/2016/04/18/wo-shi-ge-sdnkong-zhi-qi.html</guid><category>sdn</category></item><item><title>人生的意义：做自己，去帮助别人，但先拯救自己</title><link>http://www.muzixing.com/pages/2016/03/27/ren-sheng-de-yi-yi-zuo-zi-ji-qu-bang-zhu-bie-ren-dan-xian-zheng-jiu-zi-ji.html</link><description>&lt;p&gt;昨晚去北大帮忙大可老师参加北大的风采达人大赛，我又一次来到了北大。每一次来北大，都会觉得没有自信，因为自己没有能力读上北大，深感还需继续努力，这一次也一样。&lt;/p&gt;
&lt;p&gt;比赛现场气氛并不激烈，观众也不多，但是这样的场地在北邮几乎是找不到的。我看到了一个漂亮的姑娘在弹钢琴，我被这种气质所吸引。她看到我正看着她，停了下来说：“你要用吗？” 我说：“没有，我就欣赏”。比赛中有惊艳全场的琵琶，也有不错的相声节目，而这些在北邮都看不到。&lt;/p&gt;
&lt;p&gt;回到宿舍，我坐在电脑前不知道要做什么好，分明有很多事没有完成，但是感觉突然之间不明白自己要做什么。在习惯的环境中待太久就形成了定性思维，几乎不用思考就在每一天的行走着。有些时候这可以提高做事效率，但有时却让自己陷入定势，无法发生质变。&lt;/p&gt;
&lt;p&gt;我想我现在已经被社会编程了。在社会分工更加明确的今天，社会会对个人进行编程让个体满足社会的需求。诚然，大家都需要被编程才能提高整体的效率，但在被编程之外的空间，我还需要去追寻一些我渴望的东西，成为真正想要的自己。&lt;/p&gt;
&lt;p&gt;我思考着乱七八糟的内容，让我更加迷乱。烦躁之中，翻开了知乎，却看到了一条私信：“谢谢你跟我聊了许多话，来生再见”。我震惊了。&lt;/p&gt;
&lt;p&gt;给我私信的是一个98年的男生，现在在长春某二本财经院校读大一。上一次我回答某些关于自杀的问题的时候，他不支持我的观点，就给我发私信，我们才有了交集。我翻开了他的第一条私信内容：“我对你所说的非常不赞同，你知道一个人生无所恋丧失一切失望是什么感觉吗，可能是因为你太优秀，不是loser,一个人活着本来就是为了自己”，一切都恍如昨日。那次的聊天我还让他想明白了一些事情，开朗了一些。那天晚上我很开心地发朋友圈说：“我竟然让一个抑郁症患者想开了一些，好赞”。再后来，他私信我说他想通了：“他只是想要的太多”。我鼓励他，让他别着急，一步一步来。万万没想到，几个月之后的这个夜晚，我收到了他给我发的最后一条消息，一条年轻的生命就这样悄然逝去。直到现在我依然在频繁地查看我的私信，渴望他给我发一条私信告诉我他没事。我在搜索引擎上努力地搜寻着，却没有任何一点关于他的消息。&lt;/p&gt;
&lt;p&gt;一个年轻人就这样自杀了，理智而冷静地自杀了，但是世界上每天都发生着类似的事情。我不禁思考：人生的意义是什么？思考了一天我决定写下这个答案：To be yourself, to help others, but help yourself first. 做自己，帮助别人，但先拯救自己。&lt;/p&gt;
&lt;p&gt;我和他沟通的过程中，他说的最多的就是不知道活着的意义，觉得人需要为自己而活着，但却变成了为别人而活。我无法理解。他说他想为自己而活，却不知道自己想做做什么。期末考试要复习，他去复习了，但是他却找不到复习的意义。他的生活陷入了一个漩涡，在为自己而活和为迷茫之间无限地转换，就像水槽中的水，旋转着，钻进了黑暗的下水道，然后破碎融合。&lt;/p&gt;
&lt;h3&gt;Be yourself&lt;/h3&gt;
&lt;p&gt;做自己其实很艰难，但人生的意义就在与做自己。另一个抑郁症患者在知乎上发表了很长的回答，主题是自己太累，当孩子、员工，扮演各种角色，迎合所有人，他找不到自我，所以生无可恋。我想也许是他病了吧。&lt;/p&gt;
&lt;p&gt;如果一个人连自己都无法扮演好，那注定要失去自己，又怎么能做好其他呢。在社会关系中，个体无法做到完全独立，必然和其他个体发生连接，所以每个人都会在不同的场合，不同的环境下扮演不同的角色。但作为生命个体，每个人都在努力追寻着属于自己的人生，寻找着、实践着人生的意义。很明显，这两者并没有冲突，而是相辅相成的。人无法脱离社会独立存在，而各具体色的个体是形成美好社会，推动社会发展的重要成员。&lt;/p&gt;
&lt;p&gt;解决了做自己还是扮演其他角色的问题只是一个开始，如何做自己，如何寻找自己是一个更艰难的旅程。多少人忙忙碌碌一生只是为了生存，他们试图去成为想要的自己，但是却在社会竞争中失败，在社会生活中艰难度日。所以做自己首先要解决基本的生存问题，才能追求更高的需求。按照马斯洛的需求金字塔模型，在满足最基本的生存需求、安全需求以及社会需求之后，才能更好地追求更好的尊重需求和自我实现。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1f2bl16bpaej20hs0clgmu.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1. 马斯洛需求金字塔模型&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;但解决需求并不是按照层次逐渐满足的，完全可以跨越层次满足更高级的需求，比如电子游戏的虚拟世界，读书，学习可以让如我这种一穷二白的人满足自我实现的需求。但即使了解了这样的需求模型也无法让一个人找到真正的自己。什么是真实？真实是意识与物质世界的统一。真正的自己在内心，而不在外界。&lt;/p&gt;
&lt;p&gt;真实的自己就是内心想要的自己。但并不是所有人的想要的自己和物理实体都统一，大多数情况下，意识和现实会有很大的不同。有的人因此而努力，努力让物质的自己与意识的自己相统一；有的人因此而消沉，觉得人生没有希望，生无可恋；有的人因此麻木，随波逐流，得过且过，荒度一生。找到自己喜欢的事，喜欢的方向，是明白什么是真实的自己，而坚持努力去实现这个目标才是实现真实的自己。所以人生的方向是非常重要的。方向是人生的指南针，指引着我们向更深，更远的方向努力，而在任何无公害的领域里面，走得越远则越可能成功。&lt;/p&gt;
&lt;p&gt;但方向并不容易寻找，义务教育只是帮助我们掌握了基本的知识，如何在某一个方向上继续发展更多的是个人的事情。许多学生在学生时代由于教育资源有限、经济条件限制没有办法接触到很多的方面，从而失去了发现天赋和爱好的机会，只能随波逐流地去报考火热的专业，随波逐流地去做大家都在做的事情，他们是可怜的。而拥有极高悟性的人即使在很差的环境下还是能看到这一点，他们努力地去接触更多的人，更多的领域，去测试，去探索未知的世界，同时也是在探索未知的自己。当他们找到喜欢的方向之后，他们会把集中起来在喜欢的领域发力，从而更容易成功，完成自我实现。&lt;/p&gt;
&lt;p&gt;根据以上的逆向思维推理，可以发现：立足当下的资源，从自身需求出发，去探索，去挖掘方向是走向自我实现的第一步。在找到方向的基础之上，坚持努力才有可能做到真实的自我，实现人生追求，找到人生意义。所以并不是努力就能成功，要在正确的方向上努力才能成功。什么是正确的方向？去了解自己的真实价值观，真实的需求，并朝着想要的自己努力的方向就是正确的方向。做自己，才能更好地去追寻人生的意义。&lt;/p&gt;
&lt;h3&gt;To help others&lt;/h3&gt;
&lt;p&gt;成为更好的自己，并不仅仅是为了实现自我的需求，是为了有能力去帮助更多的人。帮助别人，也是人生的重要意义。作为社会群体的一部分，个体无法独立生存。自我实现的道路必然也是帮助别人的道路。&lt;/p&gt;
&lt;p&gt;真实的个体是拥有独立人格的多重社会角色的重合体。在每一种角色中，我们都需要和别人合作，去帮助别人，一起完成事物，并从中得到满足，尊重和自我实现。在孩子的角色中，我们需要对父母的爱感恩，去帮助父母，去疼爱父母，去帮助他们正如他们帮助我们一样。在朋友角色中，我们会去帮助朋友，正如朋友帮助我们一样。在工作环境中，我们需要完成工作任务，去帮助其他人一起完成更大的任务，正如别人也在帮忙我们一样。货币的存在是为了更好的衡量帮助， 更好地实现合作，通过流通来实现价值交换。而平等的合作本质上就是在相互帮助，相互帮助才能让个体和社会群体都朝着更好的方向发展前进。&lt;/p&gt;
&lt;p&gt;当然，由于社会上博弈关系复杂，必然存在一些囚徒困境等社会难题。但从个体角度出发，帮助别人是实现自我价值的重要手段。帮助别人的过程中，实现了社会价值，进而也实现了个人的自我价值，反过来也满足了被需求的基本社会需求。&lt;/p&gt;
&lt;p&gt;在生活中，我很喜欢在力所能及的范围内去帮助别人，这让我感到快乐，让我觉得我的存在有意义。正如我试图帮助那个陌生的年轻人一样，我并不企图得到他给任何回馈，但我乐在其中。我因为我拯救了他而开心，因为我因此而有价值。如果你也要心里疾病，找不到人生的意义，试着去帮助别人吧，你会找到人生的意义的。在帮助别人的过程中可以实现社会需求、尊重需求和最高层的自我实现需求，找到人生的意义。&lt;/p&gt;
&lt;h3&gt;But help yourself first&lt;/h3&gt;
&lt;p&gt;然而，在帮助别人之前，我们还需要拯救自己。年轻的生命啊，能拯救自己的只有自己。当心理失衡时，要寻求帮助，要保护自己，拯救自己，才能有机会成为更好的自己，做真正的自己，去帮助更多的人。&lt;/p&gt;
&lt;p&gt;理智型自杀的人，早就受够了无尽的心理折磨，他们无法从那种压抑的，痛苦的情绪中逃离出来。在不断地恶性循环之中挣扎，直到最后变成了绝望。所以为了实现人生的意义，我们都应该拯救自己。当心理失衡时，寻求外界的帮助，去拯救自己。&lt;/p&gt;
&lt;p&gt;抑郁的人无法找到人生的意义，没有办法找到真正的快乐。也许他们会和朋友一起开心唱歌、游玩，但是当夜深人静一人独处的时候，他们并不快乐，甚至因为之前的快乐而产生压抑的情绪。这是病，需要治疗。不过普通人在拯救自己的人生的时候，应当选择正确的方式。比如当心情压抑的时候，我们都需要快乐，但是快乐也分为两种：消费型快乐和创造型快乐。消费型快乐比如购物、吃东西等以消费资源的方式来满足需求模型中的低级需求从而达到快乐，这种快乐容易使人厌倦，不具有长久性。而创造型的快乐是建立在创作的基础之上的，比如完成一个程序的编写、画了一幅画带来或者谱写出一首曲子的喜悦。创造型快乐是满足更高层的自我实现需求的快乐，是可持续的、积极的、有长远意义的快乐。&lt;/p&gt;
&lt;p&gt;追寻创造型快乐可以让人得到高层次的满足，而这样的满足实现了部分的人生意义。创造型快乐的产物必然也可以给别人带来更多的帮助，从而实现了帮助别人的人生意义。而在创作型快乐的过程中，自我得到了提升，也实现了自我实现的人生意义。所以追求创造型快乐的自我拯救是人生意义的重要部分。&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;也许到了明天之后，生活的琐事就会让我忘记了这个曾经和我有过交集的少年已经永远地离开了这个世界。但是感谢他，让我思考人生的意义。做自己，帮助别人，但先拯救自己。&lt;/p&gt;
&lt;p&gt;目前我是一个北邮的研究生，做着SDN相关的研究，不出意外的话，以后一辈子都是IT行业人士。这就是我的方向，或者方向之一。选择IT行业是在高中的时候根据自身条件和喜好做出来的决定，在IT行业选择SDN方向是在大三的时候结合自身的情况和爱好选择的方向，所以我确信我在做我喜欢的事情，我在追求更高的自我实现，做想要的自己，实现人生的意义。&lt;/p&gt;
&lt;p&gt;去年偶然的机会接触了即兴戏剧，开始追求我另一个人生目标：当导演。在学习即兴戏剧的过程中，我学会和别人合作，帮助别人，同时也提升自己。之后，我希望继续系统地学习即兴戏剧，能成为一个专业人士，继续去推广即兴戏剧，并通过即兴戏剧给更多人帮助，帮助他们提升团队协作能力，也给更多人带来快乐。也希望以后我能有机会成为导演，可以创作更多深刻的作品来帮助更多的人，这也是我人生的意义。&lt;/p&gt;
&lt;p&gt;To be myself, to help others, but help myself first. 做自己，帮助别人，但先拯救自己（成为更好的自己，帮助别人）。&lt;/p&gt;
&lt;p&gt;作者：李呈
博客：http://www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 27 Mar 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-03-27:pages/2016/03/27/ren-sheng-de-yi-yi-zuo-zi-ji-qu-bang-zhu-bie-ren-dan-xian-zheng-jiu-zi-ji.html</guid><category>meaning of life</category></item><item><title>P4:真正的SDN还遥远吗</title><link>http://www.muzixing.com/pages/2016/03/23/p4zhen-zheng-de-sdnhuan-yao-yuan-ma.html</link><description>&lt;p&gt;OpenFlow协议作为SDN最流行的南向协议，得到了很多的关注，目前发展也良好，但OpenFlow并不完美，OpeFlow交换机还不能提供更好的可编程能力。P4作为新的网络编程语言很好的弥补这个缺陷。P4会改变网络吗？是否能带来具有完全可编程能力的SDN？还是仅仅是学术界的宠儿？本文将介绍协议独立数据包处理编程语言P4，其中包括其简介、原理和发展趋势，希望笔者能带来一些有意思的观点。&lt;/p&gt;
&lt;h3&gt;简介&lt;/h3&gt;
&lt;p&gt;P4(Programming protocol-independent packet processors)[1]是由Pat Bosshart等人提出来的高级“协议独立数据包处理编程语言”，如OpenFlow一样是一种南向协议，但是其范围要比OpenFlow要大。不仅可以指导数据流进行转发，还可以对交换机等转发设备的数据处理流程进行软件编程定义，是真正意义上的完全SDN。值得注意的是，P4论文作者中还有斯坦福大学的Nick McKeown教授和普林斯顿大学的Jennifer Rexford教授两位业界大牛的名字。Nick教授是SDN的提出者之一，一直是SDN学术领域顶尖的存在；而后者Jennifer教授也发表了4D[2]等诸多重要的SDN相关论文，更提出了网络编程语言Frenetic[3]，同样是业界的先驱。两位教授也是P4组织的主要推动者之一。目前，P4语言作为一种潜在的OpenFlow2.0的发展方向在努力发展。&lt;/p&gt;
&lt;h3&gt;原理&lt;/h3&gt;
&lt;p&gt;与POF提出的目的类似，P4提出的目的也是为了解决OpenFlow编程能力不足以及其设计本身所带来的可拓展性差的难题。自OpenFlow1.0发布以来，其版本目前已经演进到1.5版本。其中匹配域的个数从1.0版本的12元组变为1.3版本的40个，最后到1.5版本的45个匹配域，其匹配域数目随着新版本支持特性的更新而不断增加。但OpenFlow并不支持弹性地增加匹配域，每增加一个匹配域就需要重新编写控制器和交换机两端的协议栈以及交换机的数据包处理逻辑，这无疑增加了交换机设计的难度，也严重影响OpenFlow协议的版本稳定性，影响OpenFlow的推广。&lt;/p&gt;
&lt;p&gt;为了解决OpenFlow协议编程能力不足的问题，Nick教授等人提出了P4高级编程语言。P4的优点主要有如下三点：
（1）可灵活定义转发设备数据处理流程，且可以做到转发无中断的重配置。OpenFlow所拥有的能力仅是在已经固化的交换机数据处理逻辑之上通过流表项指导数据流处理，而无法重新定义交换机处理数据的逻辑，但P4编程语言具有对交换机的数据包处理流程编程的能力。&lt;/p&gt;
&lt;p&gt;（2）转发设备协议无关转发。交换机等交换设备无需关注协议语法语义等内容，则可以完成数据处理。由于P4可以自定义数据处理逻辑，所以可以通过控制器对交换机等转发设备编程实现对应的协议处理逻辑，而这个行为将被翻译成对应的匹配和动作从而被转发设备所理解和执行。&lt;/p&gt;
&lt;p&gt;（3）设备无关性。正如写C语言或者Python语言时并不需要关心CPU的相关信息，使用P4语言进行网络编程同样无需关心底层设备的具体信息。P4的编译器会将通用的P4语言处理逻辑编译成设备相关的指令，从而写入转发设备，完成转发设备的配置和编程。&lt;/p&gt;
&lt;p&gt;抽象的P4转发设备模型如图1所示。其中第一部分是可编程定制的解析器，用于编程实现自定义的数据解析流程，可将网络字节流解析成对应的协议数据包。解析之后的流程是和OpenFlow类似的Match+Action操作，其流水线支持串行和并行两种操作。受OpenFlow1.4的启发，P4设计的匹配过程也分为Ingress Pipeline和Egress Pipeline两个分离的数据处理流水线。与OpenFlow相比，P4的设计有3个优点：可定制数据解析流程，而不像OpenFlow交换机的固定解析逻辑；可执行并行和串行的匹配+动作操作，而OpenFlow仅支持串行操作；支持协议无关的转发。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="p4 model" src="http://ww3.sinaimg.cn/mw690/7f593341jw1f1ykzr2m6kj20o50hodiu.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1. P4转发设备模型&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;抽象的P4转发模型用于展示交换机如何被配置和编程的。在定义交换机处理逻辑时，需要定义数据包处理的依赖关系，也即数据报头的依赖关系，比如要处理IPV4报文可能需要依赖于以太网报文的处理。这些依赖关系可以通过P4编程语言描述出来，并编译生成TDG(Table Dependency Graph)，其中每个表都是对应的一种协议或者一个类别的数据包的处理。TDG描述了匹配表之间的逻辑关系，输入和对应操作等行为，用于指导交换机进行数据处理。TDG被定义出来之后，将被编译器翻译成交换机理解的逻辑或者指令，并写入到交换机等转发实体中，从而完成自定义数据包处理流程。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341jw1f1ykzqr0qfj20r30ebjue.jpg" /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;图2.  L2/L3交换机的TDG实例图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;一个P4程序包含如下5个关键组件:Header、Parser、Table、Action和Control Programs。其具体介绍如下：
Header（报头）：数据包的处理都需要根据报头的字段内容来决定其操作。所以P4中也需要定义对应的报头，报头本质上就是有序排列的字段序列。报头的描述由有序的字段名称和对应的字段长度组成，示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="n"&gt;ethernet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dst_addr&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt;
        &lt;span class="n"&gt;src_addr&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;ethertype&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Parser（解析器）：在定义了报头之后，还需要定义报头之间的关系，及数据包解析的对应关系。比如ethernet的ethertype=0x0800时应该跳转到IPV4的header进行后续解析。以以太网报头解析为例，示例代码如下。所有的解析均从start状态开始，并在stop状态或者错误之后结束。解析器用于将字节流的信息解析为对应的协议报文，用于后续的流表项匹配和动作执行。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="n"&gt;ethernet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ethertype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mh"&gt;0x8100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vlan&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mh"&gt;0x9100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vlan&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mh"&gt;0x800&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ipv4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Other&lt;/span&gt; &lt;span class="n"&gt;cases&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Table（表）：P4中需要定义多种用途的表用于存储匹配表项。其表的格式为Match+Action，即匹配域和对应的执行动作。P4语言定义某个表具体的匹配域以及需要执行的动作。而具体的流表项需要在网络运行过程中通过控制器来编程下发，从而完成对应数据流的处理。举个例子，比如在入口交换机上需要将对应VLAN的数据添加类似于MPLS标签的自定义标签mtag，从而数据在交换网络中通过匹配mtag来完成转发。具体示例如下，其中reads相当与读取匹配域的值，匹配类型为精确匹配；action为匹配成功之后执行的动作，此处为添加mtag标签；而max_size则描述匹配表的最大表项容量。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="n"&gt;mTag_table&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;reads&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst_addr&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;exact&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="n"&gt;vlan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vid&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;exact&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;At&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;programmed&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;mTag&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;See&lt;/span&gt; &lt;span class="n"&gt;below&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; 
    &lt;span class="n"&gt;add_mTag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;max_size&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Action（动作）：与OpenFlow的动作类似，不过P4的动作是抽象程度更高的协议无关的动作。P4定义了一套协议无关的原始指令集，基于这个指令集可以实现复杂的协议操作。P4支持的原始指令集包括set_field、add_header和checksum等为数不多的指令。复杂的动作将通过赋予不同的参数来调用这些原始指令集组合来实现，而这些参数可以是数据包匹配过程中产生的metadata。示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="n"&gt;add_mTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;up1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;up2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;down1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;down2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;egr_spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;add_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mTag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Copy&lt;/span&gt; &lt;span class="n"&gt;VLAN&lt;/span&gt; &lt;span class="n"&gt;ethertype&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;mTag&lt;/span&gt;
    &lt;span class="n"&gt;copy_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mTag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethertype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vlan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethertype&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt; &lt;span class="n"&gt;VLAN&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;ethertype&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="n"&gt;mTag&lt;/span&gt;
    &lt;span class="n"&gt;set_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vlan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethertype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xaaaa&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;set_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mTag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;up1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;up1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;set_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mTag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;up2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;up2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;set_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mTag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;down1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;down1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;set_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mTag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;down2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;down2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Control Program（控制程序）：控制程序决定了数据包处理的顺序，即数据包在不同匹配表中的跳转关系。当表和动作被定义和实现之后，还需要控制程序来确定不同表之间的控制流。P4的控制流包括用于数据处理的表，判决条件以及条件成立时所需采取的操作等组件。以mtag的处理为例，其过程如图2.11所示。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1f1ykzqju2oj20os0ar75g.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图2.11. mTag处理流程图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;以上是P4语言程序必要的5个关键的组件的介绍。完成一个P4语言程序之后，需要通过P4的编译器将程序编译并写入到交换机中，其主要分为数据解析逻辑的编译写入和控制流程的编译写入。数据解析部分用于将网络字节流解析为对应的协议报文，并将报文送到接下来的控制流程中进行匹配和处理。控制流程的编译和写入主要分为两步：第一步需要将P4的程序编译，然后生成设备无关的TDG(Table Dependency Graph)，之后再根据特定的底层转发设备的资源和能力，将TDG映射到转发设备的资源上。目前P4支持软件交换机、拥有RAM和TCAM存储设备的硬件交换机、支持并行表的交换机，支持在流水线最后才执行动作的交换机以及拥有少量表资源的交换机等多种交换设备。&lt;/p&gt;
&lt;h3&gt;发展趋势&lt;/h3&gt;
&lt;p&gt;OpenFlow协议目前的框架设计使得OpenFlow无法对转发设备的数据解析和处理流程进行编程实现，缺少足够的可编程能力。此外，由于OpenFlow的匹配项均为协议相关的，使得每增加一个匹配域均需要对协议栈以及交换机处理流程进行重新编程，而这个过程周期很长，为支持新的OpenFlow协议需要对现有交换机进行升级或者推出新的交换机产品。这样的缺点让OpenFlow协议版本难以稳定，也难以推广。服务提供商在建设网络基础设施时，需要考虑支持OpenFlow什么版本，也要担心未来OpenFlow协议推出新版本时的兼容和设备升级等问题，使得OpenFlow迟迟无法大规模应用。面对OpenFlow的缺陷，P4的推出刚好解决了这个难题。&lt;/p&gt;
&lt;p&gt;P4语言支持对交换机处理逻辑进行编程定义，从而使得协议版本在更新迭代时无需购买新设备，只需通过控制器编程更新交换机处理逻辑即可。这种创新解决了OpenFlow编程能力不足，版本不稳定的问题。此外，由于P4可以编程定义交换机处理逻辑，从而使得交换机可以实现协议无关的转发，进而使得底层交换机更加白盒化，适用范围更广，更容易降低设备采购成本。而且作为一门编程语言，P4支持设备无关特性，使得P4可以应用在不同厂家生产的转发设备上，解除了服务提供商对网络设备厂家绑定的顾虑。&lt;/p&gt;
&lt;p&gt;自P4诞生以来，得到了业界的关注和认可，目前发展良好。作为一门网络编程语言，其大大简化了网络编程的难度，同时也改善了目前SDN可编程能力不足的问题。P4的主要推动者Nick教授是当下SDN最流行的南向协议OpenFlow协议的发明者之一，Jennifer教授也在网络界的先驱。无论是处于对P4技术本身的认同，还是对Nick教授和Jennifer教授的认同，业界尤其是学术界都P4都非常认同，认为其将成为OpenFlow2.0的可能方向。目前，P4组织已经有了非常多的成员，其中包括AT&amp;amp;T、思科、华为、Intel、腾讯和微软等企业以及斯坦福大学，普林斯顿大学和康奈尔大学等多个全球顶尖的学术机构。此外，在P4发展的过程中，已经被多种转发设备支持，比如应用最广泛的软件交换机OpenVSwitch以及华为的POF交换机。转发设备的支持是P4继续发展的强大保障，是P4商业发展的前提。&lt;/p&gt;
&lt;p&gt;P4的设计和华为提出的POF十分相似，只不过侧重点和实现方式不同。POF通过{offset,length}来确定数据，强调协议无关，强调指令集，而P4不仅有底层的高度抽象的协议无关指令集，更侧重与控制器端的网络编程语言的构建。还有一点不同的是，同作为开创式的技术，由美国Nick教授等业界先驱推动的P4明显要比由华为提出的POF受到的关注要多，业界对P4的认同也要比POF要高。&lt;/p&gt;
&lt;p&gt;P4和POF相同之处在于：作为完全可编程的SDN实现，性能问题是两者需要面临的大问题，也是急需解决的技术难题。而商业因素方面，两者皆会打破目前的网络界生态平衡。选择搭上这个技术发展的进程并争取在新的技术领域占据有利地位，还是固守已有行业市场是网络厂商面连的艰难选择。完全可编程SDN的出现，将网络的重点由硬件转向软件领域，从而使得依靠硬件技术壁垒占据市场有利地位的传统巨头的优势受到严重削减。虽然巨头的决策将很大程度上影响这些创新技术的发展，但是技术的发展必然朝着更好的方向发展，无论是P4还是POF，抑或是其他的解决方案，具有更好可编程性的SDN就在不远的未来。正如SDN的出现一般，是技术发展过程中顺势而为的产物，是不可阻挡的。&lt;/p&gt;
&lt;h3&gt;参考文献&lt;/h3&gt;
&lt;p&gt;[1] Bosshart P, Daly D, Gibb G, et al. P4: Programming protocol-independent packet processors[J]. ACM SIGCOMM Computer Communication Review, 2014, 44(3): 87-95.&lt;/p&gt;
&lt;p&gt;[2] Greenberg A, Hjalmtysson G, Maltz D A, et al. A clean slate 4D approach to network control and management[J]. ACM SIGCOMM Computer Communication Review, 2005, 35(5): 41-54.&lt;/p&gt;
&lt;p&gt;[3] Foster N, Harrison R, Freedman M J, et al. Frenetic: A network programming language[C]//ACM SIGPLAN Notices. ACM, 2011, 46(9): 279-291.&lt;/p&gt;
&lt;h3&gt;作者简介：&lt;/h3&gt;
&lt;p&gt;李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：http://www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 23 Mar 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-03-23:pages/2016/03/23/p4zhen-zheng-de-sdnhuan-yao-yuan-ma.html</guid><category>p4</category><category>sdn</category></item><item><title>POF:更理想的SDN?</title><link>http://www.muzixing.com/pages/2016/03/12/pofgeng-li-xiang-de-sdn.html</link><description>&lt;p&gt;OpenFlow协议实现的SDN目前已经得到了应用和推广，但OpenFlow并不完美，OpeFlow交换机还不能提供更好的可编程能力。POF作为一种新的南向协议，是OpenFlow的未来方向？还是只是一个乌托邦？本文将介绍由华为提出的协议无关转发POF，其中包括其简介、原理、原型和应用场景以及最后的发展趋势，希望能带来一些有意思的想法。&lt;/p&gt;
&lt;h3&gt;简介&lt;/h3&gt;
&lt;p&gt;POF(Protocol Oblivious Forwarding)[1]是由华为提出的SDN南向协议，是一种SDN实现方式，中文意思为协议无关转发。与OpenFlow相似，在POF定义的架构中分为控制平面的POF控制器和和数据平面POF转发元件(Forwarding Element)。在POF架构中，POF交换机并没有协议的概念，它仅在POF控制器的指导下通过{offset, length}来定位数据、匹配并执行对应的操作，从而完成数据处理。此举使得交换机可以在不关心协议的情况下完成数据的处理，使得在支持新协议时无需对交换机进行升级或购买新设备，仅需通过控制器下发对应流表项即可，大大加快了网络创新的进程。&lt;/p&gt;
&lt;h3&gt;原理&lt;/h3&gt;
&lt;p&gt;读者可能会有疑问：OpenFlow所实现的SDN目前不是发展挺好的吗，POF相比OpenFlow有什么优点呢？&lt;/p&gt;
&lt;p&gt;在OpenFlow1.0版本推出时，普遍被认为只有12个匹配域无法适应多网络场景的需求。但随着OpenFlow版本的推进，发展到OpenFlow1.3版本时已经有了40个匹配域，已经可以支持大部分的协议字段匹配。然而始终还会有更多的协议需要支持，所以这个增长趋势不会停止。不断增多的匹配域，使得OpenFlow协议越来越复杂，也使得OpenFlow交换机的设计与实现越来越复杂。而不稳定的协议内容让OpenFlow无法被广泛支持，因为设备厂家需要不断地开发新的交换机来支持新协议，而网络所有者如运营商也会担心协议版本不稳定带来的设备不兼容问题。&lt;/p&gt;
&lt;p&gt;除此之外，OpenFlow实现的SDN还有两个明显的不足：首先，OpenFlow依然只能在现有交换机的转发逻辑上来添加对应流表项来指导数据包的转发，而无法对交换机的转发逻辑进行编程；其次，OpenFlow基本是无状态的，其无法维护网络状态并主动做出动作。这两个主要的缺陷将会带来如下的不良后果：&lt;/p&gt;
&lt;p&gt;（1）目前OpenFlow所实现的数据平面和控制平面分离得不够彻底。数据平面的交换机设备依然需要掌握协议的语义信息等控制信息才能完成数据匹配。当交换机支持的协议增多时，支持特定协议的指令会大规模增长，从而增加了交换机的设计难度。&lt;/p&gt;
&lt;p&gt;（2）在当前的交换机中，很难去对数据包进行修改或者增加一些辅助信息，更别说支持新的转发协议的运行测试了。所以目前的新协议在交换机不支持的情况下都是通过Overlay的形式来实现，这就必须对数据进行封装和解封装，这种实现方式即增加了数据解析的难度和压力，也带来了过长的报头，降低了数据传输效率。&lt;/p&gt;
&lt;p&gt;（3）在给OpenFlow添加新协议特性时，需要重写控制器和交换机两端协议栈。而且在最麻烦的情况下，还需要重新设计交换机的芯片和硬件才能支持新特性。虽然最新版本的OpenFlow已经支持40多个匹配域，但这些匹配域大多是基于以太网的协议族的字段。还存在许多其他网络的协议，以及未来诞生的协议需要支持。所以每增加一个新的协议或者特性都会带来很多的开发量，增加了支持新协议的成本。而OpenFlow不稳定的协议版本，也增大了OpenFlow推广的难度。&lt;/p&gt;
&lt;p&gt;（4）交换机目前匮乏的表达描述能力使得转发平面的可编程性受到很大的限制，最明显的一点就是交换机无法描述有状态的逻辑并主动采取动作。由于OpenFlow缺乏足够的能力去维持网络状态，所以OpenFlow交换机基本无法自主实现有状态的操作。与状态相关的信息均由控制器维护，交换机只能通过控制器来指导动作，而无法在满足条件时主动采取动作。这种完全需要控制器来指挥的机制让数据平面过度依赖控制平面，带来了SDN的可拓展性和性能问题。&lt;/p&gt;
&lt;p&gt;针对以上的问题，华为提出了POF的解决方案。POF通过{offset, length}来定位数据，所有的协议相关的内容由控制器来描述，而交换机仅需通过通用的指令集完成数据操作即可，从而实现了协议无关转发。细心的读者应该发现协议的操作无非就是增加、修改和删除对应的字段/标签，而这些操作可以通过通用的指令集来实现，比如Addfiled就可以添加所有的字段，而具体的字段只有控制器了解，而交机机并不掌握这个信息。&lt;/p&gt;
&lt;p&gt;POF的设计思想与PC的设计思想类似，所以其架构和PC的架构也类似，两者对比见图1。POF转发设备无需关心具体的协议语义，只需关心最底层的数据操作即可，正如CPU并不知道执行的运算是一个语音相关的运算，还是图片处理，它只知道执行了“+”操作。控制器正如PC中的操作系统一般，为上层业务提供丰富的业务接口，为下层提供通用的指令集，并完成两者的翻译工作。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="pof" src="http://ww4.sinaimg.cn/mw690/7f593341jw1f1s58opfiqj20b108wwf0.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1. POF与PC架构对比&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;通过使用通用指令集来实现协议无关转发的设计使得交换机拥有完全的可编程能力。控制器可以通过南向协议对交换机进行编程，包括数据转发引擎逻辑的编程以及数据流的处理规则的编程。另外，使用通用指令集的交换机很自然地就能互联互通。当网络中需要支持新的协议时，仅需通过控制器进行编程就可以实现，这大大缩短了网络创新周期。而对于运营商或者服务提供商而言，在添加新网络服务时不再需要联系厂商，也无需购买新的交换设备。&lt;/p&gt;
&lt;p&gt;针对OpenFlow无状态的缺陷，POF设计了相关指令使得在条件满足时，交换机可以主动地创建、修改和删除流表等操作。在主动执行指令之后，交换机需要异步通知控制器发生的改变，从而实现数据的同步。笔者认为状态维护特性是POF设计中的精彩之处。因为目前OpenFlow几乎无法实现与状态相关的操作，而在网络安全等重要领域，维护网络状态是实现网络安全的必要手段。当然，为实现状态维护，必然需要付出一些性能代价或者成本代价。&lt;/p&gt;
&lt;h3&gt;原型与应用场景&lt;/h3&gt;
&lt;p&gt;为了验证POF的可行性，华为团队基于FloodLight开源控制器开发了POF控制器，其架构模块图如图2所示。在数据平面，分别基于华为硬件核心路由器和软件交换机实现了两个POF交换机模型用于验证POF的可行性，其功能架构如图3所示。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="pof controller" src="http://ww4.sinaimg.cn/mw690/7f593341jw1f1s58pwvh6j20h10a9myp.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图2. POF控制器架构模块图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="pof fe" src="http://ww2.sinaimg.cn/mw690/7f593341jw1f1s58qi981j20gt0cq0uu.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图3. POF硬件交换机(左)，POF软件交换机(右)&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;在POF的论文中还介绍了转发性能测试的结果，其可以在40G的线卡测试中达到48Mpps的速率，虽然丢失了20%的性能，但是依然支持80-Bytes的线速转发。性能问题也许是POF存在的最大的技术问题之一。&lt;/p&gt;
&lt;p&gt;由于POF支持协议无关转发，所以POF可以部署在任意的网络中，包括一些非以太网络。此外，POF的协议无关转发特性使得POF可以完美地支持Named Data Network (NDN)和Content-Centric Network (CCN) 等未来网络领域的研究。而POF支持有状态的网络使得交换机可以实现更多的智能，并应用于网络安全等领域。&lt;/p&gt;
&lt;h3&gt;发展趋势&lt;/h3&gt;
&lt;p&gt;为实现POF的平滑过渡，POF应满足OpenFlow兼容的需求。目前OpenFlow设备已经存在一些，如果能让POF成为OpenFlow的一种服务，则可以平滑地从OpenFlow过渡到POF。而转发设备方面的实现需要在现有的芯片上是支持POF的指令集，使POF的指令集作为一个方法去调用。之后才是将POF的指令集直接在ASIC上支持，从而换取更高的数据处理和转发性能。&lt;/p&gt;
&lt;p&gt;作为一个理想的模型、一个开创式的技术，POF可以重新赋予SDN新的定义，带来具有完全编程能力的SDN。但是这个进程注定是艰难的。一个技术的发展，除了技术本身的技术缺陷以外，更多是收商业因素的左右。POF在技术方面的性能缺陷是一个问题，但是总可以通过不断地优化和产品迭代来提高性能，所以阻碍其发展的更多是来自商业方面的因素。POF带来的变革正如OpenFlow带来的变革一样，甚至更甚。OpenFlow使得控制平面和转发平面分离，交换机成为灰盒子或者白盒子，使得原有依靠专有技术的企业失去了技术壁垒，而这些拥有技术壁垒的企业基本都是行业的领头羊，当一项技术影响到领头羊的地位时，它必定是很难推广和发展的。企业不仅仅是推进技术的发展，让世界变得更好，更多的时候，他们还需要生存，而生存往往是最重要的。所以不难想象OpenFlow的推广并不顺利，而POF比OpenFlow有过之而无不及，所以同样可以想象POF的推广更加艰难。&lt;/p&gt;
&lt;p&gt;POF的发展以及推广势必会打破现有的行业生态，而那些在目前生态中过得很好的领头羊自然不愿接受这个改变，而提出POF的华为司司目前在这个生态中也处于上游，POF的推广最终会让华为发展更好还是更差，这不得而知。目前看来，POF自发论文以来到没有很大的进展，但在与宋浩宇前辈的沟通中得知POF项目还在继续推进，今年年中将有产品推出，希望POF能带来一些不一样的改变。&lt;/p&gt;
&lt;p&gt;历史的车轮总是前进的。目前不仅仅POF提出了这种想法，由OpenFlow发明者Nick教授的团队也提出了P4(Programming protocol-independent packet processors) [2]解决方案来解决目前OpenFlow的不足之处。POF和P4两者思路类似，但POF强调通用指令集实现协议无关转发，是偏硬件的解决思路，而P4则关注上层网络建模来定义交换设备转发逻辑，是更偏软件的解决思路。而无论哪一种解决方案，交换机将越来越开放，网络也会具有更好的可编程性。P4和POF都是OpenFlow未来有前景的发展方向之一。&lt;/p&gt;
&lt;p&gt;笔者认为，随着技术的发展，POF技术方面的缺陷将得到解决，前提是华为继续推进POF的研发工作。随着技术问题的解决，成本的降低，作为网络设备购买方的服务提供商应该会更加倾向与采购更加SDN的设备。因为POF将带来可编程性能更好的SDN设备，从长远角度看，POF也降低了设备的采购成本和运营成本。如果P4和POF可以整合，在软件方案和硬件方案上相互弥补，会成为一个更加有前途的解决方案，而目前的POF确实也已经支持了P4。如果谷歌、微软等巨头加入之后，SDN的进程就会像NFV那样变成一个由网络拥有者而非设备商主导的技术革命？也许这样POF就可以改变未来的网络，实现真正具有完全可编程能力的SDN。&lt;/p&gt;
&lt;h3&gt;参考文献&lt;/h3&gt;
&lt;p&gt;[1] Song H. Protocol-oblivious forwarding: Unleash the power of SDN through a future-proof forwarding plane[C]//Proceedings of the second ACM SIGCOMM workshop on Hot topics in software defined networking. ACM, 2013: 127-132.&lt;/p&gt;
&lt;p&gt;[2] Bosshart P, Daly D, Gibb G, et al. P4: Programming protocol-independent packet processors[J]. ACM SIGCOMM Computer Communication Review, 2014, 44(3): 87-95.&lt;/p&gt;
&lt;h3&gt;作者简介：&lt;/h3&gt;
&lt;p&gt;李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：http://www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sat, 12 Mar 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-03-12:pages/2016/03/12/pofgeng-li-xiang-de-sdn.html</guid><category>POF</category><category>SDN</category></item><item><title>OpenFlow的伴侣协议：OF-CONFIG</title><link>http://www.muzixing.com/pages/2016/03/03/openflowde-ban-lu-xie-yi-of-config.html</link><description>&lt;p&gt;本文将简要介绍OpenFlow协议的伴侣协议即补充协议OF-CONFIG，主要内容包括OF-CONFIG的简介、原理以及发展趋势。希望能让读者对OF-CONFIG有一个初步的认识。&lt;/p&gt;
&lt;h3&gt;简介&lt;/h3&gt;
&lt;p&gt;在OpenFlow协议的规范中，控制器需要和已配置的交换机进行通信。而交换机在正常工作之前需要对其特性以及资源进行配置才能正常工作。而这些配置超出了OpenFlow协议规范的范围，理应由其他的配置协议来完成。OF-Config（OpenFlow Management and Configuration Protocol）协议就是一种OpenFlow交换机配置协议。OF-CONFIG由ONF于2012年1月提出，目前已经演化到1.2版本。OF-CONFIG协议与OpenFlow协议的关系如图1所示。&lt;/p&gt;
&lt;p&gt;作为一种交换机配置协议，OF-CONFIG的主要功能包括配置交换机连接的多个控制器信息、端口和队列等资源的配置以及端口等资源的状态修改等内容。此外，作为一个配置协议，OF-CONFIG也要求链接必须是安全可靠的。为满足实际网络运维要求，OF-CONFIG支持通过配置点对多个交换机进行配置，也支持多个配置点对同一个交换机进行配置。&lt;/p&gt;
&lt;p&gt;为了满足OpenFlow版本更新的需求以及协议的可拓展要求，OF-CONFIG采用XML来描述其数据结构。此外，在OF-CONFIG的初始规范中也规定了采用NETCONF协议作为其传输协议。由于OF-Config协议没有和数据交换和路由等模块直接相关，所以相比于对实时性要求高的OpenFlow等南向协议而言，OF-CONFIG协议对实时性要求并不高。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="of-config and openflow" src="http://ww1.sinaimg.cn/mw690/7f593341jw1f1f92gb9fij209k09e3yz.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1. OF-CONFIG 与OpenFlow以及OpenFlow Switch之间的关系图&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;原理&lt;/h3&gt;
&lt;p&gt;OF-Config协议主要分为Server和Client两部分，其中Server运行在OpenFlow交换机端，而Client运行在OpenFlow配置点上。本质上，OpenFlow配置点就是一个普通的通信节点，其可以是独立的服务器，也可以是部署了控制器的服务器。通过OpenFlow Configuration Point(OpenFlow配置点)上的Client程序可以实现远程配置交换机的相关特性，比如连接的控制器信息、交换机特性及端口和队列等相关配置。最新的1.2版本的OF-CONFIG协议支持OpenFlow1.3版本的交换机的主要配置如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置datapath（在OF-CONFIG协议中称为OpenFlow逻辑交换机）连接的控制器信息，支持配置多个控制器信息，实现备份。&lt;/li&gt;
&lt;li&gt;配置交换机的端口和队列，实现资源的分配&lt;/li&gt;
&lt;li&gt;远程改变端口的状态以及特性&lt;/li&gt;
&lt;li&gt;完成OpenFlow交换机与OpenFlow控制器之间安全链接的证书配置&lt;/li&gt;
&lt;li&gt;发现OpenFlow逻辑交换机的能力&lt;/li&gt;
&lt;li&gt;配置VXLAN、NV-GRE等隧道协议&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OF-CONFIG采用XML来描述其数据结构，并通过NETCONF协议来传输其内容。其最顶层的数据结构图如图2所示。其中OpenFlow Capable Switch是有OpenFlow Logical Switch实例化出来的一个数据结构，用于与OpenFlow配置节点通信，并由配置节点对其属性进行配置。OpenFlow逻辑交换机是指对OpenFlow交换机实体的逻辑描述，用于指导交换机进行相关动作，也是与OpenFlow控制器通信的实体。OpenFlow逻辑交换机拥有包括端口，队列，流表等资源。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="data model of of-config" src="http://ww1.sinaimg.cn/mw690/7f593341jw1f1f92gkmecj20i40c0abh.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图2. OF-CONFIG 核心数据结构UML图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;作为OpenFlow的伴侣协议，OF-CONFIG很好地弥补了OpenFlow协议规范之外的内容。在OpenFlow协议的SDN框架中，OF-CONFIG需完成交换机的配置工作，包括配置控制器信息等内容。当交换机和控制器建立连接之后，将通过OpenFlow协议来传递信息。从面向对象的角度看，OpenFlow协议规范的范围仅负责指导交换机对数据流进行操作而无法对交换机的资源进行配置，转而由OF-CONFIG等配置协议来完成交换机的配置工作，此设计体现了面向对象的理念，使得协议内容更加合理。&lt;/p&gt;
&lt;p&gt;而作为伴侣协议，OF-CONFIG协议是对OpenFlow协议的补充，所以其设计动机、设计目的和实现方式等方式都不一样。但值得注意的是，OpenFlow逻辑交换机的某些属性可以通过OpenFlow协议和OF-CONFIG协议两种方式来进行配置，所以两个协议也有相互重叠的地方。笔者将OpenFlow和OF-CONFIG的差异整理于表1。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;表1. OpenFlow与OF-CONFIG的差异&lt;/center&gt;&lt;/p&gt;
&lt;table class="table-bordered table-striped table-condensed"&gt;
    &lt;tr&gt;
        &lt;td width='100'&gt;&lt;/td&gt;
        &lt;td width='350'&gt;&lt;strong&gt;OpenFlow&lt;/strong&gt;&lt;/td&gt;
        &lt;td width='350'&gt;&lt;strong&gt;OF-CONFIG&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;设计动机&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;修改流表项等规则来指导通过OpenFlow交换机的网络数据包的修改和转发等动作。&lt;/td&gt;
        &lt;td&gt;通过远端的配置点来对多个OpenFlow交换机进行配置，简化网络运维工作。 &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;传输&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;通过TCP，TSL或者SSL来传输OpenFlow比特流。&lt;/td&gt;
        &lt;td&gt;通过XML来描述数据，并通过NETCONF来传输。 &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;协议终结点&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;p&gt;(1) OpenFlow控制器(代理或者中间层在交换机看来就是控制器)&lt;/p&gt;
            &lt;p&gt;(2) OpenFlow交换机/datapath&lt;/p&gt;&lt;/td&gt;
        &lt;td&gt;&lt;p&gt;(1)OF-CONFIG配置点&lt;/p&gt;
            &lt;p&gt;(2) OpenFlow使能交换机&lt;/p&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;使用示例&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;OpenFlow控制器下发一条流表项指导交换机将从端口1进入的数据包丢弃。&lt;/td&gt;
        &lt;td&gt;通过OF-CONFIG配置点将某个OpenFlow使能交换机连接到指定的控制器。 &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;h3&gt;发展趋势&lt;/h3&gt;
&lt;p&gt;自2012年发布的OF-CONFIG 1.0版本之后，为支持OpenFlow协议的新版本特性，OF-CONFIG协议也不断更新协议版本。至2014年为止，OF-CONFIG已更新到1.2版本，其支持OpenFlow1.3版本协议的新特性。目前为止尚无更新版本更新。&lt;/p&gt;
&lt;p&gt;与OF-CONFIG类似的配置协议还有OVSDB，其专门为OpenVSwitch的数据库配置服务，可用于创建网桥并配置。而随着OpenVSwitch的流行，OVSDB的曝光率相比要高于OF-CONFIG，所以两者在技术上是一种竞争关系。但是OF-CONFIG适用于所有支持OpenFlow协议的交换机，包括软件交换机和硬件交换机，而OVSDB只支持OpenVSwitch交换机。这点差异使得OF-CONFIG在物理交换机环境下占有一定优势。&lt;/p&gt;
&lt;p&gt;随着SDN的发展，OpenFlow不再是唯一的，也不再是必须的选项。但是无论选择哪一种南向协议，都需要通过交换机配置协议，所以相比OpenFlow而言，OF-CONFIG似乎更有生命力。因此笔者看好OF-CONFIG在SDN发展的很长一段时间内将拥有稳定的技术市场，这个趋势和OpenFlow的发展有很大的关系，但是OF-CONFIG不会随着OpenFlow的可能消亡而失去竞争力。&lt;/p&gt;
&lt;p&gt;作者简介：&lt;/p&gt;
&lt;p&gt;李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 03 Mar 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-03-03:pages/2016/03/03/openflowde-ban-lu-xie-yi-of-config.html</guid><category>of-config</category></item><item><title>等风来——迟到的2015年终总结</title><link>http://www.muzixing.com/pages/2016/02/24/deng-feng-lai-chi-dao-de-2015nian-zhong-zong-jie.html</link><description>&lt;p&gt;年轻的人，总是梦想着乘上远航的船，去追逐远方的未来。扬帆启航之前的等待，他都在认真地等风来。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.muzixing.com/pages/2014/01/01/shu-yu-wo-de-2013he-2014.html"&gt;两年之前，我踏上了自己选择的路&lt;/a&gt;，满心充满的是欢喜和感恩，感谢世界给我的幸运和关爱。&lt;a href="http://www.muzixing.com/pages/2015/03/08/zhan-zai-shi-zi-lu-kou-de-nian.html"&gt;一年之前，我站在十字路口&lt;/a&gt;，对未来感到彷徨，却有坚定信念。一转眼，一年又过去了，我站在港口，打包行囊，望着远方等风来。&lt;/p&gt;
&lt;h2&gt;造船的日子&lt;/h2&gt;
&lt;p&gt;过去一年的时间，是按计划造船的时间。学习生活上都按照计划进行地不错。专业学习上计划进行顺利，计划之外也收获一些惊喜。&lt;/p&gt;
&lt;h3&gt;CIIP&lt;/h3&gt;
&lt;p&gt;CIIP并不是我计划上的内容，但是当它出现的时候，我知道它成为我的计划了。大三的时候，悉尼大学的网友就和我交流过这个事情，他说他要去参加CIIP。我谷歌了一下，原来是思科的国际实习生计划。当时特别想去，没想到两年之后，我也有机会。对待CIIP申请的事，我超出常态的谨慎和认真，这得益于那次失败的SDN大赛。&lt;/p&gt;
&lt;p&gt;在SDN第二届大赛之前，我一直是一个很自信的人，做什么事都觉得肯定能行。但是不幸的是初赛的文档得分不高，仅拿到了15名左右的成绩，没有办法进入决赛。作为一个长期混迹于各个技术QQ群的我而言，我知道从此之后我再也不能随意露面，随意发言了。因为比我厉害的人还有好多，而我连决赛都进不了。虽然最后我们的方案让学弟们拿去参赛还拿了第一，但是那和我没有半毛钱关系。不过我觉得我在这件事中得到的更多是益处，虽然没有拿奖，但是让我做事更加谨慎，认真，尤其是在申请CIIP这件事情之上。&lt;/p&gt;
&lt;p&gt;从开始的简历准备，到后来的面试等等，每个环节都超乎平常地认真仔细。幸运地，经过漫长的等待，终于在大过年的时候拿到了Offer。希望自己能赶快还完助学贷款，搞定签证，飞向硅谷学习。相信那一定是美好的一段学习生活。&lt;/p&gt;
&lt;h3&gt;期待的人生的第一本书&lt;/h3&gt;
&lt;p&gt;在去年刚写完总结之后不久，幸运地收到了一封来自某出版社编辑的写书邀请。从此开始了一段不一样的人生体验。虽然目前进度不太理想，但是依然坚信最后我和我的合作人杨前辈一定能完成这本书的。&lt;/p&gt;
&lt;p&gt;在刚开始写书的时候特别纠结，因为实验室的工作很忙，只能在晚上或者周末写，时间不充足。而且自己本身技术基础较弱，文字功底也很差，写出来的东西都无法满意，所以进度非常缓慢。再加上曾经参与过导师书籍的撰写，内容非常类似，也担心导师不同意。幸亏黄老师非常支持我的计划，真心非常感谢黄老师的支持。希望自己能在去实习之前完成这一个自认为十分特别的人生目标。&lt;/p&gt;
&lt;p&gt;写书的过程非常艰苦，需要付出很多的心血。进度推不动的时候，两人会相互鼓励，相互扶持。而前辈告诉我：“写书，受益最大的是自己”。在写书的过程中，作者可以系统地学习和总结知识，这个机会非常难得。当我了解到写书的不容易之后，更加坚定了一定购买正版的图书以及产品的想法，从而保护作者的知识产权。&lt;/p&gt;
&lt;h3&gt;Open eXchange&lt;/h3&gt;
&lt;p&gt;研究生二年级是正式产出科研成果的时候，而我显得进度有点慢。经过研一一年的摸索和思考，最终选择了可拓展性这个研究方向。结合之前的经验，我决定设计一个支持异构控制器通信的协议:Open eXchange。&lt;/p&gt;
&lt;p&gt;从3月份到10月份，我完成了Open eXchange 协议的规范设计，开发和测试等工作。其中设计方面包括通信流程的设计，报文数据结构的设计等等。从6月份开始，我根据设计方案开始独自开发协议栈，终于在10月份左右完成了协议的开发和测试。之后的几个月，努力完成了论文的初稿撰写，而如今还在等待导师审核。&lt;/p&gt;
&lt;p&gt;在设计和开发的过程中，我完整地走完了从需求文档，设计文档到开发，最后到测试，还有后期的产品文档撰写等工作，而几乎所有的工作都是自己完成的。很开心自己能从头到尾认真地努力和坚持。如今我看待这个协议就如同看待自己儿子一样（假想的，我还年轻，没有儿子），会花大量的精力来优化它，写更多通俗易懂的文档来介绍它，希望它有朝一日能如OpenFlow一样被世人所了解。特别感谢我的老师兼师兄杨帆老师一路的指导，他就是良师益友的代名词。&lt;/p&gt;
&lt;h3&gt;即兴戏剧&lt;/h3&gt;
&lt;p&gt;我有一个梦想，我想当一名导演，去演绎那些美好的故事。考上北邮之后发现北影就在边上，当时特别兴奋，还计划着要去蹭课。可惜由于种种原因，直到研究生，我才有机会到对面去学习。那是一个非常偶然的机会，我加入了北邮的即兴戏剧社，从此开始了一种特殊的生活经历。&lt;/p&gt;
&lt;p&gt;在大可老师悉心地教导下，我感受到了戏剧的魅力，尤其是&lt;a href="http://www.muzixing.com/pages/2015/11/14/ji-xing-xi-ju-yu-gou-tong-tong-xin.html"&gt;即兴戏剧&lt;/a&gt;的魅力。即兴戏剧可以锻炼人的倾听、专注、合作等能力，从而提高人的沟通能力和团队协作能力。此外，在学习即兴剧的过程中也认识了许多好玩的小伙伴。学习即兴戏剧给我本来平淡的生活添加了好多乐趣，衷心地觉得自己很幸运，可以遇到即兴戏剧。&lt;/p&gt;
&lt;p&gt;因为学习即兴戏剧，我认识了好多志同道合的人。他们有的是来自中国音乐学院、北影、中传和北邮等学校的学生；有的是工作了的戏剧爱好者，也有在职读研的爱好者。能找到自己喜欢的事情，并投入时间去做真的是一件很幸福的事情。虽然以后我可能不会是一个演员，也当不了导演，但是这都不重要。我能在学习的过程中得到成就感，并感到快乐，这才是最重要的。&lt;/p&gt;
&lt;p&gt;跟着大可老师学习即兴戏剧还可以有机会去“开心麻花”，“万合天宜”等文化公司学习交流，感觉超级有意思。同时，我很迷恋站在舞台上表演的感觉。希望有一天我能站在更大的舞台，给观众们带来更多欢乐。这一年最大的收获，就是在学校专业知识之外有幸学习了即兴戏剧。&lt;/p&gt;
&lt;h3&gt;坚持阅读&lt;/h3&gt;
&lt;p&gt;在信息爆炸的互联网行业学习工作，能有时间安心地阅读是一件很难得而幸福的事情。过去的一年看完了《腾云：云计算和大数据时代网络技术解密》、《影响力》、《结网》、《即兴的智慧》和《浪潮之巅》，而目前正在看《从0到1》。坚持阅读非常艰难，但艰难的事情才体现其价值吧。以后想刷知乎的时候都看书就好了。希望我能一直坚持下去，每年都看好几本书。&lt;/p&gt;
&lt;h3&gt;情感&amp;amp;生活&lt;/h3&gt;
&lt;p&gt;情感和生活基本算满意吧。由于&lt;a href="http://www.sdnlab.com"&gt;SDNLAB&lt;/a&gt;给了我一个报酬还不错的远程兼职，每个月的收入起码够花了，所以经济压力相对不大，再次特此感谢SDNLAB。（打个硬广告，如此硬，硬得难以忘记：SDNLAB就是好啊，特别好啊，学SDN就来看SDNLAB啊。）&lt;/p&gt;
&lt;p&gt;北京空气污染太严重，感觉待不下去了。这一年身体变得好差，连呼吸都是痛苦了。也许我该回到温暖的南方。健身没有坚持下去，每个周偷懒就去一两次，这点做得很不好。&lt;/p&gt;
&lt;p&gt;感情方面，我和小丹丹小姐的感情还可以，希望继续美好下去。同时也希望小丹丹小姐越来越美，升职加薪，走上人生巅峰，成为人生赢家。（我不能公开虐狗！）&lt;/p&gt;
&lt;p&gt;在学生时代最后的一两年里，由于情感生活稳定，经济压力减小，个人发展还算顺利，未来计划明确，所以感觉压力没有那么大。愿我越来越幸福吧！&lt;/p&gt;
&lt;h2&gt;等风来&lt;/h2&gt;
&lt;p&gt;在等待的时候，我还做了很多其他准备工作。&lt;/p&gt;
&lt;p&gt;刚刚提交了北大光华“X Plan”的申请。如果能成功，就可以参加体验营，如果体验营表现好，就可以获得免面试资格，然后要等待多年达到资格之后，笔试达到资格才可以入学。非常麻烦，但是不试试怎么知道会不会成功。如果不成功也没什么，生活有许多机会，有意思的事情还很多，总有下一个我想做的事情的。&lt;/p&gt;
&lt;p&gt;前段阵子联系了未来的Mentor, 咨询了一些需要学习的内容，然后列了一个学习列表：Java Spring framework, Cassandra, Docker和OpenStack。希望这半年能做好准备，然后等风来，启航。&lt;/p&gt;
&lt;p&gt;这半年最重要的事情之一就是抓紧时间把论文发了，再尝试写一个小小的Survey，研究生阶段的所有计划和要求就都完成了。另一件事是自己的书需要抓紧推进了，希望6月份之前可以上架出版，不管销量如何，我需要的只是认真去对待这件事，以及期待一本属于我自己的书。&lt;/p&gt;
&lt;p&gt;过去的一年是等风来的一年，希望今年的我已经在追逐梦想的路上。&lt;/p&gt;
&lt;p&gt;等风来，等风来，少年已迫不及待。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 24 Feb 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-02-24:pages/2016/02/24/deng-feng-lai-chi-dao-de-2015nian-zhong-zong-jie.html</guid><category>life</category></item><item><title>SDN组网相关解决方案</title><link>http://www.muzixing.com/pages/2016/02/14/sdnzu-wang-xiang-guan-jie-jue-fang-an.html</link><description>&lt;p&gt;SDN作为一种新的网络架构，正被应用到越来越多的网络场景中。而网络的关键在于通信，如何使得SDN网络正常运行，并且能够和传统网络相互通信是SDN组网需要解决的基本问题。本文将介绍SDN组网相关解决方案中的数据平面到控制平面的组网解决方案、多SDN域组网解决方案和SDN网络与传统网络组网通信的解决方案。&lt;/p&gt;
&lt;h3&gt;SDN数据平面到控制平面组网&lt;/h3&gt;
&lt;p&gt;目前为止，在数据层面到控制到控制平面之间的组网方案主要有两大类：带外组网和带内(in-band)组网。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;带外（out-band）组网: &lt;/p&gt;
&lt;p&gt;数据平面到控制平面的控制数据通过专门的控制网络，而不经过数据平面转发，从而将数据平面的数据和控制平面数据隔离运行在两张独立的网络中。在带外组网方案中，每个交换机都有连接到控制平面的专属线路，而无需通过其他数据平面交换机转发。带外组网可以减少组网的难度和运维的难度。缺点是交换机多时，链路数量较多。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1f0ywymcw76j20b807s74v.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1. out-band组网方案&lt;/center&gt;   &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;带内（in-band）组网&lt;/p&gt;
&lt;p&gt;带内组网指的是控制数据和数据平面数据可以共享一个物理链路。即数据平面的有些交换机直连控制器，而其他的交换机的需要经过数据平面的链路才能到达控制器。非直交换机的控制数据需要通过数据平面的链路进行转发，并通过直连交换机转发到控制器。此种组网方式可以减少许多交换机到控制器的链路数量，但是配置带内组网比较麻烦，可靠性较低，维护成本也相对要高。
&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341gw1f0ywykadhmj20ay0763z2.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图2. in-band组网方案&lt;/center&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;多SDN域组网方案&lt;/h3&gt;
&lt;p&gt;当网络规模过大时，需要部署多域的组网方案。其中每个SDN域都由各自的控制平面控制。多域组网方案有水平架构和垂直架构两种。水平架构形式的多域组网方案中，域控制平面之间的关系是对等的。而在垂直架构中，则划分为域控制器层和超级控制器层。其中域控制器层负责自身域内的控制，超级控制器层负责管理域间的通信。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;水平架构&lt;/p&gt;
&lt;p&gt;实现水平架构的多域控制器的解决方案有分布式集群和东西向接口协议两种方式。部署分布式集群可以实现同类型多控制器实例的协同工作，无法支持异构控制器之间的协同工作。而东西向接口协议支持异构多域控制器之间的协同工作，其通过交换路由等信息实现多域网络通信。水平架构多域组网架构图如图3所示：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="muti-domains" src="http://ww1.sinaimg.cn/mw690/7f593341gw1f0yw1r2dg6j20gn0bg75y.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图3. 水平架构多域控制器组网方案&lt;/center&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;垂直架构&lt;/p&gt;
&lt;p&gt;垂直架构的多域控制器组网中超级控制器负责域间通信，而域控制器负责域内的通信。超级控制器相当于集中式的路由器，负责域间的通信，而每一个域由的域控制器模拟成独立的网络域，从而实现全局网络的管理。目前实现垂直架构的多域控制器协同工作的协议有Open eXchange 协议，其组网架构图如图4所示：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1f0yw1swzo4j20hi0bjdhj.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图4. 垂直架构多域控制器组网方案&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;SDN与传统互联&lt;/h3&gt;
&lt;p&gt;以上介绍的SDN组网仅仅是SDN网络部分的组网，而如何与其他传统网络相互通信则是本小节的内容。根据现实网关功能的设备种类不同，可以将组网方案分为传统设备组网方案和SDN设备组网方案两种。采用传统路由器作为网关方案中，SDN网络作为内部网络运营，而与其他网络通信的工作由传统路由器完成。
而采用SDN设备模拟网关时，由SDN控制器在边缘交换机上模拟网关行为，从而完成与其他域之间的网络通信。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;传统网络设备作网关&lt;/p&gt;
&lt;p&gt;在此方案中，采用传统路由器作为网络出口，由其完成和其他路由器之间的路由同步等工作。此方案中，复杂的网关功能由现网设备完成，而SDN控制器只需控制内部网络节点，从而降低了组网的难度，也提升了对内部网络的管控能力。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341gw1f0ywf1xbo2j20fg087q3r.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图5. 采用传统设备作网关方案&lt;/center&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SDN数据交换机作网关&lt;/p&gt;
&lt;p&gt;SDN设备解决方案中，SDN控制器需将边缘交换机模拟成一个路由器，如运行BGP协议的路由器，从而实现对传统路由协议的响应和支持，向外表现出路由器的特征，进而实现与互联网的互联互通。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341gw1f0yweyc3msj20f00ac3zc.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图6. 采用SDN设备模拟网关组网方案示意图&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;作为一名SDN初学者，在平时学习研究中，仅仅需要通过Mininet模拟则可以完成实验。而当真正部署SDN网络时，则需要考虑到很多实际问题，尤其是基本的组网方案。本文从数据平面到控制平面组网、SDN域之间组网和SDN域与传统网络之间组网三个方面简要介绍了SDN组网的相关解决方案。以此作为一个学习的总结，同时也希望这篇文章能帮助到有需要的研究人员。&lt;/p&gt;
&lt;p&gt;作者简介：&lt;/p&gt;
&lt;p&gt;李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 14 Feb 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-02-14:pages/2016/02/14/sdnzu-wang-xiang-guan-jie-jue-fang-an.html</guid><category>SDN</category></item><item><title>基于SDN的网络状态测量</title><link>http://www.muzixing.com/pages/2016/01/27/ji-yu-sdnde-wang-luo-zhuang-tai-ce-liang.html</link><description>&lt;p&gt;为了更好地管理和运行网络，非常有必要收集网络资源及其状态信息。在很多网络场景中，SDN控制器的决策都取决时延，带宽和拓扑等网络状态。在开发SDN应用的过程中，笔者总结了一些有用的网络状态测量的解决方案，可以为初学者在解决网络问题时提供一些启发。本文将主要介绍如何通过SDN控制器和OpenFlow协议来测量和收集网络中的时延、带宽以及拓扑状态等信息。&lt;/p&gt;
&lt;h3&gt;时延&lt;/h3&gt;
&lt;p&gt;时延的测试在终端会显得很容易，但是在交换机节点上测试时延就比较麻烦。在SDN中，可以通过一下步骤实现交换机之间链路的时延。&lt;/p&gt;
&lt;p&gt;（1）控制器向交换机A下发一个Packet_out报文。报文的数据段携带了任意一个约定好的协议报文，其报文的数据段携带了控制器下发报文时的时间戳。Packet_out报文的动作指示交换机将其泛洪或者转发到某端口。&lt;/p&gt;
&lt;p&gt;（2）交换机B收到了交换机A发送过来的数据包，无法匹配对应流表项，从而packet_in到控制器。控制器接收到这个数据包之后，和当下时间相减，得到时间差T1。其时间差约等于数据包从控制器到交换机A + 交换机A到交换机B + 交换机B到控制器的时延。&lt;/p&gt;
&lt;p&gt;（3）同理，控制器向交换机B发送一个类似的报文。然后控制器从交换机A收到Packet_in报文，记录下时间差T2。所以T1+T2=控制器到交换机A的RTT+控制器到交换机B的RTT+交换机A到交换机B的时延RTT。&lt;/p&gt;
&lt;p&gt;（4）控制器向交换机A和交换机B分别发送带有时间戳的Echo request。交换机收到之后即刻回复携带echo request时间戳的echo reply消息。所以控制器可以通过Echo reply的时间戳减去Echo reply携带的时间，从而得到对应交换机和控制器之间的RTT。通过这种方法测得控制器到交换机A,B的RTT分别为Ta，Tb。&lt;/p&gt;
&lt;p&gt;（5）T1+T2-Ta-Tb则得到交换机A到交换机B的RTT。假设往返时间一样，则交换机A到交换机B的链路时延为（T1+T2-Ta-Tb）/2。&lt;/p&gt;
&lt;p&gt;这种方法可以相对准确地测试到链路的实验，无法计算而忽略掉的部分时间是数据包在交换机中的处理时延。而这种简单的方法已经被申请专利了，不知道我这么写会不会有问题。&lt;/p&gt;
&lt;h3&gt;带宽&lt;/h3&gt;
&lt;p&gt;带宽数据是网络状态中的重要数据。在SDN网络中获取带宽可以通过OpenFlow协议，也可以通过第三方的测量软件获取数据，如sFlow。此处仅介绍如何通过OpenFlow协议来获取可用带宽。&lt;/p&gt;
&lt;p&gt;一条链路的带宽由两个端口的能力决定。所以我们可以通过获取端口的流量来得到链路的流量。OpenFlow协议中可以通过统计报文来获取端口、流表、流表项、组表和meter表的统计信息。以端口的统计信息为例，控制器通过周期下发Port statistics消息可以获得交换机端口的统计信息，其返回的统计消息格式如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ofp_port_stats&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="sr"&gt;/* Align to 64-bits. */&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;rx_packets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;/* Number of received packets. */&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;tx_packets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;/* Number of transmitted packets. */&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;rx_bytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;/* Number of received bytes. */&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;tx_bytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;/* Number of transmitted bytes. */&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;rx_dropped&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;/* Number of packets dropped by RX. */&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;tx_dropped&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;/* Number of packets dropped by TX. */&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;rx_errors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt; &lt;span class="n"&gt;Number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;
                         &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="n"&gt;specific&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;tx_errors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;/*&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;rx_frame_err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;rx_over_err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;rx_crc_err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;collisions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;duration_sec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;duration_nsec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从消息格式中可以发现可获取到收发的包数、字节数以及这个统计持续的时间。如果把两个不同时间的统计消息的字节数相减，再除以两个消息差也即统计时间差则可以得到统计流量速度。如果想得到剩余带宽则可以用端口最大带宽减去当前流量带宽，则得端口剩余带宽。同理，可以计算出对应流表项或者组表等的统计流量。基于以上计算出来的端口剩余带宽等数据，可为部署负载均衡等流量优化工程提高数据支撑。&lt;/p&gt;
&lt;h3&gt;拓扑&lt;/h3&gt;
&lt;p&gt;拓扑的发现比较容易理解。控制器通过将携带dpid+port_no信息的LLDP数据包从对应端口packet_out出去，然后LLDP数据包被对端交换机Packet_in到控制器，最后再由控制器结合Packet_in消息报头的DPID和in_port和LLDP报文中的DPID和Port_no从而得出一条链路信息。依次类推，控制器可以发现全部的链路信息，从而发现网络拓扑。&lt;/p&gt;
&lt;p&gt;以上的解决方案需要向每个端口下发packet_out，而此举会产生很多的OpenFlow消息，消耗OpenFlow channel宝贵的带宽资源。所以可以采用以下的优化结局方式。&lt;/p&gt;
&lt;p&gt;（1）收集swicth features时记录交换机上端口号和端口mac的对应关系。&lt;/p&gt;
&lt;p&gt;（2）弃用port_id的tlv，转而使用端口的mac作为端口的标记。&lt;/p&gt;
&lt;p&gt;（3）下发packet_out时，actions中添加对每个端口的OFPActionSetField(eth_src=port_infor.hw_addr)动作和OFPActionOutput(port_infor.port_no)动作,从而使得仅对交换机下发一个Packet_out就可以完成对所有的端口进行LLDP发送的操作。在每个端口发送数据之前，都需要对数据的src_mac地址置位成端口的mac地址。而控制器收到LLDP的packet_in时，通过mac和port_id的对应关系找出链路。通过这种方法可以将packet_out的数目大大降低，从每个端口发送端口数目N个降低至到1个。&lt;/p&gt;
&lt;p&gt;以上的解决方案仅能发现OpenFlow的网络，如果OpenFlow网络中间存在传统网络设备形成的子网络，则以上的解决方案将会将与传统网络连接的端口误认为是接入端口。&lt;/p&gt;
&lt;p&gt;这个问题可以通过LLDP和发送广播包的方式解决。首先通过LLDP发现OpenFlow的拓扑。然后再往“边缘端口”（与传统网络相连的端口此时也被认为是边缘端口）发送广播包，如果广播包从某一个交换机端口回来，则说明这个端口之外未知的地方还有一些交换设备，则证明这个端口不是主机的接入端口。但是传统设备如果不通过其他形式去发现还是无法发现具体的网络拓扑的信息。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;本文总结了在SDN网络中如何发现和测量网络的一些基础的信息，比如链路的时延和带宽，网络的拓扑等等。发现和测量这些基础的网络状态可以用于其他的网络决策，从而使得网络运行更加合理，进而提高资源利用率。以上部分内容以实现并公布，比如带宽测量模块可查看&lt;a href="http://www.muzixing.com/pages/2015/07/08/sdnwang-luo-gan-zhi-fu-wu-yu-zui-duan-lu-jing-ying-yong.html"&gt;《SDN网络感知服务与最短路径应用》&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;作者简介：
李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 27 Jan 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-01-27:pages/2016/01/27/ji-yu-sdnde-wang-luo-zhuang-tai-ce-liang.html</guid><category>measure</category></item><item><title>如何提升SDN可拓展性</title><link>http://www.muzixing.com/pages/2016/01/20/ru-he-ti-sheng-sdnke-tuo-zhan-xing.html</link><description>&lt;p&gt;Software Defined Networking是一种控制平面和数据平面分离的可编程的网络架构，目前已经有许多商业落地案例。在部署SDN时，往往会因SDN控制器性能不足而限制了SDN的可拓展性。因此SDN网络的规模往往不大。针对此问题，笔者在研究相关文献之后，总结了相关的解决方案，并通过本文来记录和分享。&lt;/p&gt;
&lt;h2&gt;解决方案&lt;/h2&gt;
&lt;p&gt;SDN分离了网络的控制平面和数据平面，而控制平面是SDN的大脑，其能力极大地影响着SDN网络的可拓展性。所以基本上，解决方案都是围绕如何给控制平面减压或者提升控制平面的能力来实现。根据控制器数目的不同，解决方案可以分为如下两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单控制器节点的性能拓展&lt;/li&gt;
&lt;li&gt;部署多控制器系统&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;单控制器节点的性能拓展&lt;/h2&gt;
&lt;p&gt;单控制器节点的性能拓展是最常见的方式之一，包括控制器采用多线程，负载下放等解决方案。多线程等解决方案属于软件开发范畴，不属于本文讨论范围。通过负载下放（offload）等方式可以降低网络对控制平面的依赖，减少控制平面的负载和压力，从而可以管理更多的交换机，进而提升SDN网络的可拓展性。DIFANE和DoveFlow就是典型的代表。&lt;/p&gt;
&lt;p&gt;DIFANE[1]是DIstributed Flow Architecture for Networked Enterprises的缩写。 在DIFANE架构中，其数据平面的所有数据均由数据平面完成，而控制器仅负责策略的计算，而不会直接响应Packet_in。其通过减轻控制平面的负载的方式，从而增强了SDN的可拓展性。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="difane" src="http://ww4.sinaimg.cn/mw690/7f593341jw1f03rkwo1qsj20r80g6djx.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1.DIFANE 架构图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;在DIFANE的数据平面，可以分为权威交换机（Authority switch）和包括Ingress switch在内的普通交换机的两类交换机。此外，DIFANE还定义了Cache rules、Authority rules和Partition rules三类流表项。其中Cache rules为从Authority switch上取回来的缓存规则，用于指导数据包的转发；Authority rules是控制器预计算下发的规则，可将其分发给Ingress switch，并作为Cache rules, 其仅存在于Authority switch中。Partition rules用于指导交换机将无法匹配到Cache rules的数据包转向指定的Authority switch，优先级最低。Authority switch具有一定的处理数据的能力，可以运行链路协议等基本协议，可实现DIFANE的数据层面需求。&lt;/p&gt;
&lt;p&gt;当网络上线时，控制器通过收集网络的拓扑信息和主机接入位置信息等计算出Authority rules并分发到对应的Authority switch中。此外，控制器还需要完成粗粒度的Partition rules的计算和下发。Partition rules是由网络拓扑的具体情况计算出来的粗粒度规则，其告知Ingress switch将无法匹配Cache rules的数据包应该转发到哪一个Authority switch。当第一个packet到达Ingress switch时，不会选择上报controller，而是会匹配到低优先级的Partition rules，并转发到Authority switch。Authority switch负责将其转发到对应的Egress switch。此外，Authority switch还会将对应的Authority rules推送并安装到Ingress switch中，作为其Cache rules。之后的packet就可以匹配Cache rules，然后直接转发到Egress switch，而不需要转发给Authority switch。在DIFANE架构中，控制器则负责主动预先计算规则并下发，而网络事件的被动响应则由数据平面的Authority switch完成。&lt;/p&gt;
&lt;p&gt;DIFANE的设计使得所有的数据平面的数据都由数据平面处理，而不是缓存在交换机队列中，再发送给控制器处理。此举使得络首包的延迟变小，同时也大大降低了控制器的压力，进而可以管理更大的网络。不过这样的解决方案难度较大，需要解决许多问题。比如Cache rules的流表项过期之后如何处理，主机移动带来的策略变化以及拓扑变化带来的策略转变等问题。虽然DIFANE确实降低了控制器的压力，拓展了网络规模，但是其仅在一定程度上提升了可拓展性，无法大规模地扩大网络规模，难以从根本上解决可拓展性的问题。&lt;/p&gt;
&lt;p&gt;同样的，为解决OpenFlow处理首包所带来的性能不足的问题，DoveFlow[2]也设计了自己的解决方案。DevoFlow同样主张尽可能将包括流表的安装，统计信息的收集等IO高消耗的业务下放到交换机上，由交换机负责完成。而控制器负责高级的策略计算和下发工作。不过论文仅完成了模型建立和仿真分析，并没有实际部署。&lt;/p&gt;
&lt;p&gt;将控制器的部分高IO消耗的业务下放到数据平面来处理，是解决SDN可拓展性问题的主要思路之一。这种方法可以实现不仅可以提升可拓展性，还可以降低网络延迟。不过这样的解决方案难度相对也比较大。&lt;/p&gt;
&lt;h2&gt;多控制器系统&lt;/h2&gt;
&lt;p&gt;除了通过下放负载来减轻控制器压力来提高可拓展性这种解决思路以外，更普遍的解决思路是通过部署多控制器系统来共同实现网络的管理。而根据控制器系统中控制器的种类异同可以将方案分为分布式控制器和东西向接口协议两种解决方案。&lt;/p&gt;
&lt;h3&gt;分布式控制器&lt;/h3&gt;
&lt;p&gt;较为出名的分布式控制器，当属HyperFlow[3]系统, Google的Onix[4]以及开源控制器ONOS[5]。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HyperFlow&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;HyperFlow是一个基于事件的OpenFlow分布式控制平台，可以实现多控制器之间协同工作。部署HyperFlow分布式系统的多控制器实例维护一个共同的全局网络视图。在管理本地网络时，控制器无需和其他节点交互而直接进行网络管理，从而实现快速地响应Packet_in请求。同时HyperFlow并没有改变OpenFlow的协议内容，也不会影响已有的应用运行。与部署DHT不同，HyperFlow不需要改变控制器本身的存储。在数据同步方面也是通过直接推送方式将信息直接推送到其他节点。&lt;/p&gt;
&lt;p&gt;每个HyperFlow节点都维护着全局的网络视图，看起来好像管理了全局网络一样，但是只能管理本地的网络。交换机可配置多控制器，从而提供High Availability。一旦某节点的网络视图发生改变，这个事件将会发布给所有订阅它的节点。而其他节点将需要重播(replay)所有已发布的事件来重新构建网络视图，这点将产生大量的同步数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Onix和ONOS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Onix是google的分布式控制器，其在所有节点之间维护了全局网络视图，实现分布式控制。此外，还定义了一套API，用于定义具体的同步操作。面对不同的场景，比如不同域之间的通信，可制定具体的同步数据细节来保障网络的安全和隐私。Onix支持两种形式的网络拓展：Partition(分区)， Aggregation(聚合)。&lt;/p&gt;
&lt;p&gt;当网络规模增长到一定程度时，一个控制器无法应付全部的网络状态和流表状态的存储，内存上出现瓶颈。那么将网络划分为分别由多个控制器管理的子网络可以解决这个问题。所有控制器都共同维持一个网络状态的数据，但是流表状态由本地控制器管理，且本地控制器可以在全局拓扑上计算路径。&lt;/p&gt;
&lt;p&gt;当网络继续增大时，一个控制器在全局网络上计算路径就显得有些吃力了，CPU资源成为了新的瓶颈。所以可以把多个子网聚合成一个逻辑节点。而不同逻辑节点之间由另一个管理全局流量的Onix控制器管理，从而实现更大网络的管理。举例如，一个很大的校园网里面，每栋大楼都是由一个Onix管理的子网络。多栋大楼组成的网络可以被抽象成一个逻辑节点，由管理校际的Onix来管理逻辑节点组成的逻辑网络，从而实现大规模网络的管理。&lt;/p&gt;
&lt;p&gt;此外Onix也针对数据一致性等方面做了相关的部署。然而由于分布式控制器本身数据同步数据量较大，其需要比较充裕的网络带宽。尽管如此，Onix还是在Google的数据中心中起到了很大的作用。&lt;/p&gt;
&lt;p&gt;ONOS是一款开源的分布式控制器。与其他分布式控制器一样，ONOS也构建了全局的拓扑，控制器实例也是独立管理网络。此外,ONOS也可以实现控制器之间的负载均衡。在ONOS的实现过程中，对于不同的数据的分布式存储是不同的。对于分布式集群的master/slaver的关系等信息采用的是Hazelcast来存储，而Device,link等内容则是通过Gossip协议来直接发送。而且发送形式是单播，而非在节点之间组播。&lt;/p&gt;
&lt;p&gt;ONOS作为一款新兴的分布式控制器，在可拓展性方面还是相对不错的。但是分布式系统的心跳包等大量数据需要消耗大量带宽，使其可能难以适应链路质量不足的场景。&lt;/p&gt;
&lt;h3&gt;东西向协议&lt;/h3&gt;
&lt;p&gt;本质上HyperFlow也可以部署在异构的控制器上从而实现多控制协同工作。不过异构控制器部分，解决方案的思路主要是通过协议来消除通信终端的差异性,而HyperFlow并没有强调这一点。目前已有的可用于异构控制器之间的东西向协议有SDNi[6]和West-East[7] Bridge协议。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SDNi&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SDNi是华为提出的一种用于处理SDN域之间通信的协议。在其提交的草案中，定义了SDN域的概念和SDNi如何帮助域之间通信。目前SDNi已经在开源控制器OpenDaylight[8]上作为应用实现。SDNi需要在控制器之间交互Reachability、Flow setup/tear-down/update请求和包括带宽，QoS和延迟等Capability信息。SDNi的数据交换可以基于SIP或者BGP协议实现，如OpenDaylight中就是基于BGP协议实现的。基于SDNi可以实现异构控制器协同工作，实现大规模网络的管理，实现跨域流量优化等应用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;West-East Bridge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;West-East Bridge协议也是一种支持异构控制器协同工作的协议。其同样也是通过订阅/发布机制来完成数据的分发。当网络视图发生变化时，该事件将会被发布到所有订阅其数据的节点。为保证数据的一致性，其节点之间为全连接关系。此外，West-East Bridge还设计了虚拟的网络视图，可以满足某些SDN域对于安全和隐私的需求。&lt;/p&gt;
&lt;h3&gt;其他解决方式&lt;/h3&gt;
&lt;p&gt;除了以上列举的解决方案外，还有许多其他的解决方案，但是笔者无法简单地将其归类为以上两种方案，所以在此部分介绍。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kandoo&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第一种解决方案中提到减轻控制器负载可以提升SDN的可拓展性。而第一种方案是通过把相关高IO消耗的业务下放到了数据平面的交换机上。但是这种方式需要对交换机进行修改，其难度较大。所以在控制平面做文章则成为另一种可选的方案。Kandoo就是一种控制平面的解决方案。Kandoo[9]是一种分层式的控制平面，由本地控制器和根控制器组成。其中本地控制器对网络的信息并不了解，仅完成本地的业务。而根控制器负责完成网络范围内的业务请求，如路由等等。本地控制器需要运行APP detect应用来检测大象流等需要上报给根控制器的报文，而根控制器需要运行APP reroute应用来完成网络范围内的业务部署。在根控制器完成计算之后，发送给本地控制器，由本地控制器完成流表项的安装。即本地控制器本质上只是一个代理，完成了大部分的高发频率的本地网络事件，而根控制器完成网络范围内的业务响应。从而将全局网络事件分摊到多个本地控制器上，降低对IO性能的要求，从而提升SDN可拓展性。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="kandoo" src="http://ww4.sinaimg.cn/mw690/7f593341jw1f041blt59nj20ii0a675w.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图2.Kandoo架构图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DISCO&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;DISCO[10]本质上可以理解为一种和SDNi类似的东西向协议，但是由于论文中只字不提东西向协议，所以笔者只能将其放在这部分了。DISCO通过AMQP协议实现了控制器之间的数据交换，来实现控制器之间的协同，实现跨域业务的部署，从而增强了SDN的可拓展性。其实现原理和SDNi，West-East Bridge基本一样，不再赘述。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;目前针对SDN可拓展性的研究已经非常火热，对应的解决方案也已经有不少。从以上的解决方案中我们可以总结出来可以从把负载从控制器上offload到数据平面和拓展控制平面两种大的解决思路。在控制平面能力拓展方面，Google的Onix确实是做得最全面的，包括了是网络的分区和聚合。基本上目前SDN可扩展性方面的研究已经有了一定的基础。随着SDN的发展，相信后续SDN的可拓展性方面或者说东西向方面的内容将会有更多的研究成果出现，从而推动SDN东西向和可拓展性方面的发展进程，进而带来一个更大的SDN网络。&lt;/p&gt;
&lt;h3&gt;参考文献&lt;/h3&gt;
&lt;p&gt;[1] Curtis A R, Mogul J C, Tourrilhes J, et al. DevoFlow: Scaling flow management for high-performance networks[C]//ACM SIGCOMM Computer Communication Review. ACM, 2011, 41(4): 254-265.&lt;/p&gt;
&lt;p&gt;[2] Curtis A R, Mogul J C, Tourrilhes J, et al. DevoFlow: Scaling flow management for high-performance networks[C]//ACM SIGCOMM Computer Communication Review. ACM, 2011, 41(4): 254-265.&lt;/p&gt;
&lt;p&gt;[3] Tootoonchian A, Ganjali Y. HyperFlow: A distributed control plane for OpenFlow[C]//Proceedings of the 2010 internet network management conference on Research on enterprise networking. USENIX Association, 2010: 3-3.&lt;/p&gt;
&lt;p&gt;[4] Koponen T, Casado M, Gude N, et al. Onix: A Distributed Control Platform for Large-scale Production Networks[C]//OSDI. 2010, 10: 1-6.&lt;/p&gt;
&lt;p&gt;[5] Berde P, Gerola M, Hart J, et al. ONOS: towards an open, distributed SDN OS[C]//Proceedings of the third workshop on Hot topics in software defined networking. ACM, 2014: 1-6.&lt;/p&gt;
&lt;p&gt;[6] Yin, H., Xie, H., Tsou, T., Lopez, D., Aranda, P.A., Sidi, R.: SDNi: A message exchange protocol for software defined networks (SDNs) across multiple domains. IRTF InternetDraft (2012)&lt;/p&gt;
&lt;p&gt;[7] Lin P, Bi J, Chen Z, et al. WE-bridge: West-East Bridge for SDN inter-domain network peering[C]//Computer Communications Workshops (INFOCOM WKSHPS), 2014 IEEE Conference on. IEEE, 2014: 111-112.&lt;/p&gt;
&lt;p&gt;[8] https://wiki.opendaylight.org/view/ODL-SDNi_App:Main&lt;/p&gt;
&lt;p&gt;[9] Hassas Yeganeh S, Ganjali Y. Kandoo: a framework for efficient and scalable offloading of control applications[C]//Proceedings of the first workshop on Hot topics in software defined networks. ACM, 2012: 19-24.&lt;/p&gt;
&lt;p&gt;[10] Phemius K, Bouet M, Leguay J. Disco: Distributed multi-domain sdn controllers[C]//Network Operations and Management Symposium (NOMS), 2014 IEEE. IEEE, 2014: 1-4.&lt;/p&gt;
&lt;p&gt;作者简介：
李呈，2014/09-至今，北京邮电大学信息与通信工程学院未来网络理论与应用实验室（FNL实验室）攻读硕士研究生。&lt;/p&gt;
&lt;p&gt;个人博客：http://www.muzixing.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 20 Jan 2016 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2016-01-20:pages/2016/01/20/ru-he-ti-sheng-sdnke-tuo-zhan-xing.html</guid><category>SDN</category><category>scalability</category></item><item><title>SDN与网络虚拟化</title><link>http://www.muzixing.com/pages/2015/12/29/sdnyu-wang-luo-xu-ni-hua.html</link><description>&lt;p&gt;网络虚拟化是一种重要的网络技术，该技术可在物理网络上虚拟多个相互隔离的虚拟网络，从而使得不同用户之间使用独立的网络资源切片，从而提高网络资源利用率，实现弹性的网络。SDN的出现使得网络虚拟化的实现更加灵活和高效，同时网络虚拟化也成为SDN应用中的重量级应用。本文将介绍SDN与网络虚拟化的关系以及通过SDN实现网络虚拟化的方法，其中第二部分内容将从虚拟化平台，网络资源虚拟化和网络隔离三个方面介绍。&lt;/p&gt;
&lt;h2&gt;SDN与网络虚拟化&lt;/h2&gt;
&lt;p&gt;由于早期成功的的SDN方案中网络虚拟化案例较多，有的读者可能会认为SDN和网络虚拟化是同一个层面的，然而这是一个错误的说法。SDN不是网络虚拟化，网络虚拟化也不是SDN。SDN是一种集中控制的网络架构，可将网络划分为数据层面和控制层面。而网络虚拟化是一种网络技术，可以在物理拓扑上创建虚拟网络。传统的网络虚拟化部署需要手动逐跳部署，其效率低下，人力成本很高。而在数据中心等场景中，为实现快速部署和动态调整，必须使用自动化的业务部署。SDN的出现给网络虚拟化业务部署提供了新的解决方案。通过集中控制的方式，网络管理员可以通过控制器的API来编写程序，从而实现自动化的业务部署，大大缩短业务部署周期，同时也实现随需动态调整。&lt;/p&gt;
&lt;p&gt;随着IaaS的发展，数据中心网络对网络虚拟化技术的需求将会越来越强烈。SDN出现不久后，SDN初创公司Nicira就开发了网络虚拟化产品NVP(Network Virtualization Platform)。Nicira被VMware收购之后，VMware结合NVP和自己的产品vCloud Networking and Security (vCNS)，推出了VMware的网络虚拟化和安全产品NSX。NSX可以为数据中心提供软件定义化的网络虚拟化服务。由于网络虚拟化是SDN早期少数几个可以落地的应用，所以大众很容易将网络虚拟化和SDN弄混淆。正如前面所说，网络虚拟化只是一种网络技术，而基于SDN的网络架构可以更容易地实现网络虚拟化。&lt;/p&gt;
&lt;h2&gt;SDN实现网络虚拟化&lt;/h2&gt;
&lt;p&gt;通过SDN实现网络虚拟化需要完成物理网络管理，网络资源虚拟化和网络隔离三部分工作。而这三部分内容往往通过专门的中间层软件完成，我们称之为网络虚拟化平台。虚拟化平台需要完成物理网络的管理和抽象虚拟化，并分别提供给不同的租户。此外，虚拟化平台还应该实现不同租户之间的相互隔离，保证不同租户互不影响。虚拟化平台的存在使得租户无法感知到网络虚拟化的存在，也即虚拟化平台可实现用户透明的网络虚拟化。&lt;/p&gt;
&lt;h3&gt;虚拟化平台&lt;/h3&gt;
&lt;p&gt;虚拟化平台是介于数据网络拓扑和租户控制器之间的中间层。面向数据平面，虚拟化平面就是控制器，而面向租户控制器，虚拟化平台就是数据平面。所以虚拟化平台本质上具有数据平面和控制层面两种属性。在虚拟化的核心层，虚拟化平台需要完成物理网络资源到虚拟资源的虚拟化映射过程。面向租户控制器，虚拟化平台充当数据平面角色，将模拟出来的虚拟网络呈现给租户控制器。从租户控制器上往下看，只能看到属于自己的虚拟网络，而并不了解真实的物理网络。而在数据层面的角度看，虚拟化平台就是控制器，而交换机并不知道虚拟平面的存在。所以虚拟化平台的存在实现了面向租户和面向底层网络的透明虚拟化，其管理全部的物理网络拓扑，并向租户提供隔离的虚拟网络。
&lt;center&gt;&lt;img alt="netwrok virtualization" src="http://ww2.sinaimg.cn/mw690/7f593341jw1ezc2dspu9wj20h20cetay.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图 2 .网络虚拟化平台示意图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;虚拟化平台不仅可以实现物理拓扑到虚拟拓扑“一对一”的映射，也应该能实现物理拓扑“多对一”的映射。而由于租户网络无法独占物理平面的交换机，所以本质上虚拟网络实现了“一虚多”和“多虚一”的虚拟化。此处的“一虚多”是指单个物理交换机可以虚拟映射成多个虚拟租户网中的逻辑交换机，从而被不同的租户共享；“多虚一”是指多个物理交换机和链路资源被虚拟成一个大型的逻辑交换机。即租户眼中的一个交换机可能在物理上由多个物理交换机连接而成。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1ezc2dtgewxj20ef07yq3g.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图3 .单虚拟节点映射到多物理节点&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;网络资源虚拟化&lt;/h3&gt;
&lt;p&gt;为实现网络虚拟化，虚拟化平台需要对物理网络资源进行抽象虚拟化，其中包括拓扑虚拟化，节点资源虚拟化和链路资源虚拟化[1]。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;拓扑虚拟化&lt;/strong&gt;
拓扑虚拟化是网络虚拟化平台最基本的功能。虚拟平台需要完成租户虚网中的虚拟节点和虚拟链路到物理节点和链路的映射。其中包括“一对一”和“一对多”的映射。“一对一”的映射中，一个虚拟节点将会映射成一个物理节点，同理虚拟链路也是。而在“一对多”的映射中，一个虚拟节点可以映射成由多个连接在一起的物理节点；一条逻辑链路也可能映射成由链接在一起的多条链路。而对于物理节点而言，一个物理节点可以被多个逻辑节点映射。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;节点资源虚拟化&lt;/strong&gt;
节点资源的虚拟化包括对节点Flow tables（流表）、CPU等资源的抽象虚拟化。流表资源本身是交换机节点的稀缺资源，如果能对其进行虚拟化，然后由虚拟化平台对其进行分配，分配给不同的租户，那么就可以实现不同租户对节点资源使用的分配和限制。拓扑抽象仅仅完成了虚拟节点到物理节点的映射，而没有规定不同用户/租户对物理节点资源使用的分配情况。若希望进行更细粒度的网络虚拟化，节点资源虚拟化非常有必要。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;链路资源虚拟化&lt;/strong&gt;
和节点资源一样，链路资源也是网络中重要的资源，而拓扑抽象并没有规定某些用户可使用的链路资源的多少。所以在进行更细粒度的虚拟化时，有必要对链路资源进行虚拟化，从而实现链路资源的合理分配。可被抽象虚拟化的链路资源包括租户可使用的带宽以及端口的队列资源等等。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;网络隔离&lt;/h3&gt;
&lt;p&gt;网络资源虚拟化仅仅完成了物理资源到虚拟资源的抽象过程，为实现完全的网络虚拟化，还需要对不同的租户提供隔离的网络资源。网络隔离需要对SDN的控制平面和数据平面进行隔离，从而保证不同租户控制器之间互补干扰，不同虚网之间彼此隔离。此外，为了满足用户对地址空间自定义的需求，虚拟化平台还需要对网络地址进行虚拟化。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;控制面隔离&lt;/strong&gt;
控制器的性能对SDN整体的性能产生极大的影响，所以虚拟化平台需保证租户的控制器在运行时不受其他租户控制器的影响，保证租户对虚拟化平台资源的使用。虚拟化平台在连接租户控制器时需保证该进程可以得到一定的资源保障，比如CPU资源。而虚拟化平台本身所处的位置就可以轻易实现租户的控制器之间的相互隔离。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数据面隔离&lt;/strong&gt;
数据面的资源包括节点的CPU、Flow Tables等资源以及链路的带宽，端口的队列资源等。为保证各个租户的正常使用，需对数据面的资源进行相应的隔离，从而保证租户的资源不被其他租户所占据。若在数据面上不进行资源的隔离，则会产生租户数据在数据面上的竞争，从而无法保障租户对网络资源的需求，所以很有必要在数据面对资源进行隔离。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;地址隔离&lt;/strong&gt;
为使租户能在自己的虚拟租户网中任意使用地址，虚拟化平台需要完成地址的隔离。实现地址隔离主要通过地址映射来完成。租户可任意定制地址空间，而这些地址对于虚拟化平台而言是面向租户的虚拟地址。虚拟化平台在转发租户控制器南向协议报文时，需要将虚拟地址转化成全网唯一的物理地址。租户的服务器的地址在发送到接入交换机时就会被修改成物理地址，然后数据包的转发会基于修改之后的物理地址进行转发。当数据到达租户目的地址主机出端口，控制器需将地址转换成原来租户设定的地址，从而完成地址的虚拟化映射。地址的虚拟化映射使得租户可以使用完全的地址空间，可以使用任意的FlowSpace（流空间：流表匹配项所组成的多维空间），而面向物理层面则实现了地址的隔离，使得不同的租户使用特定的物理地址，数据之间互不干扰。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;本文介绍了SDN与网络虚拟化的关系以及如何通过SDN实现网络虚拟化。第二部分内容通过介绍网络虚拟化平台，网络资源虚拟化，网络隔离等三个方面来介绍如何通过SDN实现网络虚拟化。随着SDN和网络虚拟化的发展，更多基于SDN的网络虚拟化案例将会诞生，从而为用户提供更灵活的网络服务。后续将有文章介绍基于SDN的网络虚拟化技术的产品和应用案例，敬请期待。&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;[1] Blenk A, Basta A, Reisslein M, et al. Survey on Network Virtualization Hypervisors for Software Defined Networking[J]. 2015.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 29 Dec 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-12-29:pages/2015/12/29/sdnyu-wang-luo-xu-ni-hua.html</guid><category>network virtualization</category></item><item><title>基于流量的SDN最短路径转发应用</title><link>http://www.muzixing.com/pages/2015/11/30/ji-yu-liu-liang-de-sdnzui-duan-lu-jing-zhuan-fa-ying-yong.html</link><description>&lt;p&gt;网络的转发是通信的基本功能，其完成信息在网络中传递，实现有序的数据交换。通过SDN控制器的集中控制，可以轻松实现基础的转发算法有二层MAC学习转发和基于跳数的最短路径算法。然而，网络跳数并不是决定路径优劣的唯一状态。除了跳数以外，还有带宽，时延等标准。本文将介绍如何通过SDN控制器Ryu开发基于流量的最短路径转发应用。&lt;/p&gt;
&lt;h3&gt;Forwarding Algorithm&lt;/h3&gt;
&lt;p&gt;目前基于流量的路由算法基本的解决思路有两种：&lt;/p&gt;
&lt;p&gt;(1) 首先基于跳数计算最优K条路径，然后在这些路径中选择可用带宽最大的路径。&lt;/p&gt;
&lt;p&gt;(2) 首先基于跳数计算最优路径，归一化路径的评价分数，然后基于流量计算最优路径，归一化基于带宽的评价；设置跳数和带宽的权重，对基于跳数和带宽的评分求其加权总和；按照加权求和值降序排序，取前K条作为最优评价路径。&lt;/p&gt;
&lt;p&gt;本文以第一种算法为例，介绍基于网络流量的最短路径转发应用开发。第二种算法基于前者的基础修改即可完成。&lt;/p&gt;
&lt;h3&gt;Network Awareness&lt;/h3&gt;
&lt;p&gt;首先我们需要编写一个网络感知应用，用于发现网络的资源，包括节点，链路，终端主机等。并根据拓扑信息计算基于条数的最短路径。开发此应用基本步骤如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建继承app_manager.RyuApp的应用network_awareness&lt;/li&gt;
&lt;li&gt;从topology.switches获取拓扑信息，包括交换机节点信息，链路信息&lt;/li&gt;
&lt;li&gt;使用Networkx 创建拓扑图的对象，用于存储网络拓扑&lt;/li&gt;
&lt;li&gt;使用Networkx的函数all_simple_paths(G, source, target, cutoff=None)计算K条最优路径并存储，该函数实现了&lt;a href="https://en.wikipedia.org/wiki/Yen%27s_algorithm"&gt;Yen's algorithm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例代码可由&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_aware/network_aware.py"&gt;muzixing/ryu/network_awareness&lt;/a&gt;获取。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note that:&lt;/strong&gt; 以上的示例代码中，拓扑信息的存储并没有使用networkx，所以读者需要独立完成基于networkx的存储和算法调用部分。&lt;/p&gt;
&lt;h3&gt;Network Monitor&lt;/h3&gt;
&lt;p&gt;第二个应用是网络流量监控应用。网络流量监控应用完成网络流量的实时监控，计算出实时的流量统计数据。基于本应用的数据，可以完成转发算法的第二部分内容。示例代码可由&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_aware/network_monitor.py"&gt;muzixing/ryu/network_monitor&lt;/a&gt;获取。&lt;/p&gt;
&lt;p&gt;为了让其他模块获取到最新的流量信息，可在Ryu中自定义事件，具体教程请查看&lt;a href="http://www.muzixing.com/pages/2015/11/20/ji-yu-ryuda-zao-zi-ding-yi-kong-zhi-qi.html"&gt;《基于Ryu打造自定义控制器》&lt;/a&gt;的自定义事件部分内容。不定义事件的情况下，需要将此模块作为新模块的CONTEXT。详情可阅读&lt;a href="http://www.muzixing.com/pages/2015/09/08/ryumo-kuai-jian-tong-xin-ji-zhi-fen-xi.html"&gt;《Ryu:模块间通信机制分析》&lt;/a&gt;的相关内容。&lt;/p&gt;
&lt;h3&gt;Forwarding Application&lt;/h3&gt;
&lt;p&gt;基于以上两个模块的数据，转发应用模块需要完成如下几个步骤，从而完成基于流量的最优路径转发。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;获取network awareness和network monitor的数据&lt;/li&gt;
&lt;li&gt;将network monitor的数据整合到networkx存储的网络拓扑信息中&lt;/li&gt;
&lt;li&gt;比较最短K条路径中各路径的剩余带宽，选择最优路径，剩余路径为备份路径和逃生路径&lt;/li&gt;
&lt;li&gt;基于路径信息，安装流表项&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;整合流量信息代码示例代码如下, 其中，link2port为链路信息，bw_dict为network monitor模块的流量数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_bw_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;link2port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bw_dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;link2port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src_dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst_dpid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link2port&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;src_dpid&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bw_dict&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;dst_dpid&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bw_dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;bw_src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bw_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src_dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;src_port&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;bw_dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bw_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dst_dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst_port&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src_dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst_dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;bandwidth&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bw_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bw_dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src_dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst_dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;bandwidth&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;获取最短K条路径函数示例代码如下所示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;k_shortest_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;path_generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shortest_simple_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;weight&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;path_generator&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;基于流量的最优路径比较算法示例代码如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;band_width_compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;best_paths&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;best_paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
                &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;max_bw_of_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;best_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="n"&gt;min_bw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt;
                &lt;span class="n"&gt;min_bw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_min_bw_of_links&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_bw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;min_bw&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max_bw_of_paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;max_bw_of_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;min_bw&lt;/span&gt;
                    &lt;span class="n"&gt;best_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;

            &lt;span class="n"&gt;best_paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;best_path&lt;/span&gt;
            &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;max_bw_of_paths&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_bw_of_paths&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;best_paths&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;best_paths_by_bw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;best_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="c"&gt;# find ksp in graph.&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
        &lt;span class="n"&gt;best_paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
            &lt;span class="n"&gt;best_paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
            &lt;span class="n"&gt;path_generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k_shortest_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;path_generator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;
                &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="c"&gt;# find best path by comparing bandwidth.&lt;/span&gt;
    &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;best_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;band_width_compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;best_paths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;best_paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;安装流表项函数示例代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;install_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;link2port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;access_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;#39;&amp;#39;&amp;#39; path=[dpid1, dpid2, dpid3...]&lt;/span&gt;
&lt;span class="sd"&gt;        flow_info=(eth_type, src_ip, dst_ip, in_port)&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;PATH ERROR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="n"&gt;in_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;first_dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapaths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;first_dp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_LOCAL&lt;/span&gt;
    &lt;span class="n"&gt;reverse_flow_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_link2port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;link2port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;port_next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_link2port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;link2port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;port_next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;src_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;port_next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapaths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
                &lt;span class="n"&gt;send_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;send_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reverse_flow_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;# the last flow entry: tor -&amp;gt; host&lt;/span&gt;
        &lt;span class="n"&gt;last_dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapaths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="n"&gt;port_pair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_link2port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;link2port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;port_pair&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;src_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port_pair&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="n"&gt;dst_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;access_table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;send_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;send_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reverse_flow_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# the first flow entry&lt;/span&gt;
        &lt;span class="n"&gt;port_pair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_link2port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;link2port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;port_pair&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port_pair&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="n"&gt;send_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;send_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reverse_flow_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;send_packet_out&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;# ensure the first ping success.&lt;/span&gt;
        &lt;span class="c"&gt;# send_packet_out(last_dp, buffer_id, src_port, dst_port, data)&lt;/span&gt;
    &lt;span class="c"&gt;# src and dst on the same datapath&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;access_table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;send_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flow_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;send_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reverse_flow_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;send_packet_out&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;读者可以基于&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_aware/shortest_route.py"&gt;muzixing/ryu/shortest_route&lt;/a&gt;的代码进行修改。该代码是初始版本，质量欠佳，但是可以成功运行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note that:&lt;/strong&gt; 以上的代码均为示例代码，不可直接运行，完整版代码后续将发布。&lt;/p&gt;
&lt;h3&gt;Implementation and Test&lt;/h3&gt;
&lt;p&gt;启动network_awareness, network_monitor,和写好的forwarding模块，再启动一个简单拓扑连接到控制器Ryu。拓扑中，h1, h2到h39有两条路径：[1,2,4]和[1,3,4]。每条链路的最大带宽为500Mbits/s。然后xterm到h1, h2 和还h39，并在h39之上启动iperf服务端程序。先启动h1上的iperf客户端程序，向h39打流，等一个Monitor模块的周期之后，启动h2的iperf客户端程序，向h39打流。此操作的原因在于需要等待控制器获取流量信息和计算出最优路径。测试截图如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img alt="shortest forwarding" src="http://ww3.sinaimg.cn/mw690/7f593341jw1eyiwle5hubj20je09ngmo.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;上图左上为控制器的显示，路径选择了[1,2,4]和[1,3,4]。右侧的数据为h1的流量信息，左下为h2的流量信息，可以发现h1和h2各自独占一条路径，都打满了500Mbits。实验成功。&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;本文介绍了在Ryu控制器中开发基于流量的最优转发的流程。不过内容仅仅涉及了解决思路，实际工程代码的发布还需要等待一段时间。文中提到的第二种算法的解决方法与本文举例类似，仅需加上归一化数据，求加权求和评分步骤就可以完成新解决方案的工作。希望本文能给读者带来一些帮助。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Mon, 30 Nov 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-11-30:pages/2015/11/30/ji-yu-liu-liang-de-sdnzui-duan-lu-jing-zhuan-fa-ying-yong.html</guid><category>Traffic</category><category>SDN</category><category>forwarding</category></item><item><title>基于Ryu打造自定义控制器</title><link>http://www.muzixing.com/pages/2015/11/20/ji-yu-ryuda-zao-zi-ding-yi-kong-zhi-qi.html</link><description>&lt;p&gt;控制器是SDN网络中最重要的组成部分。在开发SDN应用时，需要基于某一个控制器开发，而大部分开源控制器都是一个框架或者平台，更多个性化的设置和应用需要开发者自己完成。对于开发者而言，一个自定义的控制器可以让控制器更加适配开发场景，发挥控制器最大的作用，提高开发效率。本篇文章将以Ryu为例，介绍如何修改Ryu源码，打造属于自己风格的自定义控制器。其内容包括自定义参数，事件，启动顺序，报文，协议和底层服务。&lt;/p&gt;
&lt;h3&gt;自定义参数&lt;/h3&gt;
&lt;p&gt;很多应用都会涉及相关参数的输入才能运行， 如OpenFlow协议的启动需要配置监听端口。在编写新应用时，需要获取相关参数的值来运行应用，所以需要开发应用时注册参数。目前已有的参数可以通过ryu-manager -h查看。而不同的应用注册的参数很可能名字一样，这就有可能发生冲突。为解决这个问题，Ryu采用了OpenStack的Oslo库，支持全局的命令注册和解析。Oslo支持全局的命令注册和解析，成功解除了命令冲突的难题，也大大降低了参数注册和解析的难度。注册新参数的方法很简单，只需要新建一个文件，然后按照如下案例完成注册，最后再在cmd/manager.py中import即可。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;

&lt;span class="n"&gt;CONF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;
&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_cli_opts&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StrOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;&amp;#39;milestone-argument&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;my test argument&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;milestone-server-port&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;milestone server port&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.base.app_manager&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AppManager&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.controller&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.milestone&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;milestone&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.topology&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;switches&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;通过python setup.py install重新安装Ryu之后即可通过ryu-manager -h来查看到新注册的命令。&lt;/p&gt;
&lt;h3&gt;自定义事件&lt;/h3&gt;
&lt;p&gt;Ryu的应用之间通信通过事件机制来完成。比如底层的协议解析模块解析报文之后，生成对应的报文事件，然后分发到各个监听该事件的监听函数。不过，目前为止事件类型还不够丰富，很多需要的信息还无法通过事件传递。比如网络流量监控服务监控到流量发生变化的事件之后，需要生成对应的事件。又比如OFPPacket_in事件包含了所有报文类型的数据，还可以根据触发Packet_in的数据的协议类型来定义细粒度的事件去分流，从而使得处理ARP报文的函数只接收ARP报文的Packet_in, 而不是全部接收到然后再去判断是否是不是ARP报文。以网络流量变化事件EventOXPTrafficStateChange为例，定义事件，生成事件和处理事件的流程如下：&lt;/p&gt;
&lt;p&gt;(1) 在controller/ofp_event.py中添加相关类描述：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EventOXPTrafficStateChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;traffic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventOXPTrafficStateChange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;traffic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;traffic&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;(2) 在相关应用中实例化事件，并通过OFPHandler模块的send_event_to_observers函数分发到指定函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oxp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOXPTrafficStateChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;traffic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;free_band_width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oxp_brick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookup_service_brick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;oxp_event&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oxp_brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_event_to_observers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;(3) 注册handler处理事件， 使用@set_ev_cls来注册handler监听该事件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nd"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oxp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOXPTrafficStateChange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reflesh_bw_best_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;free_band_width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;traffic&lt;/span&gt;
    &lt;span class="n"&gt;do_some_thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;free_band_width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;像Packet_in分流的定义可以参考以上的做法，将事件作为新事件的属性。也可以参考ofp_event模块中的修改类名的方式将类名修改，从而生成新的事件。&lt;/p&gt;
&lt;h3&gt;自定义启动顺序&lt;/h3&gt;
&lt;p&gt;Ryu关于Application的启动源码在cmd/manager.py文件中。main函数中完成了app_lists的赋值，即启动应用的顺序。若在Ryu开发了一个很重要的底层应用，需要在启动那个时启动，则可以将其加入app_lists中. 比如当milestone参数为1时，启动多个应用，否则仅启动基础应用的示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu.controller.ofp_handler&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;milestone&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;my_app_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;muzixing&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;milestone&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_app_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个自定义启动顺序一般情况下不需要修改，但是当开发的应用是非常重要的底层服务时，可能需要初始化就启动，所以也是非常关键的自定义内容之一。&lt;/p&gt;
&lt;h3&gt;自定义报文&lt;/h3&gt;
&lt;p&gt;在某些特定的场景中，需要对OpenFlow协议等协议进行报文拓展，从而完成新报文，新字段的测试工作。在Ryu中自定义OpenFlow报文的操作步骤如下：&lt;/p&gt;
&lt;p&gt;(1) 在对应版本的ofproto_v1_x.py中定义所有需要使用到的字段值，如最重要的报文类型，以定义一个名为milestone的报文为例，报文类型为25, 字段只有一个字符串类型的data, 可以用来放任何信息，长度为64bits。所以在文件中定义/声明 报文名字和类型的对应，报文的格式和长度，以便序列化和解析。Ryu使用struct对数据进行序列化和解析。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;OFPT_MILESTONE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
&lt;span class="n"&gt;OFP_MILESTONE_PACK_STR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;!8s&amp;#39;&lt;/span&gt;  &lt;span class="c"&gt;#定义报文格式&lt;/span&gt;
&lt;span class="n"&gt;OFP_MILESTONE_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;    &lt;span class="c"&gt;# 定义报文长度&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calcsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFP_MILESTONE_PACK_STR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;OFP_MILESTONE_SIZE&lt;/span&gt;&lt;span class="err"&gt;）&lt;/span&gt;  &lt;span class="c"&gt;# 检查长度是否正确&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;(2) 在对应版本的ofproto_v1_x_parser.py中添加对应报文类的定义，包括其解析方法和序列化方法。其中解析方法是一个类方法，在MsgBase中定义，派生类调用时需要使用类型来区分。序列化方法分为self._serialize_pre(), self._serialize_body()和self._serialize_header()三部分。派生类仅需完成self._serialize_body()的内容即可。值得注意的是，如果需要对报文进行除报头以外的解析，则必须在完成parser函数之后使用@_register_parser装饰符将对应函数和类名的映射关系加入到关系字典中，以便使用时查找，否则会报错。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nd"&gt;@_register_parser&lt;/span&gt;
&lt;span class="nd"&gt;@_set_msg_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPT_MILESTONE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OFPMILESTONE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MsgBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    MILESTONE message&lt;/span&gt;

&lt;span class="sd"&gt;    It is a test msg:www.muzixing.com&lt;/span&gt;
&lt;span class="sd"&gt;    ========== =========================================================&lt;/span&gt;
&lt;span class="sd"&gt;    Attribute  Description&lt;/span&gt;
&lt;span class="sd"&gt;    ========== =========================================================&lt;/span&gt;
&lt;span class="sd"&gt;    data       just some data.&lt;/span&gt;
&lt;span class="sd"&gt;    ========== =========================================================&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFPMILESTONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;

    &lt;span class="nd"&gt;@classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFPMILESTONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                          &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_HELLO_HEADER_SIZE&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_MILESTONE_PACK_STR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_serialize_body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;msg_pack_into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_MILESTONE_PACK_STR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;至此，自定义报文完成。关于struct模块的使用，以及OpenFlow协议代码的介绍可以参考另一篇文章&lt;a href="http://www.muzixing.com/pages/2015/07/24/ryuopenflowxie-yi-yuan-ma-fen-xi.html"&gt;《Ryu:OpenFlow协议源码分析》&lt;/a&gt;。重新安装Ryu即可将该报文写入到Ryu运行代码中，Ryu的事件机制会自动将这个报文生成对应的事件，进一步测试需要读者自行开发。&lt;/p&gt;
&lt;h3&gt;自定义协议&lt;/h3&gt;
&lt;p&gt;既然讲到自定义报文，那么继续提一下自定义协议。读者可以根据&lt;a href="http://www.muzixing.com/pages/2015/07/24/ryuopenflowxie-yi-yuan-ma-fen-xi.html"&gt;《Ryu:OpenFlow协议源码分析》&lt;/a&gt;提到的思路去模仿编写一个新的协议。底层的数据收发可以学习controller/controller.py, 协议定义可以学习ofproto目录下的一系列内容。各种需要自定义的细节，如自定义参数，自定义事件等都已经在上文提到。后续将会专门书写如何在Ryu中开发新协议，本文不再展开。&lt;/p&gt;
&lt;h3&gt;自定义服务&lt;/h3&gt;
&lt;p&gt;为了更好的开发应用，开发者应该开发一套底层的服务，为自己的进一步开发提供帮助。如ARP代理，DHCP服务，基础的网络资源感知服务等等。SDN集中式的优点很大在于拥有全局的视角，可以掌握全局的资源，从而进行全局最优的业务部署。所有业务的基础都基于对网络资源的感知，所以此处以网络资源感知为例。首先需要完成网络拓扑的最优路径的计算，此外处于某些场景的需求，需要收集网络流量状况的数据，从而完成基于流量的最优化决策。在此基础之上，完成基础的
最短路径转发应用，实现最基础的网络应用，为其他更高层次的应用开发和算法验证提供基本的服务支撑。由于篇幅限制，本文不加展开，详情可查看&lt;a href="http://www.muzixing.com/pages/2015/07/08/sdnwang-luo-gan-zhi-fu-wu-yu-zui-duan-lu-jing-ying-yong.html"&gt;《SDN网络感知服务与最短路径应用》&lt;/a&gt;。如果读者希望自己搭建一套底层服务，或者在笔者的基础之上加工，推荐使用networkx进行拓扑信息的存储。networkx提供了大量高效有用的函数，可以最大程度降低开发者在算法问题上的工作量。&lt;/p&gt;
&lt;p&gt;完成以上应用之后，可将其作为启动服务的一种，并通过参数来确定是否启动Ryu时启动这些业务。这些业务中涉及到的自定义事件，可用于与上层应用之间的通信，实现定制化的SDN控制器。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;本篇文章介绍了基于Ryu打造自定义控制器的内容，包括自定义参数，事件，启动顺序，报文，协议和服务。相信读者如果能根据应用场景进行深度自定义，可以很大程度上提升开发效率。关于自定义协议部分，后续会有更多文章介绍，敬请期待。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 20 Nov 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-11-20:pages/2015/11/20/ji-yu-ryuda-zao-zi-ding-yi-kong-zhi-qi.html</guid><category>Ryu</category></item><item><title>即兴戏剧与沟通／通信</title><link>http://www.muzixing.com/pages/2015/11/14/ji-xing-xi-ju-yu-gou-tong-tong-xin.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;即兴剧第一次出现在我的世界，是2015年3月份的时候。那时大学校园里春意盎然，遍地都是刚褪去厚重冬衣的男男女女，走在大道上欢声谈笑着，一转眼， 又到了一年一度交配的季节。我裹着厚厚的风衣，戴着黑框眼镜，面带微笑地欣赏着这美好时光。脚上那经历一个冬天磨砺的大靴子，在阳光的照耀下，也变得崭新了一些。&lt;/p&gt;
&lt;p&gt;“同学，参加即兴戏剧社吗？”一个甜美的声音吸引了我的注意。今天是社团招新的日子，校园大道上都是社团在摇旗呐喊，特别热闹。我寻声望去，却有点小失望。简陋的展台，只有一张桌子，几个穿着并不像演员的人在那里对着我憨笑，不免让我觉得有些不过去有些不给面子，有些尴尬。&lt;/p&gt;
&lt;p&gt;“什么是即兴剧啊？”我自小个性张扬，梦想是当一面导演，然后导演出传世的经典。在经过快20年的努力，饱读诗书十余载，学习街舞，在KTV当麦霸之后，终于成为了北京电影学院旁边的北京邮电大学的一个学通信工程的学生。高中就渴望着能考到一个离北影近一些的学校，这样平时就可以到对面蹭课了。虽然现实有些让人失望，但是梦想总是要有的，只要留住梦想的火种，总有一天，它就会熄灭。在熄灭之前，任何时候，我都做好了燎原的准备。不管是什么剧，抓住就是机会啊，学习，表演，签约，红地毯，当红影星，演员，我已经梦过很多次这样的场景了！&lt;/p&gt;
&lt;p&gt;“即兴剧就是没有台词，没有剧本的戏剧，每个人都可以学习，表演，非常好玩。” 一个并不怎么好听的男生的声音打断了我的思考。&lt;/p&gt;
&lt;p&gt;“迪斯坦斯，你最适合了，来啊，你来就当主演啊！ ”， 突然从男生后面钻出来了一个女生，原来是本科时候隔壁班的姑娘。“我们即兴戏剧社有北影的指导老师教我们学习表演，演得好的话，还可以到香港，澳门去参加即兴剧比赛，还有机会到美国去比赛！” 她拉着我的手，递给我一支笔，兴奋地介绍着。&lt;/p&gt;
&lt;p&gt;看起来有点意思啊，但是我这么有原则的人，怎么可能被这么几句话就给忽悠了呢，不过冲着主演，我还是扫码加入了他们的社团群。&lt;/p&gt;
&lt;p&gt;“学习，表演，签约，红地毯。。。”， 我大跨步离开了那个摊位，嘴角挂着一丝淡淡的微笑，发现周围的美女突然多了一些。&lt;/p&gt;
&lt;p&gt;周四晚上7点，我准时到了活动地点，当时是在零壹时光的二楼。到的时候，已经有几个人在哪里了，但是看起来并不像演员的样子，可能他们来北邮的原因也和我一样吧。不过老师确实非常有范儿，肚子很大，很有分量的角色，头发的装饰有些怪异的个性，这是我第一次对大可老师的印象，不是特别好。&lt;/p&gt;
&lt;p&gt;即兴戏剧是什么？ 大可老师先给我们看了一个视频，一个amazing的视频。&lt;/p&gt;
&lt;iframe height=498 width=510 src="http://player.youku.com/embed/XNzAzMzk4MDcy" frameborder=0 allowfullscreen&gt;&lt;/iframe&gt;

&lt;h3&gt;即兴戏剧是什么？&lt;/h3&gt;
&lt;p&gt;即兴戏剧是一种不经排练，没有台词，没有剧本，当下即兴表演的戏剧，主要有Short Form和Long Form两种形式，即短篇即兴和长篇即兴。最纯粹的即兴戏剧的表演的台词，动作，剧情，和人物都是和队友一起合作创造的。即兴戏剧远在古罗马时代即兴戏剧就已经出现，后来到18世纪左右，成为演员锻炼创造力的手段之一，目前在美国较为流行，在中国处于刚起步阶段，主要用于年轻演员的训练，团队建设，创造力培训等等领域。&lt;/p&gt;
&lt;p&gt;目前，美国已有的较为出名的即兴戏剧团队有Second City, UCB剧团等。喜剧秀方面也有很多节目，如《周六夜现场》，《猪凯瑞即兴秀》等，可以在Youtube上面搜索相关视频。（笔者孤陋寡闻，并不了解外面的世界，仅知道这两个）&lt;/p&gt;
&lt;p&gt;国内目前也有一些即兴戏剧团体，如沈飞老师的飞来即兴，开心麻花的即兴教学平台，还有北京大大小小许多个团队，如北京邮电大学即兴戏剧社。目前开心麻花团队正在开设学习班，邀请美国著名的即兴戏剧老师来授课，有兴趣的读者可以自行搜索。&lt;/p&gt;
&lt;h3&gt;即兴戏剧怎么演出来的&lt;/h3&gt;
&lt;p&gt;读者可能比较好奇，没有台词和剧本，如何在即可表演出一出精彩的戏剧的。其魔法就在于“say yes,and”, 直白地说就是支持别人。支持队友的信息，给出你的信息，随着改变而改变：“follow the flollower”相互支持，接受队友的信息，并添加更多的信息是支撑即兴演出的核心所在。&lt;/p&gt;
&lt;p&gt;如慕容翠花对欧阳铁柱说：“铁柱，你看，那盛开的菊花多么美，就像当年你送我的一样。”，如果欧阳铁柱回复：“哪里？那里什么都没有啊，你是不是傻!”, 后续的发展只能变成争论花是否存在，或者是翠花傻还是铁柱瞎，相当无聊。如果铁柱接受并承认这个事实，在此基础上添加信息，也就是“say yes, and..”，那么故事就很容易发展。铁柱做出陶醉姿势，回答翠花：“是啊，菊花好美啊，而且还有一个美女在欣赏，那背影和当年的你好像。”，在承认了花的事实之后，继续给出信息：有一个美女在欣赏，和翠花很像，接下来就有很多可能，很多剧情，如翠花吃醋，或者一起回忆美好过去都可以。这就是“yes, and”的魅力所在。&lt;/p&gt;
&lt;p&gt;关于即兴表演的队友合作，老师教授了5个点：Listen, Agree, Support, Error tolerance, Create。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Listen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Listen是表演的最基础的要求，倾听队友给出的信息是一切创造的基础。所以即兴戏剧在学习培训时会进行大量的关于倾听和专注的训练，这点是目前人们所缺乏的能力，后面会讲即兴剧对普通人的好处，此处不展开。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agree&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Agree建立在倾听的基础之上，倾听队友的信息，接受它并认同它为进一步创造创造条件，对应say yes。认同队友的信息，所有队友说的信息都是真的，然后去创造，创造规则为：如果一件事是真的，还有什么是真的。英文为：If something is true, what else can be true. 比如观众给的地点是装修华丽，高端大气的养猪场前面。在这个场景下，翠花动情地对铁柱说：“铁柱， 我们养的猪终于长大了，一定能买好价钱。”， 铁柱应该接受仔细倾听翠花的信息，然后进行“分想”， 提取出其中可以继续“联想”的内容，继续创造。倾听之后，认同其信息：“猪大了，可能买好价钱”。那么铁柱可以就这个点继续联想。如果猪长大了是真的，那么还有什么是真的？可以卖钱是真的，有钱之后可以做什么呢？继续联想，可以的到很多种答案，比如铁柱回复：“是啊，亲爱的，卖了猪，我们就有钱买大房子了，再也不用住写着拆字的危房了”，接下来就能发展出更多有意思的剧情了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Support&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Support同理，需要建立在之前的基础之上。support对应yes,and中的and。如果铁柱只回复了“是啊，猪好大了。”，那么铁柱只完成了yes的任务，并没有完成and的任务。这种行为将整个剧情发展的压力都交给了翠花，可以想象翠花需要多少智慧才能继续演。所以support非常关键，在认同的基础之上，给出更多确切的信息，能给队友传递有用信息，从而帮助队友进行进一步创造，推动戏剧的发展。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Error tolerance&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Error tolerance指的是在舞台上表演时对错误的容忍性，当队友犯错误时要具有一定的容错性，才能更好地合作，继续演下去。比如场景是北极的雪原上，伊丽莎白.淑芬指着远处，兴奋地说：“看，那是什么？”，她首先没有给出队友明确的名称，也没有给出明确的信息，明显犯了错误。此时，队友应该容忍这个错误，努力创造信息，发展剧情。“淑芬啊，你读书少，那是企鹅啊，北极的特产”。“大力，不对吧，北极没有企鹅，只有北极熊”， 淑芬给出了人物的名称，但是没有yes and对方的信息，给了一个否定的回答，这是禁忌。当然，这是因为大力说了一个错误的信息。这个时候不能因为信息的错乱而手忙脚乱，开动你的智慧，将其合理化，观众则会为你的智慧喝彩。“是啊，那是过去的事了，在30世纪，南极被淹没了，企鹅都搬迁到北极来了。你看，那里还有恐龙呢，28世纪的时候人们把恐龙复活了呢” 。这是一个脑洞稍微大的解释，但不失为一个好的选择，很好地合理化了剧情，推动了剧情的发展。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create是即兴戏剧剧情得以发展的核心。老师经常强调一个规则：创新=发现+创造。发现就是发现场上的资源，包括队友给出的信息，地点，身份，心理位阶等，然后在此基础之上进行创造。基于前面几个阶段的努力，目前我们得到了队友提供的信息，然后根据信息进行想象，从而创造出新的内容。想象分为三种：分想（dissociation），联想(Association)和异态联想(bisociation)。分想就是在将一串台词，分割成若干的信息单元，然后选择某一个信息单元，进行后续创造。联想是最普遍的想象，如提到碗，想到喝水，想到乞讨，想到饭碗等等。联想基于表演者自身的知识系统，这点无需赘述。异态联想，是一些看似不合理但是又能产生联系的想象，往往会由于出乎意料而带来笑点。异态联想主要在于反转，提到反转，可以看看下面的案例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;考试前，小红对小明说，如果你这次能考全班第一，我就做你女朋友。&lt;/span&gt; 
&lt;span class="err"&gt;全班同学都听到了，试卷发下来后，大家都默默的把笔放下了，打算交白卷。&lt;/span&gt; 
&lt;span class="err"&gt;小明眼泛泪花……他看了一眼虎背熊腰&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="err"&gt;斤的小红，默默的把试卷撕了吃了下去……&lt;/span&gt; 
&lt;span class="err"&gt;小红微微一笑，在自己试卷上写下了小明的名字……&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;正常的想象下，特别是对于工科男而言，考试能第一就可以女朋友，江山与美人兼得，甚是美哉！且大家也为了成全自己，做了做大的努力，交白卷，想想也是很感动啊，所以眼泛感动的泪花，这一切想象都是正常的逻辑，基于女朋友是美女这个前提。此时突然来了一个异态联想，小红竟然是一个200斤虎背熊腰的女生，一切都变得很忧伤。好在小明很聪明，把试卷撕掉，不交，总可以了吧！然而，黄雀在后，小红微微一笑，在试卷上写下小明的名字。幸福来得太突然，让承受不住的小明心脏病突发，不幸去世的既视感。笑点在与转折，转折来自不按常理出牌的想象，我们称之为异态联想。可以继续看一个例子，感受一下。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;小明昨天刚理的头发，被班上同学嘲笑他的发型像个风筝。小明很伤心，跑出了教室，哭泣着往家里跑，跑着跑着就飞了起来。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上的故事前半段给观众带来的场景是一个可怜的小朋友，因为发型而被其他人嘲笑，是一个悲伤的故事。画面应该是寒风中，那个瘦弱的小明，独自一人，默默哭泣地奔跑，去寻找妈妈温暖的怀抱，然而剧情却峰会路转，小明由于发型像风筝竟然飞了起来，突然之间，好像他的发型确实就像风筝。&lt;/p&gt;
&lt;p&gt;以上的内容主要介绍了在舞台上如何和队友配合，演好一出戏。除此以外，还有一些重要的小建议，值得注意。笔者根据学习和表演经验列举如下，更多信息可以查阅wiki相关内容。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;给出明确的人物关系&lt;/strong&gt;：明确的人物关系，包括人物的名称，身份，关系，心理位阶。名称方面，建议采用一些有意思的名字，中西结合等跨界的组合有更好的记忆点，容易带来喜剧效果，如奥黛丽·春梅。身份最好采取特殊一些，这样思路才容易集中，且脱离生活实际才能不受惯性思维的束缚。禁忌在表演中演自己，都说人生如戏，其实戏也如人生，我们需要相信戏中的人生，摆脱现实生活对想象的禁锢。如身份是娘娘，那么很容易就出来宫廷戏，演员的想象力就可以集中在宫廷戏之上，容易表演出真实的剧情，相比小丽，小王而言，更容易被观众铭记。人物关系在一个戏剧中起到关键作用，不明朗的人物关系，给观众带来的理解就是两个认识的人，仅此而已。在即兴剧中，最好不要演陌生人关系，因为很难出剧情。一般而言，人物关系都是熟人关系，哪怕是仇人，也是熟悉的仇人。若能具体化关系，比如老板和员工，师傅和孙悟空，尔康和紫薇等，剧情就容易发展得多。一方面观众有同样的知识背景，更能认同当下所营造的场景并进行想象；另一方面，明确的人物关系对剧情的发展提供了良好的保障，为想象提供了框架。心理位阶是人物关系的深层次体现，比如员工面对老板时，心理位阶是低的，则在表演时不能趾高气扬，需要从肢体动作上表现出心理位阶低的特征，如不敢直视对方。关于心理位阶的训练，我们平时会采用位阶反转的方式来训练。如员工发现了老板和小秘书勾搭的事，借此威胁老板，此时老板就范，变成心理位阶低的一方，员工则变成心理位阶高的一方。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;记住上场任务&lt;/strong&gt;：即兴剧剧情场景基本由3W组成：Who、Where和What。也就是谁在什么地方做什么事，这是一个故事的基本要素。在3W训练中，演员应当记住自己的上场任务，明确交代身份，地点，和事件。平时训练时，一方交代身份和事件，另一方交代身份和地点，配合yes and原则就能演好即兴剧。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其他的小建议如不要问问题，不要出戏，努力塑造人物个性等都可以由以上的内容发散得到，不在介绍，读者可以在实践中慢慢掌握。&lt;/p&gt;
&lt;p&gt;掌握了基础的技巧之后，基本就可以胜任短篇即兴的表演了。然而以上的内容对于长篇即兴表演者而言还远远不够。目前笔者也在进一步学习之中。长篇即兴重点不在与搞笑，而在与演员相互支持，共同创造，推动剧情发展，并找到有趣的发展路线，然后将戏剧推向高潮，最后结束。其表演更偏向与戏剧，所以对演员要求非常高。不过长篇即兴对于创造而言有非常大的帮助，很多好莱坞的电影都采用了即兴创作的方式进行编剧，然后形成剧本，最后再演出。长篇机型中一个基础的理论成为Game theory。我们知道戏剧的英文单词可以是play,所以通过game来play就很容易理解了。&lt;/p&gt;
&lt;p&gt;在演员相互支持，共同创造的时候，可能会出现一些中文称之为“梗”的东西，也就是笑点，那么抓住这个梗，玩它，然后推动剧情发展，这就是对Game theory的最浅层次的理解。一般而言，一个有趣的梗可以玩3次左右，效果最好。第一次很普通，平常，观众很容易接受；第二次稍微奇怪一些，让观众觉得有些新意；最后一次疯狂一些，制造笑点，达到小高潮。这样的手法在喜剧创作中经常被使用到，比如《头脑特工队》的最后一段：每个人脑中都有5种情绪：喜，怒，哀，惧，厌，他们一起操控着人的情绪；最开始顺序地展现了几个正常的人的脑中的情绪小人，让观众觉得很正常，突然到了扮演小丑逗小朋友开心的内心活动时，就有一些不一样，小丑的心里活动是“表演学校N年就是为了这个”，让观众觉得有点意思，有点喜剧效果了；最后，癫狂错乱的猫，让整个game的达到了高潮，爆发了笑点。这就是使用game理论的体现。在喜剧产品创作中，Game理论被大量使用，包括侯宝林先生的《开会迷》，多次提到开会迷的事情，过程是类似的，程度不断加强，最后达到高潮。&lt;/p&gt;
&lt;p&gt;关于演员上场（Walk on），也有相关的理论知识。一般而言，演员上场起到以下三个作用：Support、Match和Heighten。当台上的演员表演一段时间还没有交代清楚如名称，关系，地点等基本要素时，上场的演员需要补充所缺的信息，支持场上演员一起构建故事框架，推动故事发展。当台上演员谈论到某些人物或者事件事，相关的人物出现，匹配(Match)当下的信息，可以起到强调信息的作用，同时按照Game理论，多次出现，可以推动剧情发展。比如台上演员在谈论领导有小三这家事，此时，小三，小四们依次出现，不仅可以印证这一信息，还可以带来一定的笑点。Heighten意为提高，即演员的上场可以将故事的剧情推到最高点，矛盾冲突最大化。比如老板和老板娘就老板有小三一事在争论，老板正要被老板娘打败的时候，老板娘的小三出现，此时矛盾再次提升，将剧情提高到新高度。&lt;/p&gt;
&lt;p&gt;更多的关于即兴剧和创作的内容，还需要等待进一步学习才能总结得更好。以上的内容都是一些偏学术的内容，不够接地气，接下来就介绍学习即兴戏剧对我们平时的生活有什么帮助。介绍之前，先介绍一本书《即兴的智慧》，其作者Patricia Ryan Madson是斯坦福大学戏剧系教师，同时也是企业创意顾问，书中介绍了如何学习即兴戏剧，以及学习即兴戏剧对个人的帮助。书中提到了yes,and以及即刻现身等建议，可以给初学者一个很好的建议，有兴趣的读者可以尝试阅读。关于即兴戏剧对个人的影响，笔者针对其在沟通方面的影响总结如下，关于创作方面不再介绍。&lt;/p&gt;
&lt;h3&gt;即兴剧和沟通的关系。&lt;/h3&gt;
&lt;p&gt;Communication，可以指沟通，也可以指通信。此处将介绍人与人之间的沟通，不局限与语言，也包括行为的沟通，如团队协作等。后续将介绍机器之间的沟通：通信。&lt;/p&gt;
&lt;p&gt;沟通是人在当今社会赖以生存的技能之一。学会如何更好的与人沟通是当下许多人，尤其是年轻人应该学习的功课。而传统的教育中有关沟通的课程很少，大学里倒是有一些类似的课程，但是认真听课，实践的人并不多。这就导致了许多年轻人在与人相处时沟通不顺利，团队合作能力差等结果。即兴戏剧强调say yes,and..需要演员在表演时专注，倾听，所以学习即兴戏剧是一种很好的培养倾听能力的手段。在没有接触即兴戏剧之前，我自认为我是一个能说会道的人，我习惯于向别人传递信息，但不擅长倾听。所以很多时候听不进去别人的意见，导致合作上的一些分歧等等，这都是沟通能力上的一些漏洞。在我刚开始学习即兴戏剧时，被老师提醒最多的就是你要认真听，不要自己说自己的。经过一段时间之后，我终于学会了倾听队友的信息，当然这需要我在场上非常专注。学习即兴戏剧帮助我学会更好地倾听，专注，学会了沟通中很重要的一种能力。训练倾听等能力的方式一般是通过有趣的游戏来完成的，比如“大鱼小鱼”，所以在欢声笑语中学习知识是即兴戏剧带给我的不一样的学习体验。&lt;/p&gt;
&lt;p&gt;此外，即兴戏剧强调支持别人，分享控制权，而不是一个人当主角去控制整个场面，整个剧情的发展。在表演的过程中，需要给队友戏份，给队友支持和说话的机会，这样才能减轻自己的负担，让剧情更好地发展下去。而在现实生活中，很少会有因为支持别人所以成功的案例，一般而言，大家都在为自己着想。而在团队合作中，需要去支持队友，扮演一个角色，支持整个团队的运作，才能使得团队成功，进而个人成功。在平时的学习中，会有如“聚光灯”等游戏来锻炼分享控制权的能力，也会有3W等训练支持别人的训练内容。&lt;/p&gt;
&lt;p&gt;基本上，学习即兴戏剧足以改变一个人的沟通方式，让内向的人学会开口表达，让控制欲强的人学会倾听，最重要的是其过程是欢乐的，这就是为什么我学习即兴戏剧的原因之一，另一个原因是我确实想当导演。&lt;/p&gt;
&lt;h3&gt;即兴剧和通信的关系&lt;/h3&gt;
&lt;p&gt;Communication的另一个意思是通信。通信是一门工科类学科，可以按照OSI层次分为几大类，底层的无线，编码，中层的网络，上层的应用。笔者仅对中层的网络有所了解，且网络更符合通信的含义，所以本部分介绍即兴戏剧和通信的关系。&lt;/p&gt;
&lt;p&gt;通信系统之所以能运行起来，是因为其遵循很多规则，这些规则称之为协议。换言之，就是机器之间进行沟通所遵守的约定。既然都是沟通，必然就有其相似之处。比如CSMA/CD规定主机需要检测网络中是否有别人在发送信息，若有则随机退避，直到没有人发信息，自己就发信息。这种机制大大提升了共享信道的利用率。在生活中也有类似的场景，如多人一起开会，如果大家一起说，那么大家相互影响，都是噪音，则沟通效率很低；而如果规定一个人说话的时候，其他人必须听着，保证任何时刻只有一个人在传递信息，那么大家任何时刻都在接受一种信息，而不是多种信息混杂的噪音，从而大大提升了沟通的效率。再到即兴戏剧中，场上的演员如果争着说台词，那么观众的感觉就是乱糟糟的，听不清楚。如果能够很好地分享控制权，保证说台词的演员独占这个时间，其他演员认真倾听，可以帮助戏剧继续推进的。所以说学习即兴戏剧对更好地理解通信的相关知识很有帮助。本质上，通信就是机器之间的沟通，与人之间的沟通无异，那么通过锻炼人与人之间的沟通能力，一定可以对理解其他领域的沟通起到帮助的。&lt;/p&gt;
&lt;p&gt;上一次纪老师的创业课堂上，我就组织了两个小时的即兴工作坊，大家玩得都挺开心，在遇到问题时，我尝试用通信的角度去解释即兴剧里面的一些现象，发现两者竟是相通的，好像在两个世界中打开了一个通道一样。可惜，我并不是一个专门讲课的老师，不然，我的通信课一定是非常好玩的。学习本应该是一种充满快乐的过程，即兴戏剧可以做到这一点。&lt;/p&gt;
&lt;p&gt;同理，还有其他很多场景可以和即兴剧的理论相通，比如网络协议。传统的网络协议多是分布式的，由多个实例一起运作，从而完成共同的工作。即兴剧中同样强调去中心化，分布式控制，即一场演出是由多名演员一起创作而成的，每个人都有控制权，而不是大家都听某一个主演的，由主演主导演出。此外，即兴戏剧中强调尽力就好，不强求完美，且确实无法做到完美。在通信系统中为了更好地通信，传输，有一些协议的传输是尽力而为的，如IP报文的传输。&lt;/p&gt;
&lt;p&gt;本质上，如果你抽象能力够强，通信的学科，包括计算机学科的内容是可以抽象出来，然后在生活的具体案例中找到映射。比如负载均衡可以找到多窗口检票进站，分布式可以类比成一个医院的不同部门。网络类比成现实生活中的交通系统，路由表项则对应这路标，等等。而即兴戏剧的智慧来源于生活而高于生活，所以通过即兴戏剧来学习，培养生活中的智慧，并将其应用到相关的学科学习中，是一件一举多得的事情，对个人的成长起到了很大的帮助。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;学习即兴戏剧半年多了，一直在学习，却从未停下来总结过。直到这学期一边学习，一边教授新人如何去学习即兴戏剧，才发现自己的知识还没有系统地整理过，讲得并不是很好，所以花了两个晚上，总结了一下即兴戏剧的学习。这半年来，我也接触了开心麻花等多个即兴戏剧团体，发现很多有才的人，并向他们学习。此外，最近在课堂上尝试将通信有趣话描述之后，我突然发现之前我脑海里总结的那些很学术的知识，可以通过如此生动形象的方式来介绍，真的可以让学习变得很快乐。学习即兴戏剧让我改变很大，变成一个更加包容的人，懂得去倾听、去包容、去支持、去学习更好的沟通方式，同时也打开了我生活的另一扇门，走向了一个新鲜的有趣的世界。感谢大可老师，带领我学习即兴戏剧，还应该感谢的应该是隔壁班的女同学，是你骗我来当主角，结果发现大家都是主角。同时，希望此文能给不了解即兴戏剧的同学一个初步的介绍，帮助即兴戏剧在中国继续传播。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sat, 14 Nov 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-11-14:pages/2015/11/14/ji-xing-xi-ju-yu-gou-tong-tong-xin.html</guid><category>improv</category><category>communication</category></item><item><title>SDN东西向现状简介</title><link>http://www.muzixing.com/pages/2015/10/29/sdndong-xi-xiang-xian-zhuang-jian-jie.html</link><description>&lt;h3&gt;What is SDN West-East Interface&lt;/h3&gt;
&lt;p&gt;在SDN架构中，控制平面掌控全局网络的资源，控制数据平面的转发等功能，尤其重要，所以控制平面的性能对整体网络的性能有直接的影响。以前控制平面多以单例控制器为主，控制平面能力欠缺成为SDN网络规模受限的最大原因之一。 后来OpenDayLight，ONOS等控制器的出现，使用了集群技术，使得SDN控制平面性能得到了提升，是当下解决SDN控制平面性能不足的主要解决方案之一。&lt;/p&gt;
&lt;p&gt;然而，这样的解决方案只能用于同一控制器之间的性能扩展，无法完成异构控制器之间的协同工作。此外，某些场景对于安全，隐私方面的考虑，需要隐藏网络内部的细节，所以还需要有SDN域的概念。如何完成跨域之间的流量处理，实现多异构控制器之间的协同工作是未来研究的方向之一，笔者将其归类为SDN控制平面的东西向接口。SDN控制平面的南向接口面对数据平面，北向接口面向应用，容易理解，控制器之间的接口称之为东西向接口，用于完成控制器之间的通信。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="West-East" src="http://ww2.sinaimg.cn/mw690/7f593341jw1exixzvkpi6j20og0d2gml.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;Figure1. West-East Interface of SDN&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;Why SDN need West-East Interface&lt;/h3&gt;
&lt;p&gt;SDN东西向接口是定义控制器之间通信的接口。由于单控制器能力有限，为满足大规模和可拓展性要求，东西向接口的研究成为下一个SDN研究领域。目前对于SDN东西向接口的研究还处于初级阶段，还缺少行业标准。标准的SDN东西向接口应与SDN控制器解耦，能实现不同厂家控制器之间通信。&lt;/p&gt;
&lt;p&gt;在很多场景中都需要控制器之间的协同工作，如在运营商网络场景中，接入网，回传网，核心网三者功能差异很大，需要制定不同的控制器去运行不同的应用，而这三者又需要协同合作，实现全网的最优化。此时就需要东西向接口来完成控制器之间的通信。跨数据中心的网络中，多数据中心的控制器也有相互通信的需求。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="West-East interface for mobiel network" src="http://ww4.sinaimg.cn/mw690/7f593341jw1exixzu4513j20wq0cm76v.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;Figure2. Federation of SDN Controllers&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;目前南向的标准还为统一，OpenFlow成为SDN南向接口的通用标准之一，其他还有许多可以实现SDN架构的南向接口协议。总的来说，目前南向接口是百花齐放的状态。北向接口方面，目前ONF已经有相关部门在进行这项工作。统一的北向接口标准可以降低在不同控制器上开发应用的成本。关于东西向接口的标准，目前在业界中还未的到重视，仅ONF一个项目组在关注这个方向。&lt;/p&gt;
&lt;h3&gt;Approach for West-East Interface&lt;/h3&gt;
&lt;p&gt;SDN控制平面性能拓展方案中，目前的设计方案有两种，一种是垂直架构的，另一种是水平架构的[1]。垂直架构的实现方案是在多个控制器之上再叠加一层高级控制层，用于协调多个异构控制器之间的通信，从而完成跨控制器的通信请求。水平架构中，所有的节点都在同一层级，身份也相同，没有级别之分。目前比较常见的架构为水平架构，比如华为的SDNi[2]，Pingping Lin博士提出的West-East Bridge for SDN inter-domain network peering[3]。垂直架构目前在中国移动提出的SPTN架构中有涉及，笔者正在研究的内容也正是这部分内容。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1exixzuopf7j20jj0a4gm1.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;Figure3. Vertical Approach for Inter-SDN Controller Communication &lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341jw1exixzud6drj20ky07b74i.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;Figure4. Horizontal Approach for Inter-SDN Controller Communication &lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;Previous Research&lt;/h3&gt;
&lt;p&gt;东西向接口其实并不是一个新鲜事，在很多架构中都会被提到。2013年， 清华的博士pingping lin的论文“East-West Bridge for SDN Network Peering”中提出了West-East Bridge的概念。论文中介绍了他们设计的东西向接口的功能，并完成了部署和测试。&lt;/p&gt;
&lt;p&gt;SDNi是华为提出的一种SDN东西向的实现，目前已经在OpenDayLight中部署实现。其架构为水平架构，可实现多OpenDayLight实例之间的通信，完成跨域通信。目前支持传输Topology Data, QoS Data和其他一些拓展内容。&lt;/p&gt;
&lt;p&gt;中国移动发布的关于SPTN的白皮书中也有设计多控制器协同工作的内容，然而目前仅仅处于白皮书阶段，并没有实际部署和测试。SPTN白皮书中提到了层级式的SDN控制平面架构，分别为Super层和Domain层。Super层的Super Controller负责跨域通信的业务，Domain层的Domain Controller负责域内的通信。分级的架构能使得SDN控制平面能力得到大大的提升。&lt;/p&gt;
&lt;p&gt;TATA在很久以前发布了关于跨域通信的报告。报告中介绍了实现SDN跨域通信的两种架构：垂直架构和水平架构。此外还提出了基于BGP或者SIP协议去完成SDN东西向接口的想法，不过报告内容仅限于次，并没有提及任何实际部署的内容。目前为止，依然没有搜集到相关的实践部署。&lt;/p&gt;
&lt;p&gt;其他相关论文也有若干，但影响力不够，暂不介绍。&lt;/p&gt;
&lt;p&gt;目前笔者正在研究SDN东西向的内容，期待后续能有所产出。&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;随着SDN的发展，部署SDN的网络规模将越来越大，对SDN控制平面的性能要求也越来越高。虽然当下业界对SDN控制层面东西向并不够重视，但相信随着技术的发展，东西向方向的解决方案，技术标准将逐渐完善。期待未来自己的成果能顺利发表，产生一定的影响。&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;p&gt;[1]：http://www.tcs.com/SiteCollectionDocuments/White%20Papers/Inter-SDN-Controller-Communication-Border-Gateway-Protocol-0314-1.pdf &lt;/p&gt;
&lt;p&gt;[2]：https://tools.ietf.org/html/draft-yin-sdn-sdni-00&lt;/p&gt;
&lt;p&gt;[3]：Lin P, Bi J, Chen Z, et al. WE-bridge: West-East Bridge for SDN inter-domain network peering[C]//Computer Communications Workshops (INFOCOM WKSHPS), 2014 IEEE Conference on. IEEE, 2014: 111-112.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 29 Oct 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-10-29:pages/2015/10/29/sdndong-xi-xiang-xian-zhuang-jian-jie.html</guid><category>SDN</category><category>west-east</category></item><item><title>SDN应用路由算法实现工具之Networkx</title><link>http://www.muzixing.com/pages/2015/09/28/sdnying-yong-lu-you-suan-fa-shi-xian-gong-ju-zhi-networkx.html</link><description>&lt;p&gt;SDN(Software Defined Networking)是一种新型的网络架构，通过集中式的控制平面管理数据层面的转发等操作。网络的联通性是最基础的需求，为保证网络联通性，控制器需要应用相应的图论算法，计算出转发路径，完成数据转发。在开发SDN应用时，为完成基础的路径计算，时常需要开发者独立编写网络算法，不仅麻烦，性能和代码可复用性还受开发者个人编程水平影响。所以本篇文章将介绍网络算法工具networkx，用于完成路径算法开发工作。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://networkx.github.io/"&gt;networkx&lt;/a&gt;是用于创建、操作和研究复杂网络动态、结构和功能的Python语言包。networkx支持创建简单无向图，有向图和多重图（multigraph）；内置了许多标准的图论算法，节点可为任意数据，如图像文件；支持任意的边值维度，功能丰富，简单易用。&lt;/p&gt;
&lt;p&gt;由于Networkx代码经过多次测试，性能方面也做了很多的工作，使用Networkx内置的多种图论算法能给开发SDN应用带来很多的便利，可以节省开发时间，降低代码故障率。networkx的安装和使用，读者可从&lt;a href="http://networkx.github.io/documentation/networkx-1.9.1/index.html#"&gt;官网文档&lt;/a&gt;中快速得到，不加赘述。接下来的内容将简要介绍Networkx的经典图论算法内容， 包括&lt;a href="http://networkx.github.io/documentation/networkx-1.9.1/reference/algorithms.shortest_paths.html"&gt;最短路径&lt;/a&gt;, &lt;a href="http://networkx.github.io/documentation/networkx-1.9.1/reference/generated/networkx.algorithms.simple_paths.all_simple_paths.html"&gt;KSP(K Shortest Paths)&lt;/a&gt;算法和&lt;a href="http://networkx.github.io/documentation/networkx-1.9.1/reference/algorithms.traversal.html"&gt;Traversal(遍历)算法&lt;/a&gt;BFS（Breadth First Search）/DFS(Depth First Search)。&lt;/p&gt;
&lt;h2&gt;最短路径算法Dijkstra和Floyd&lt;/h2&gt;
&lt;p&gt;计算单源到其他所有节点的最短路径的Dijkstra算法和计算所有节点之间最短路径的Floyd算法是最经典的网络算法之一。在networkx中对于二者的实现将在介绍如下。&lt;/p&gt;
&lt;h3&gt;Dijkstra&lt;/h3&gt;
&lt;p&gt;无论有向图还是无向图均可以使用的Dijkstra算法， G为networkx生成的图数据结构。source为起点，target为终点。起点、终点和权重均为可选参数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;networkx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shortest_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;无权图&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;networkx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;single_source_shortest_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;有权图&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;networkx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dijkstra_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;weight&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Floyd&lt;/h3&gt;
&lt;p&gt;对于Floyd算法，有无权图和有权图两种实现：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无权图&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;networkx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_pairs_shortest_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;有权图&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;networkx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_pairs_dijkstra_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;对于路径的长度的计算可以调用network.XXX_length函数获得，XXX为对应的路径计算算法名称。除了以上提到的几个算法以外，networkx还针对很多需求设计了变种的函数，如返回同样长度的多条最佳路径算法等，读者可根据需求自定义学习内容。&lt;/p&gt;
&lt;h2&gt;K-Shortest paths&lt;/h2&gt;
&lt;p&gt;在研究网络路由算法/转发算法时，除了使用跳数作为计算最优路径的标准以外，还会使用到很多其他的指标，如带宽，时延等，也有可能根据多种指标，建立多维度评价系统，计算加权值，从而计算最佳路径。例如，当涉及到带宽为标准时，计算量就会很大。首先，获取网络链路的剩余带宽数据，然后从源头开始，选途径路径中带宽最大的路径。由于一条链路中的最大剩余带宽取决与剩余带宽最小的那一条，若使用贪心算法逐跳排除，很可能计算错误，所以每遇到一个分支就需要选择一个路径，并保存其他未选择的路径数据。每一个节点都需要对所有的数据进行对比，从而选择当下最优的路径，直至所有的链路都比较完成。这样的算法可以通过修改Dijkstra算法完成，逻辑不困难，但效率并不高，具体实现不加赘述，读者可查看笔者在网上找到的一个介绍文章:&lt;a href="http://www.0x94.com/doc/0o3dyiZgX_3k94OWp.html"&gt;基于SDN的最短路径算法(迪杰斯特拉)dijkstra&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;在研究的过程中，发现许多论文提的方法都是基于拓扑信息算法K条最短路径，然后在根据带宽计算最优路径。根据算法可以直接在这K条中选择最大的路径最为最优，也可以设置权重，计算跳数和带宽的加权值，再选择最优。由于跳数的数值和带宽的数值相差甚远，所以二者均需进行归一化/正则化。&lt;/p&gt;
&lt;p&gt;考虑跳数的原因在于：每经过一个交换机，消耗的资源就多一份，所以需要考虑在内。举例：路径A带宽100M，跳数为2； 路径B带宽110M，跳数为5,若按照带宽选择则选择B，然而B经过的路径是A的若干倍，消耗的资源更多，产生的传输时延，以及传播时延（假设跳数为5的链路长度大于2， 否则不成立）也更多，所以综合考虑A可能是更好的路径。&lt;/p&gt;
&lt;p&gt;传统的KSP算法很多，Yen, Jin Y于1971年发表的论文 "Finding the k Shortest Loopless Paths in a Network"中提出的&lt;a href="https://en.wikipedia.org/wiki/Yen%27s_algorithm"&gt;Yen's algorithm&lt;/a&gt;就是经典算法之一，读者可直接查看点击&lt;a href="https://en.wikipedia.org/wiki/Yen%27s_algorithm"&gt;Yen's algorithm&lt;/a&gt;的wiki。其算法思想并不复杂，基本思想为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dijkstra选择第1条最优路径， 保存为A[0]&lt;/li&gt;
&lt;li&gt;外循环，k从1到k。 内循环，以第k-1条（前一条）最优路径为路径，从该路径的第一个点开始作为分叉节点，分叉节点之前的为前一条最优路径与当前路径一致的部分，称之为rootpaths；将分叉点上已选的最优路径分支去掉（权值设置为正无穷），然后再运算dijkstra,将路径计算结果放到临时数据结构B中，随着循环的进行，分叉点不断前进，直至终点前一跳，内循环比较，已选出多条潜在的最优路径。&lt;/li&gt;
&lt;li&gt;对临时数据结构B中的路径进行排序，找到最优路径，添加到A数据结构中， 存为A[k], 外循环一轮结束。&lt;/li&gt;
&lt;li&gt;外循环继续，直至找到K条最优路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Networkx已经实现了KSP算法，该算法patch于2015年4月份左右才加入networkx项目，由于networkx中all_shrtest_paths名字已被使用，所以新加入的算法在networkx中对应函数命名为&lt;a href="http://networkx.github.io/documentation/networkx-1.9.1/reference/generated/networkx.algorithms.simple_paths.all_simple_paths.html"&gt;all_simple_pay&lt;/a&gt;，具体参数如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;all_simple_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cutoff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其中G为networkx的图数据结构，source为起点，target为终点，cutoff为搜索深度，只返回路径长度短于cutoff的路径。为优化性能，函数返回值为一个generator(生成器)， 读者可通过for循环，生成对应的K shortest paths。采用generator可以逐次计算结果，而不会一次运算全部结果都写入内存，可以大大降低内存使用&lt;/p&gt;
&lt;h2&gt;Traversal&lt;/h2&gt;
&lt;p&gt;在某些网络应用场景中，会使用到遍历算法，如BFS（Breadth First Search）/DFS(Depth First Search)算法， networkx已经定义好的对应函数，具体内容由于篇幅限制，不再介绍。读者可查看networkx官方文档中关于&lt;a href="http://networkx.github.io/documentation/networkx-1.9.1/reference/algorithms.traversal.html"&gt;遍历&lt;/a&gt;的文档进行学习。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;在开发SDN应用中，网络联通性是最基本的需求。在开发网络应用时，可采用networkx来保存网络数据，计算路径等，可大大提高开发效率。在学习的过程中，从不断自己造轮子，到逐渐使用成熟的开源软件，接触了很多工具，学习到了很多有用的知识。自己造的轮子很多时候，性能，适用度以及接口的稳定读都是很大的考验，逐渐尝试优秀的开源工具将成为我在未来编程学习的方向。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Mon, 28 Sep 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-09-28:pages/2015/09/28/sdnying-yong-lu-you-suan-fa-shi-xian-gong-ju-zhi-networkx.html</guid><category>SDN</category><category>networkx</category></item><item><title>Ryu:模块间通信机制分析</title><link>http://www.muzixing.com/pages/2015/09/08/ryumo-kuai-jian-tong-xin-ji-zhi-fen-xi.html</link><description>&lt;p&gt;Ryu是一款非常轻便的SDN控制器，在科研方面得到了广泛的应用。相比其他控制器，受益于Python语言，在Ryu上开发SDN应用的效率要远高于其他控制器。为了解决复杂的业务，有时需要在Ryu上开发多模块来协同工作，从而共同完成复杂的业务。本文将介绍Ryu模块之间通信的包括Context等方式的多种通信方式。&lt;/p&gt;
&lt;h3&gt;_CONTEXTS&lt;/h3&gt;
&lt;p&gt;在RyuApp类中有一个属性是_CONTEXTS。_CONTEXTS中的内容将作为当前模块的服务在模块初始化时得到加载。示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;_CONTEXTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;Network_Aware&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;network_aware&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Network_Aware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;Network_Monitor&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;network_monitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Network_Monitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Shortest_forwarding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;shortest_forwarding&amp;#39;&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;network_aware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Network_Aware&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;network_monitor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Network_Monitor&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在模块启动时，首先会将_CONTEXTS中的模块先启动，在模块的初始化函数中可以通过self.network_aware = kwargs["Network_Aware"]的形式获得该服务模块的实例，从而获取到该模块的数据，并具有完全的读写能力。这种模式很清晰地体现了模块之间的关系。然而在Ryu的实现中，这个机制并不完美，或者有所限制。首先，当某个模块作为别的模块的服务启动时，就无法在启动Ryu时手动启动。这种做法应该是出于保证模块启动顺序，从而顺利完成多模块启动而设计。另一方面，Ryu不支持多级的服务关系， 如A是B的服务，那么B就不能作为其他模块的服务，也即这种服务关系只有两层。所以在设计模块时，若完全使用_CONTEXTS方式来传递信息则需将架构设计成两层以内。若希望不受此限制，开发者可以自己修改其源码解除这个限制。&lt;/p&gt;
&lt;h3&gt;app_manager.lookup_service_brick()&lt;/h3&gt;
&lt;p&gt;在某些业务场景，我们需要使用其他模块的数据，但是又不希望将对方作为自己的服务来加载，则可以通过app_manager.lookup_service_brick('module name')来获取运行中的某个模块的实例，从而获取其数据。典型案例可以参考controller/controller.py中的Datapath类。示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_brick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookup_service_brick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ofp_event&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;
            &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPStateChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_event_to_observers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这种做法区别于import, import引入的是静态的数据，如某个类的函数的定义，静态数据的定义。当涉及到动态的数据，import则无法获取到对应的数据。如名为app的模块中有一个属性self.domain = Domain(）,那么import可以获得其类的定义，而实际上，我们需要的是运行状态时Domain的实例，而import无法做到这一点。通过app = app_manager.lookup_service_brick(‘app’)可以获得当前的app实例，进而通过app.domain来获取当前的domain实例的数据。&lt;/p&gt;
&lt;h3&gt;Event&lt;/h3&gt;
&lt;p&gt;通过事件系统来通信是模块之间通信的最普通的形式。每当交换机和Ryu建立连接，都会实例化一个Datapath对象来处理这个连接。在Datapath对象中，会将接收到的数据解析成对应的报文，进而转化成对应的事件，然后发布。注册了对应事件的模块将收到事件，然后调用对应的handler处理事件。示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_msg_to_ev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_event_to_observers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;dispatchers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispatchers&lt;/span&gt;
        &lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_handlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dispatchers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;simple_switch_13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nd"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPPacketIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_packet_in_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;编译运行之后，simple_switch_13模块的_packet_in_handler函数注册了事件ofp_event.EventOFPPacketIn, 当Controller模块中的Datapath分发ofp_event.EventOFPPacketIn事件时， 将会分发到_packet_in_handler函数，在Datapath中调用handler(ev)来处理事件，从而完成了信息在模块之间的通信。&lt;/p&gt;
&lt;h3&gt;公共文件读写&lt;/h3&gt;
&lt;p&gt;除了以上的形式以外，某些数据的通信则通过读写公共文件完成。最典型的案例是oslo.config的使用。&lt;a href="https://wiki.openstack.org/wiki/Oslo"&gt;oslo&lt;/a&gt;是OpenStack的开源库。oslo.config提供一个全局的配置文件，同时也完成命令行的解析。通过读写公共文件的内容，可以完成信息的传递，如模块A将config中CONF对象的某个参数arg的i值修改为1, B再读取对应的参数arg，则可以获得数值1, 从而完成通信。面对配置信息等全局信息时，公共文件的使用可以避免不同模块之间的冲突，从而实现全局数据的统一。但是这种做法会频繁地读写文件，效率不高。且此类数据仅适合静态数据的传递，不适合存在于实例中的动态数据。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;在使用Ryu开发SDN网络应用的过程中，多模块协同工作是非常常见的场景。使用_CONTEXTS形式可以更清晰地体现模块之间的关系，代码架构可读性更高；采用app_manager.lookup_service_brick()形式可以得到运行的实例，可以达到_CONTEXTS的效果，适用与仅需使用某模块某小部分功能集合，模块之间没有明显的服务关系的场景；Event是最普通的模块见通信，可以实现订阅发布模式的多模块协同工作场景，实现模块之间解偶；采用公共文件作为信息的中转站是最后的选择，效率比较低，适用于全局信息的传递。以上的几种方式是笔者在实验过程中总结的通信方式，若有错误指出，敬请指出，万分感谢。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 08 Sep 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-09-08:pages/2015/09/08/ryumo-kuai-jian-tong-xin-ji-zhi-fen-xi.html</guid><category>ryu</category></item><item><title>SDN控制平面发展历史及趋势</title><link>http://www.muzixing.com/pages/2015/08/30/sdnkong-zhi-ping-mian-fa-zhan-li-shi-ji-qu-shi.html</link><description>&lt;p&gt;SDN的特点之一就是控制平面与数据平面分离，其主张通过集中式的控制器平台实现网络的控制。在SDN架构中，控制平面是逻辑集中的，通过某种协议将控制信息下发至底层的数据平面去执行。所以，控制平台被称为SDN的大脑，指挥整个数据网络的运行。&lt;/p&gt;
&lt;p&gt;得益于集中控制的优势，控制平面的存在能使得网络的部署和配置更加智能和简化。支持编程的SDN控制平面使得网络更加智能，更加灵活和易于拓展。控制器通过SDN的南向协议的API可以对数据层面的网元设备下发指令，完成控制平面与数据平面的控制传输。2008年，SDN和OpenFlow一起诞生于斯坦福大学。目前，在SDN领域中，OpenFlow协议是最流行的南向协议之一。&lt;/p&gt;
&lt;p&gt;SDN出现初期，控制平面的表现形式更多的是以单实例的控制器出现，实现SDN的协议也是以OpenFlow为主。所以在SDN发展初期，SDN控制器更多指的是OpenFlow控制器。SDN出现之后，ONF[1]成立。ONF(Open Network Foundation),中文名为“开放网络基金会” ，是致力于推进SDN标准化的一个用户驱动的组织。在ONF的白皮书中，提出了SDN的架构标准，SDN架构1.0版本和1.1版本分别如图3.11和 图3.12[2]所示。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="sdn architecture" src="https://upload.wikimedia.org/wikipedia/commons/e/e6/SDN-architecture-overview-transparent.png" /&gt;&lt;/center&gt;
&lt;center&gt;图3.11 SDN网络架构1.0版本&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="sdnarchiteture1.1" src="http://ww1.sinaimg.cn/mw690/7f593341jw1evl062y0pwj20oa0jdwhv.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图3.12 SDN网络架构1.1版本&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;第一款SDN控制器是NOX，目前NOX的社区状态已经不再活跃。在早期的SDN论文中，NOX作为唯一的控制器，发挥了重要的作用。NOX给后来的控制器开发提供了很好的范例，高层级的编程架构。然而，由于其使用C语言编写，给开发SDN应用带来了许多困难，逐渐在控制器竞争中失去优势。在NOX出现不久之后，其兄弟版本POX面世。POX采用Python语言开发。其内部机制和NOX一样。在SDN发展初期，POX也扮演了相当重要的角色，许多SDN学习者都接触过POX。POX因其简单，易入门而得到广泛的关注和使用，成为SDN入门，学习SDN控制器的很好选择。然而，随着技术的发展，更多优秀的控制器，如采用Python语言开发的控制器代表Ryu，采用Java语言开发的控制器代表FloodLight等纷纷涌现。后者均具有更加成熟的架构，更加优秀的性能，相比之下，POX不具有优势，慢慢在控制器的竞争中处于下风。目前POX的开源社区还是活跃状态，由Murphy McCauley继续运营社区。&lt;/p&gt;
&lt;p&gt;2012年和2013年，Ryu和FloodLight诞生。Ryu使用Python语言开发，FloodLight采用Java语言开发。由于其易用性，性能，架构等均比早先时期的POX/NOX优秀，很快得到了SDN研究者的青睐。&lt;/p&gt;
&lt;p&gt;Ryu是日本NTT公司开发的模块化的控制器。Ryu因其架构清晰、支持OpenFlow全部版本、有社区的Plug-in集成到OpenStack、性能良好和文档齐全等优点获得了许多SDN研究者的关注。同样，在Beacon上改进而来的FloodLight，以其企业级别的优秀性能，开发效率更高的Java语言，模块化的设计等优点得到了偏好Java语言的SDN研究者的青睐。此时的SDN控制器侧重于提升单例性能，支持的南向协议也是以OpenFlow为主。笔者认为可以称之为OpenFlow式SDN的控制器发展中期，然而这个时期非常短。&lt;/p&gt;
&lt;p&gt;SDN经过几年的发展，成为趋势的势头逐渐浮出水面。SDN控制器的发展也因一个重要的SDN“控制器”而展开新的篇章。2013年，由Linux Foundation和多家网络巨头如Cisco、Juniper和Broadcom等公司一起创立的开源项目OpenDaylight。其赞助商、发起者多为设备厂商而非运营商等消费者，其目的在于推出一个通用的SDN控制平台。OpenDaylight不仅仅是一个SDN控制器，它更是一个庞大的开源项目，其中包含许多子项目，而Controller只是其中的一个子项目。OpenDaylight支持多种南向协议，包括OpenFlow(支持1.0和1.3版本）、Netconf和OVSDB等，是一个广义的SDN控制平台，而不是OpenFlow系的狭义SDN控制器。&lt;/p&gt;
&lt;p&gt;OpenDaylight的诞生意味着SDN进入一个崭新的时期，此时SDN的概念发生了改变。SDN控制器应支持多南向协议，而不仅仅局限于OpenFlow。这给业界带来了很多想象空间，会被巨头引导走向不够开放的另一端吗？SDN控制器应该支持分布式集群，即单实例的控制器变成了分布式的控制平台。分布式的控制平台不仅可以管理更大的网络，性能更好，还可以相互容灾备份，提升系统的可靠性。在分布式系统盛行的今天，SDN控制器虽逻辑集中但也需要架构上分布。&lt;/p&gt;
&lt;p&gt;OpenDaylight的社区的会员很多，早期的会员多为设备商。各个厂商均竭尽所能得把自己的思想，产品放到OpenDaylight项目中，如Ciscod的OpFlex。虽然多家参与社区的维护和OpenDaylight的开发，但是Cisco还是占据主导，大多数项目还是Cisco在主导开发。在角力的过程中，有的企业就会有其他的打算，如Big Switch Networks退出OpenDaylight,  Juniper将经历转向了自己的Open Contrial。 OpenContrial是Juniper的商业控制器Contrial的开源版本，其使用C++语言编写，支持OpenFlow协议和Netconf等南向协议。另一方面，也有跟进的企业，增加了对OpenDaylight的投入，如HP将自己升级到了铂金会员。Huawei则兵分多路，一部分人开发OpenDaylight，另一部分人则参与了新生代的控制平台ONOS的开发，还有其他很大一部分人在进行华为敏捷智能网络控制器SNC的开发。虽然OpenDaylight社区势力众多，各自的想法也不一样，但是这并不影响OpenDaylight的性能和在SDN研究者心目中的地位，OpenDaylight依然凭借自己社区强大的技术，在SDN控制器的竞争中成为最具有影响力的控制器之一。许多企业在自己的产品中或者网络中使用到了OpenDaylight, 比如Brocade一直推基于OpenDaylight的商业控制器vaytta。腾讯也在最新的技术分享中提到使用了OpenDaylight管理自己的数据中心网络。&lt;/p&gt;
&lt;p&gt;从2013年底到2014年底这段时间内，OpenDaylight可谓风光无限，提到SDN几乎都会提到OpenDaylight，仿佛OpenDaylight就是SDN控制器的最终形态和最终归属。这一局面，在2014年12月5日被打破了。由On.Lab开发的ONOS面世了。ONOS(Open Network Operating System)是一款同样采用Java语言编写，采用OSGi架构，同样分布式的控制平台产品。其目标是打造一个开放的SDN网络操作系统，市场地位于运营商级别网络市场。ONOS底层模块直接借用FloodLight优秀的模块如Switch模块，不使用YANG语言建模，最新版本使用Raft作为分布式框架。从此，OpenDaylight遇到了新的竞争对手。虽然截至2015年，并没有使用ONOS的案例，但是在未来，凭借自身的优秀性能，ONOS可以取得一部分市场。&lt;/p&gt;
&lt;p&gt;SDN开源控制器除了以上提到的比较流行的控制器之外，也有其他用户比较少的控制器，如Trame,FlowER, LOOM等。笔者参考SDxCentral最新的SDN控制器的数据，将目前SDN开源控制器是否活跃情况列举如下表，先后顺序无关。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;table class="table-bordered table-striped table-condensed"&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;Active&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Not Active&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;FloodLight       &lt;/td&gt;
        &lt;td&gt;Beacon           &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Ryu&lt;/td&gt;
        &lt;td&gt;NOX&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;OpenDaylight&lt;/td&gt;
        &lt;td&gt;NodeFlow&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;ONOS&lt;/td&gt;
        &lt;td&gt;FlowER&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;OpenContrial&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;LOOM&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Trema&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;POX&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;OpenMUL&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;然而目前最神秘，最出名的控制应该不是以上提到的任何一个控制器，而是Google的分布式控制器ONIX，ONIX目前没有开源，相关资料非常少。目前由Nicira、NTT和Google共同开发。2013年，Google在SIGCOMM上发表了论文《B4: Experience with a Globally-Deployed Software Defined WAN》[3]，论文介绍了Google的WAN加速SDN方案，其中使用的控制器就是ONIX。论文发布时，B4已经运行了3年，除了发生过Datapath_id相同导致的错误以外，基本正常运行。该方案将带宽利用率提升到了接近100%的恐怖利用率。即2010年Google已经开发出了整套方案，然后在数据中心之间上线运行，并成功运行了3年，并发表了论文。很明显，Google和整个技术发展不在一个时期，这个案例也是SDN支持者心中的最有力的论据。&lt;/p&gt;
&lt;p&gt;除了ONIX之外，还有许多闭源的商业控制器，如HP的VAN(Virtual Applications Networks)控制器，武汉绿网的GNflush等，更多商业控制器的内容可参考SDxCentral的SDN-Controller-Report 2015B[4]。&lt;/p&gt;
&lt;p&gt;影响SDN控制器发展的因素除了技术因素以外，还有重要的非技术因素，如行业企业对技术的态度等。企业在制定SDN战略时都是从自身的利益出发的，这些战略很大程度上影响着SDN的发展。在一项技术的发展过程中，行业巨头等企业的战略等非技术因素会对技术的发展曲线，发展方向产生非常大的影响。&lt;/p&gt;
&lt;p&gt;自SDN发展以来，业界声音不一。支持者声称这将改变传统网络，打破目前固化的网络架构，带来更灵活，更智能的网络；而反对者则认为这并没有良好的发展前途，因为分布式的优点足以支撑目前的网络运行，而SDN所提倡的集中式虽有优点，但劣势多于优势。这些声音代表了不同利益阵营，所以处于不同利益阵营的企业对SDN的态度也不一而同，读者在接收到对SDN不同的声音时，需考虑其发表者的利益阵营。传统巨头Cisco，态度就很微妙。对于Cisco而言，如果不支持SDN，万一SDN真成为下一个潮流，那么市场损失过大，影响行业地位。如果完全支持，那么在SDN这个崭新的战场，市场重新布局，门槛降低，更多竞争者进入，且追赶者Huawei等企业也会趁机大力发展SDN，最终SDN格局还无法明朗。所以Cisco一方面投入研发精力研究SDN，另一方面，剑走偏锋，推出自己的ACI（Application Centric Infrustructure），企图另辟蹊径占领SDN市场。ACI也是一种广义上的SDN，其控制器为APIC( Application Policy Infrastructure Controller)，但它区别与我们所理解的之前提到的控制器，它并不负责指挥数据层面如何转发流量。所以在ACI中，底层设备Nexus9000才是重点，而非控制器。其使用的南向协议也避开了OpenFlow，而使用了私有协议OpFlex。如此以来，成功避开了SDN白牌交换级的冲击，成功将战场引到了拥有技术壁垒的数据层面产品上。
对于传统网络行业巨头而言，目前稳定市场布局对自己有利，自然不希望新技术打破这一平衡，所以他们对于SDN的态度往往是不够积极。但是为了防止新技术的冲击，他们一定会跟进，也一定会想办法推出兼容产品或者竞争产品，力图在新技术市场上占据有力地位。除了投入研发精力跟进外，还会对有希望的创业公司进行技术收购。若创业公司成长壮大，那么收购是成功的，如果创业公司失败，那也没有太大关系，这笔投资对于巨头而言并非大事。技术收购的策略在技术发展过程经常被使用，所以近些年关于SDN创业公司被收购的新闻屡见不鲜，相信在SDN发展的道路上，技术收购还会继续发生。&lt;/p&gt;
&lt;p&gt;对于第二阵营或者新技术公司而言，必然大力支持SDN的发展。如Huawei大力投入研发精力研发SDN相关产品。不仅在开源项目方面参与OpenDaylight项目，还参与ONOS项目，一方面，跟进OpenDaylight项目不落后，另一方面，企图通过ONOS项目来争取更多的市场。此外，Huawei也大力发展SNC等控制器等SDN产品。和Huawei类似的，HP也在投入经历发展SDN，不仅推出了自己的SDN控制器产品，也推出了SDN交换机等数据平面产品。新技术公司方面，国内的盛科，国外的PICA8等交换机厂家已经抓住SDN发展的机会，推出了许多数据平面产品，占据了一定的SDN市场。配套的数据平面产品的推出必将推动SDN控制平面的发展及落地。&lt;/p&gt;
&lt;p&gt;SDN的发展也给更多的其他领域的竞争者入足的机会，虚拟化产品巨头VMware就是一个很好的例子。瞄准SDN的市场之后，VMware收购了创业公司Nicira，在其Network Virtualization Platform (NVP) 的基础之上，结合自己的vCloud Networking and Security (vCNS) 推出了NSX，从而占据了数据中心网络虚拟化的一部分市场，加入了SDN市场的竞争。新的SDN产品的推出，也给业界推动SDN发展的信心，从而促进SDN控制平台的发展。&lt;/p&gt;
&lt;p&gt;笔者认为，随着技术的发展，网络规模的扩大，SDN控制器将出现分级分域的概念，多控制器之间将出现协同工作的功能。即管理不同网络的控制器运行对应的应用，而不同控制器之间通过东西向接口进行信息同步，从而完成全网的管理。目前在OpenDaylight中实现的SDNi协议即是一种SDN东西向协议的实现方法。未来的SDN控制平面应该是局域集群，全局分级的架构。此外，未来的SDN控制平台会成为网络操作系统形式的存在，目前ONOS就是网络操作系统的示范。除此之外，SDN控制平台将和OpenStack等云管理平台集成运作，这也是当下控制器的一个趋势之一。虽然开发者可以在SDN控制平面上开发部署很多应用，但是未来的SDN控制器将面对特定的网络运行特定的应用，而不会运行全部的应用，甚至于根据不同场景，出现不同的版本的控制平台。&lt;/p&gt;
&lt;p&gt;SDN控制器的竞争最终会优胜劣汰，剩下几款经典的控制器分别占领不同的市场，正如当下的计算机操作系统一般。即不会有任何一款控制器垄断整个市场，不同的控制器将会相互竞争相互促进。此外，短期之内OpenFlow不会失去竞争力，但最终同样会存在多种南向协议相互竞争，竞争是常态，是技术发展的源泉。&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;p&gt;[1] https://www.opennetworking.org/about/onf-overview&lt;/p&gt;
&lt;p&gt;[2] sdn architecture overview:https://www.opennetworking.org/images/stories/downloads/sdn-resources/technical-reports/TR_SDN-ARCH-Overview-1.1-11112014.02.pdf&lt;/p&gt;
&lt;p&gt;[3] Jain S, Kumar A, Mandal S, et al. B4: Experience with a globally-deployed software defined WAN[C]//ACM SIGCOMM Computer Communication Review. ACM, 2013, 43(4): 3-14.&lt;/p&gt;
&lt;p&gt;[4] SDxCentral SDN Controllers Report： https://www.sdxcentral.com/sdn-controllers-report-2015/&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 30 Aug 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-08-30:pages/2015/08/30/sdnkong-zhi-ping-mian-fa-zhan-li-shi-ji-qu-shi.html</guid><category>SDN</category><category>control platform</category></item><item><title>Mininet搭建多控制器拓扑</title><link>http://www.muzixing.com/pages/2015/08/05/mininetda-jian-duo-kong-zhi-qi-tuo-bu.html</link><description>&lt;p&gt;Mininet是一款非常轻巧但是功能很强大的网络模拟器。网络研究者可以使用Mininet创建支持OpenFlow的SDN拓扑。随着SDN研究的发展，多控制器协作成为未来的研究方向，所以使用Mininet构建多控制器网络拓扑也成为一种需求。本篇将讲述如何使用Mininet搭建多控制器网络拓扑。&lt;/p&gt;
&lt;h3&gt;Multi-Controller&lt;/h3&gt;
&lt;p&gt;多控制器有两种理解，一种理解是面向交换机的多控制器。即一个交换机会连接多个控制器，控制器之间的关系可以是equal，也可以是master/slave模式。关于多控制器的介绍，有兴趣的读者可以参考OpenFlow1.3协议的multi-controller部分内容。另一种理解是面向控制器的多控制器。即，多个控制器分别管理各自的数据平面网络，且数据平面之间有链路互联。这种模式下，控制器之间没有关系，控制器所控制的数据平面也没有关系。关于多控制器方面的研究，笔者会在后续的博客中大篇幅介绍。&lt;/p&gt;
&lt;p&gt;本篇将针对这两种理解，介绍如何搭建多控制器的Mininet拓扑。&lt;/p&gt;
&lt;h3&gt;面向交换机的多控制器网络拓扑&lt;/h3&gt;
&lt;p&gt;对于一个交换机而言，可以连接多个控制器，其实现方式非常简单， 在Mininet的源码中已经实现。从Mininet的&lt;a href="https://github.com/mininet/mininet/blob/master/mininet/node.py"&gt;node.py&lt;/a&gt;文件中，我们可以找到有用的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;controllers&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Start OpenFlow reference user datapath.&lt;/span&gt;
&lt;span class="sd"&gt;               Log to /tmp/sN-{ofd,ofp}.log.&lt;/span&gt;
&lt;span class="sd"&gt;               controllers: list of controller objects&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
            &lt;span class="c"&gt;# Add controllers&lt;/span&gt;
            &lt;span class="n"&gt;clist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;tcp:&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;controllers&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ofdlog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/tmp/&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;-ofd.log&amp;#39;&lt;/span&gt;
            &lt;span class="n"&gt;ofplog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/tmp/&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;-ofp.log&amp;#39;&lt;/span&gt;
            &lt;span class="n"&gt;intfs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intfList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;ofdatapath -i &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;intfs&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;#39; punix:/tmp/&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; -d &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                      &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpopts&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;#39; 1&amp;gt; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ofdlog&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; 2&amp;gt; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ofdlog&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; &amp;amp;&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;ofprotocol unix:/tmp/&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;clist&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;#39; --fail=closed &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;#39; 1&amp;gt; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ofplog&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; 2&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ofplog&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; &amp;amp;&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;no-slicing&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpopts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c"&gt;# Only TCReapply if slicing is enable&lt;/span&gt;
                &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# Allow ofdatapath to start before re-arranging qdisc&amp;#39;s&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intfList&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TCReapply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;start函数发起了交换机到控制器的网络连接。传入的参数controllers是一个可迭代的数组，clist是整合之后的控制器信息，包括控制器的IP和控制器的端口。之后调用self.cmd函数启动连接，连接到控制器。&lt;/p&gt;
&lt;p&gt;start函数在UserSwitch和OVSSwitch等交换机类中均有对应实现。所以，只需在启动交换机时，传入对应的控制器列表即可。&lt;/p&gt;
&lt;p&gt;关键代码举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Mininet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OVSSwitch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TCLink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;s1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;controller_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;controller&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;RemoteController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6661&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;controller_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;controller_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其余代码如头文件引入，主函数等请参考后续示例代码。&lt;/p&gt;
&lt;h3&gt;面向控制器的多控制器网络拓扑&lt;/h3&gt;
&lt;p&gt;面向控制器的多控制器网络拓扑定义了多个交换机，并使其分别连接到不同的控制器，从而完成拓扑搭建。在下列示例代码中，我们定义了7个网络分别连接到7个控制器，每一个网络中有5个全连接的交换机，不同网络之间还有链路，使得7个网络彼此联通。代码比较简单，不再赘述，读者可自行阅读。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="c"&gt;#!/usr/bin/python&lt;/span&gt;

    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;        This example create 7 sub-networks to connect 7  domain controllers.&lt;/span&gt;
&lt;span class="sd"&gt;        Each domain network contains at least 5 switches.&lt;/span&gt;
&lt;span class="sd"&gt;        For an easy test, we add 2 hosts for one switch.&lt;/span&gt;
&lt;span class="sd"&gt;        So, in our topology, we have at least 35 switches and 70 hosts.&lt;/span&gt;
&lt;span class="sd"&gt;        Hope it will work perfectly.&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mininet.net&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mininet&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mininet.node&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RemoteController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OVSSwitch&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mininet.cli&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CLI&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mininet.log&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;setLogLevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mininet.link&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Intf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TCLink&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mininet.topo&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Topo&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;


    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiControllerNet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;con_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;Create a network from semi-scratch with multiple controllers.&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;controller_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;switch_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;host_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Mininet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OVSSwitch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TCLink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;con_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;controller&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;RemoteController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6661&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;controller_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*** Creating &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*** Creating switches&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;switch_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;s&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*** Creating hosts&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;host_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;h&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host_num&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*** Creating links of host2switch.&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;host_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;host_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*** Creating interior links of switch2switch.&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;con_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;con_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;con_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*** Creating intra links of switch2switch.&amp;quot;&lt;/span&gt;

        &lt;span class="c"&gt;# 0-4  5-9 10-14 15-19 20-24 25-29 30-34&lt;/span&gt;
        &lt;span class="c"&gt;# domain1 -&amp;gt; others&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="c"&gt;# domain2 -&amp;gt; others&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="c"&gt;# domain3 -&amp;gt; others&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="c"&gt;# domain4 -&amp;gt; others&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="c"&gt;# domain5 -&amp;gt; others&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="c"&gt;# domain6 -&amp;gt; others&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="c"&gt;#domain7 has not need to add links.&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*** Starting network&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;controller_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;_No&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;con_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;con_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;controller_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_No&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
            &lt;span class="n"&gt;_No&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="c"&gt;#print &amp;quot;*** Testing network&amp;quot;&lt;/span&gt;
        &lt;span class="c"&gt;#net.pingAll()&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*** Running CLI&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;CLI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*** Stopping network&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;setLogLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;info&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# for CLI output&lt;/span&gt;
        &lt;span class="n"&gt;multiControllerNet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;con_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sw_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;Mininet功能很强大，基本可以满足日常的科研需求。更多的参考案例，可查看mininet的examples目录。最后，简单的启动脚本可以供参考。该脚本可以启动7个窗口，分别在不同的端口上启动7个ryu控制器，从而使得7个网络的交换机可以连接到对应的网络。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;seq&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;let&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;6660&lt;/span&gt;
        &lt;span class="n"&gt;xterm&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;app$i&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;hold&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="sr"&gt;/app/sim&lt;/span&gt;&lt;span class="n"&gt;ple_switch_13&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;ofp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;
        &lt;span class="n"&gt;done&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;希望自己的研究能够顺利进行，最终面世。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 05 Aug 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-08-05:pages/2015/08/05/mininetda-jian-duo-kong-zhi-qi-tuo-bu.html</guid><category>mininet</category><category>multi-controller</category></item><item><title>Ryu:OpenFlow协议源码分析</title><link>http://www.muzixing.com/pages/2015/07/24/ryuopenflowxie-yi-yuan-ma-fen-xi.html</link><description>&lt;p&gt;Ryu支持OpenFlow所有的版本，是所有SDN控制器中对OpenFlow支持最好的控制器之一。这得益于Ryu的代码设计，Ryu中关于OpenFlow协议的代码量不多。阅读Ryu源码，不仅让我了解到了Ryu的运行细节，也学会了许多的编码知识。这为我当前开发的协议提供了很大的帮助。&lt;/p&gt;
&lt;p&gt;本篇将从交换机与控制器建立连接开始，介绍OpenFlow报文的解析的相关代码实现。关于如何注册handler和发送报文，可查看之前的&lt;a href="http://www.muzixing.com/pages/2014/12/27/ryuhe-xin-yuan-ma-jie-du-ofphandlercontrollerryuapphe-appmanager.html"&gt;RYU核心源码解读：OFPHandler,Controller,RyuApp和AppManager&lt;/a&gt;。该篇侧重点为Ryu整体架构的运作，重点在RyuApp和AppManager;本篇重点在与详细介绍OpenFlow的解析和封装实现。希望对读者提供帮助。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Ofp_handler&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;负责底层数据通信的模块是ofp_handler模块。ofp_handler启动之后，start函数实例化了一个controller.OpenFlowController实例。OpenFlowController实例化之后，立即调用_&lt;em&gt;call_&lt;/em&gt;()函数，call函数启动了server_loop去创建server socket，其handler为domain_connection_factory函数。每当收到一个switch连接，domain_connection_factory就会实例化一个datapath对象。这个对象用于描述交换机的所有行为。其中定义了接收循环和发送循环。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Datapath&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;datapath.serve函数是socket通信收发逻辑的入口。该函数启动了一个绿色线程去处理发送循环，然后本线程负责接收循环的处理。self._send_loop是发送主循环。其主要逻辑为：不断获取发送队列是否有数据，若有，则发送；底层调用的是socket.send_all（）函数, 逻辑比较简单，不加赘述。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;send_thr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_send_loop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# send hello message immediately&lt;/span&gt;
        &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_recv_loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send_thr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinall&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;send_thr&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;接收函数_reck_loop中实现了数据的接收和解析。 重点较多，解释作为代码注释，注释如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;        &lt;span class="nd"&gt;@_deactivate&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_recv_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;bytearray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c"&gt;#初始化一个字节数组&lt;/span&gt;
            &lt;span class="n"&gt;required_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt;   &lt;span class="c"&gt;# ofproto_common模块定义了OpenFlow常用的公共属性         &lt;/span&gt;
                                                            &lt;span class="c"&gt;# 如报头长度=8&lt;/span&gt;
            &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;
                &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;
                &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;required_len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c"&gt;# ofproto_parser是在Datapath实例的父类ProtocolDesc的属性。&lt;/span&gt;
                    &lt;span class="c"&gt;# 用于寻找对应协议版本的解析文件,如ofproto_v1_0_parser.py&lt;/span&gt;
                    &lt;span class="c"&gt;# header函数是解析报头的函数。定义在ofproto_parser.py。&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;required_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;required_len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="k"&gt;break&lt;/span&gt;
                    &lt;span class="c"&gt;# ofproto_parser.msg的定义并没有在对应的ofproto_parser中&lt;/span&gt;
                    &lt;span class="c"&gt;# msg函数的位置和header函数位置一样，都在ofproto_parser.py中。&lt;/span&gt;
                    &lt;span class="c"&gt;# msg返回的是解析完成的消息。&lt;/span&gt;
                    &lt;span class="c"&gt;# msg函数返回了msg_parser函数的返回值&lt;/span&gt;
                    &lt;span class="c"&gt;# ofproto_parser.py中的_MSG_PARSERS记录了不同版本对应的msg_parser。其注册手法是通过@ofproto_parser.register_msg_parser(ofproto.OFP_VERSION)装饰器。&lt;/span&gt;
                    &lt;span class="c"&gt;# 在对应版本的ofproto_parser,如ofproto_v1_0_parser.py中，都有定义一个同名的_MSG_PARSERS字典，这个字典用于记录报文类型和解析函数的关系。此处命名不恰当，引入混淆。&lt;/span&gt;
                    &lt;span class="c"&gt;# parser函数通过@register_parser来将函数注册/记录到_MSG_PARSERS字典中。&lt;/span&gt;

                    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                             &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="c"&gt;# LOG.debug(&amp;#39;queue msg %s cls %s&amp;#39;, msg, msg.__class__)&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="c"&gt;# Ryu定义的Event system很简单，在报文名前加上前缀“Event”,即是事件的名称。&lt;/span&gt;
                        &lt;span class="c"&gt;# 同时此类系带msg信息。&lt;/span&gt;
                        &lt;span class="c"&gt;# 使用send_event_to_obserevrs()函数将事件分发给监听事件的handler，完成事件的分发。&lt;/span&gt;
                        &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_msg_to_ev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_event_to_observers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                        &lt;span class="n"&gt;dispatchers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispatchers&lt;/span&gt;
                        &lt;span class="c"&gt;# handler的注册是通过使用controller.handler.py文件下定义的set_ev_handler作为装饰器去注册。                &lt;/span&gt;
                        &lt;span class="c"&gt;# self.ofp_brick在初始化时，由注册在服务列表中查找名为&amp;quot;ofp_event&amp;quot;的模块赋值。&lt;/span&gt;
                        &lt;span class="c"&gt;# ofp_handler模块的名字为&amp;quot;ofp_event&amp;quot;，所以对应的模块是ofp_handler&lt;/span&gt;
                        &lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt;
                                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_handlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;
                                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dispatchers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
                        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                            &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;required_len&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
                    &lt;span class="n"&gt;required_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt;

                    &lt;span class="c"&gt;# We need to schedule other greenlets. Otherwise, ryu&lt;/span&gt;
                    &lt;span class="c"&gt;# can&amp;#39;t accept new switches or handle the existing&lt;/span&gt;
                    &lt;span class="c"&gt;# switches. The limit is arbitrary. We need the better&lt;/span&gt;
                    &lt;span class="c"&gt;# approach in the future.&lt;/span&gt;
                    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                        &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;&lt;strong&gt;OpenFlow协议实现&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;OpenFlow协议解析部分代码大部分在ofproto目录下，少部分在controller目录下。以下内容将首先介绍ofproto目录下的源码内容，再介绍controller目录下的ofp_event文件。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;strong&gt;init&lt;/strong&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;首先，__init__.py并不为空。该文件定义了两个功能类似的函数get_ofp_module()和get_ofp_modules()，前者用于取得协议版本对应的协议定义文件和协议解析模块，后者则取出整个字典。对应的字典在ofproto_protocol模块中定义。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;ofproto_protocol&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;在ofproto_protocol定义了_versions字典，具体如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;_versions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ofproto_v1_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_0_parser&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;ofproto_v1_2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_2_parser&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_3_parser&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;ofproto_v1_4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_4_parser&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;除此之外，该文件还定义了Datapath的父类ProtocolDesc，此类基本上只完成了与协议版本相关的内容。该类最重要的两个成员是self.ofproto和self.ofproto_parser，其值指明所本次通信所使用的OpenFlow协议的版本以及对应的解析模块。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;ofproto_common&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;ofproto_common文件比较简单，主要定义了OpenFlow需要使用的公共属性，如监听端口，报头长度，报头封装格式等内容。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;ofproto_parser&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;ofproto_parser文件定义了所有版本都需要的解析相关的公共属性。如定义了最重要的基类MsgBase(StringifyMixin)。
StringifyMixin类的定义在lib.stringify文件，有兴趣的读者可自行查看。MsgBase基类定义了最基础的属性信息，具体如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="nd"&gt;@create_list_of_base_attributes&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MsgBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;此外，该类还定义了基础的parser函数和serialize函数。基础的parser函数基本什么都没有做，仅返回一个赋值后的消息体。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="nd"&gt;@classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;msg_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;msg_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;msg_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_buf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;msg_&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;serialize函数分为3部分，self._serialize_pre(), self._serialize_body()和self._serialize_header()。本质上完成了header的序列化。关于body的序列化，将在对应的派生类中得到重写。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;ofproto_v1_0&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;以1.0版本为例介绍ofproto_v1_x.py文件的作用。由于Ryu支持多版本的OpenFlow，所以在ofproto目录下，定义了从1.0到1.5版本的所有代码实现。所以其文件命名为ofproto_v1_x.py，x从[1,2,3,4,5]中获得，分别对应相应的协议版本。&lt;/p&gt;
&lt;p&gt;此类文件最重要的一个目的是定义了所有需要的静态内容，包括某字段的所有选项以及消息封装的格式以及长度。与OpenFlow消息内容相关的有协议的类型，动作的类型，port的类型等。此外对应每一个报文，都需要定义其封装的格式，以及封装的长度。Ryu采用了Python的Struct库去完成数据的解封装工作，关于Struct的介绍将在后续内容介绍。具体定义内容举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="c"&gt;# enum ofp_port&lt;/span&gt;
    &lt;span class="n"&gt;OFPP_MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xff00&lt;/span&gt;
    &lt;span class="n"&gt;OFPP_IN_PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xfff8&lt;/span&gt;   &lt;span class="c"&gt;# Send the packet out the input port. This&lt;/span&gt;
                            &lt;span class="c"&gt;# virtual port must be explicitly used&lt;/span&gt;
                            &lt;span class="c"&gt;# in order to send back out of the input&lt;/span&gt;
                            &lt;span class="c"&gt;# port.&lt;/span&gt;
    &lt;span class="n"&gt;OFPP_TABLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xfff9&lt;/span&gt;     &lt;span class="c"&gt;# Perform actions in flow table.&lt;/span&gt;
                            &lt;span class="c"&gt;# NB: This can only be the destination&lt;/span&gt;
                            &lt;span class="c"&gt;# port for packet-out messages.&lt;/span&gt;
    &lt;span class="n"&gt;OFPP_NORMAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xfffa&lt;/span&gt;    &lt;span class="c"&gt;# Process with normal L2/L3 switching.&lt;/span&gt;
    &lt;span class="n"&gt;OFPP_FLOOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xfffb&lt;/span&gt;     &lt;span class="c"&gt;# All physical ports except input port and&lt;/span&gt;
                            &lt;span class="c"&gt;# those disabled by STP.&lt;/span&gt;
    &lt;span class="n"&gt;OFPP_ALL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xfffc&lt;/span&gt;       &lt;span class="c"&gt;# All physical ports except input port.&lt;/span&gt;
    &lt;span class="n"&gt;OFPP_CONTROLLER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xfffd&lt;/span&gt;        &lt;span class="c"&gt;# Send to controller.&lt;/span&gt;
    &lt;span class="n"&gt;OFPP_LOCAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xfffe&lt;/span&gt;     &lt;span class="c"&gt;# Local openflow &amp;quot;port&amp;quot;.&lt;/span&gt;
    &lt;span class="n"&gt;OFPP_NONE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xffff&lt;/span&gt;      &lt;span class="c"&gt;# Not associated with a physical port.&lt;/span&gt;


    &lt;span class="c"&gt;# enum ofp_type&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_HELLO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="c"&gt;# Symmetric message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_ERROR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c"&gt;# Symmetric message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_ECHO_REQUEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;   &lt;span class="c"&gt;# Symmetric message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_ECHO_REPLY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;     &lt;span class="c"&gt;# Symmetric message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_VENDOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;         &lt;span class="c"&gt;# Symmetric message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_FEATURES_REQUEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;       &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_FEATURES_REPLY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;         &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_GET_CONFIG_REQUEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;     &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_GET_CONFIG_REPLY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;       &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_SET_CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;      &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_PACKET_IN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;      &lt;span class="c"&gt;# Async message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_FLOW_REMOVED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;   &lt;span class="c"&gt;# Async message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_PORT_STATUS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;    &lt;span class="c"&gt;# Async message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_PACKET_OUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;     &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_FLOW_MOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;       &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_PORT_MOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;       &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_STATS_REQUEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;  &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_STATS_REPLY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;    &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_BARRIER_REQUEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;       &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_BARRIER_REPLY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;  &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_QUEUE_GET_CONFIG_REQUEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;      &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;
    &lt;span class="n"&gt;OFPT_QUEUE_GET_CONFIG_REPLY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;        &lt;span class="c"&gt;# Controller/switch message&lt;/span&gt;

    &lt;span class="n"&gt;OFP_HEADER_PACK_STR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;!BBHI&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
    &lt;span class="n"&gt;OFP_MSG_SIZE_MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;65535&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;calcsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFP_HEADER_PACK_STR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;OFP_HEADER_PACK_STR = '!BBHI'的意思是将header按照8|8|16|32的长度封装成对应的数值。在Python中分别对应的是1个字节的integer|一个字节的integer|2个字节的integer|4个字节的integer。&lt;/p&gt;
&lt;p&gt;calcsize函数用于计算对应的format的长度。&lt;/p&gt;
&lt;p&gt;其他内容均为静态的定义，无需赘述。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;ofproto_v1_0_parser&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;本模块用于定义报文的解析等动态内容。模块中定义了与OpenFlow协议对应的Common_struct及message type对应的类。每一个message对应的类都是有MsgBase派生的，其继承了父类的parser函数和serialize函数。若报文无消息体，如Hello报文，则无需重写parser和serialize函数。&lt;/p&gt;
&lt;p&gt;本模块定义了几个重要的全局函数：_set_msg_type，_register_parser，msg_parser和_set_msg_reply。其作用介绍如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;_set_msg_type: 完成类与ofproto模块中定义的报文名字的映射，原因在于ofproto模块定义的名字并不是类名，而解析时需要使用ofproto中的名字。&lt;/li&gt;
&lt;li&gt;_register_parser：完成对应的类与类中的parser函数的映射，当解析函数从ofproto模块的名字映射到类之后，若需要解析，则需从类对应到对应的解析函数。parser函数是一个类函数，所以在使用时必须传入对应的类的对象作为参数。&lt;/li&gt;
&lt;li&gt;msg_parser：从_MSG_PARSERS中获取对msg_type的parser，并返回解析之后的内容。&lt;/li&gt;
&lt;li&gt;_set_msg_reply：完成该类与对应的回应报文的映射。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;源码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_set_msg_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sd"&gt;&amp;#39;&amp;#39;&amp;#39;Annotate corresponding OFP message type&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_set_cls_msg_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cls_msg_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_set_cls_msg_type&lt;/span&gt;


    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_register_parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sd"&gt;&amp;#39;&amp;#39;&amp;#39;class decorator to register msg parser&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cls_msg_type&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cls_msg_type&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_MSG_PARSERS&lt;/span&gt;
        &lt;span class="n"&gt;_MSG_PARSERS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cls_msg_type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;


    &lt;span class="nd"&gt;@ofproto_parser.register_msg_parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;msg_parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_MSG_PARSERS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_set_msg_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_reply&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sd"&gt;&amp;#39;&amp;#39;&amp;#39;Annotate OFP reply message class&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_set_cls_msg_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cls_msg_reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg_reply&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_set_cls_msg_reply&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;报文如果有消息体，则需要重写parser函数或者serialize函数，具体根据报文内容而不一样。此处，分别以Packet_in和Flow_mod作为parser的案例和serialize的案例，示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="nd"&gt;@_register_parser&lt;/span&gt;
    &lt;span class="nd"&gt;@_set_msg_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPT_PACKET_IN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OFPPacketIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MsgBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFPPacketIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer_id&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total_len&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;

        &lt;span class="nd"&gt;@classmethod&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="c"&gt;# 解析头部，获取msg&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFPPacketIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                 &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c"&gt;# 解析body,获取packet_in相关字段。&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_PACKET_IN_PACK_STR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c"&gt;# 将ofproto.OFP_PACKET_IN_SIZE长度之外的buf内容，赋值给data&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_PACKET_IN_SIZE&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_len&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="c"&gt;# discard padding for 8-byte alignment of OFP packet&lt;/span&gt;
                &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_len&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;


    &lt;span class="nd"&gt;@_set_msg_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPT_FLOW_MOD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OFPFlowMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MsgBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;idle_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hard_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_DEFAULT_PRIORITY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;0xffffffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_NONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFPFlowMod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idle_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;idle_timeout&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hard_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hard_timeout&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer_id&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_serialize_body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c"&gt;# 封装的起点是offset&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_MATCH_SIZE&lt;/span&gt;
            &lt;span class="c"&gt;# 按照ofproto.OFP_FLOW_MOD_PACK_STR0的格式，将对应的字段封装到self.buf中&lt;/span&gt;
            &lt;span class="n"&gt;msg_pack_into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_FLOW_MOD_PACK_STR0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idle_timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hard_timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_FLOW_MOD_SIZE&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c"&gt;# 序列化action&lt;/span&gt;
                    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;此模块代码量大，包括OpenFlow协议对应版本内容的完全描述。分类上可分为解析和序列化封装两个重点内容。读者在阅读源码时可根据需求阅读片段即可。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Inet &amp;amp; ether&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;这两个模块非常简单，ether定义了常用的以太网的协议类型及其对应的代码；inet定义了IP协议族中不同协议的端口号，如TCP=6。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;oxm_field&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;在1.3等高版本OpenFlow中，使用到了oxm_field的概念。oxm全称为OpenFlow Extensible Match。当OpenFlow逐渐发展成熟，flow的match域越来越多。然而很多通信场景下使用到的匹配字段很少，甚至只有一个。OXM是一种TLV格式，使用OXM可以在下发流表时仅携带使用到的match域内容，而放弃剩余的大量的match域。当使用的match域较少时，统计概率上会减少报文传输的字节数。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;nx_match&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;该文件定义了nicira extensible match的相关内容。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;ofp_event&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;这个模块的位置并不再ofproto，而位于controller目录下。controller模块下的event定义了基础的事件基类。ofp_event模块完成了OpenFlow报文到event的生成过程。模块中定义了EventOFPMsgBase(event.EventBase)类和_ofp_msg_name_to_ev_name(msg_name)等函数的定义。相关函数都非常的简单，可从函数名了解到其功能，不再赘述。示例代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_ofp_msg_name_to_ev_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Event&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;msg_name&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;文件中最后一句代码很重要，最后一句完成了服务的注册，告知app_manager,本模块需要以来于服务：ofp_handler,即需要启动ofp_handler才能完成本模块的工作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu.controller.ofp_handler&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;&lt;strong&gt;Struct lib&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Python的&lt;a href="https://docs.python.org/2/library/struct.html"&gt;struct&lt;/a&gt;库是一个简单的，高效的数据封装\解封装的库。该库主要包含5个函数，介绍如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;struct.pack(fmt, v1, v2, ...)： 将V1,V2等值按照对应的fmt(format)进行封装。&lt;/li&gt;
&lt;li&gt;struct.pack_into(fmt, buffer, offset, v1, v2, ...)：将V1,V2等值按照对应的fmt(format)封装到buffer中，从初始位置offset开始。&lt;/li&gt;
&lt;li&gt;struct.unpack(fmt, string): 将string按照fmt的格式解封&lt;/li&gt;
&lt;li&gt;struct.unpack_from(fmt, buffer[offset=0，])： 按照fmt的格式，从offset开始将buffer解封。&lt;/li&gt;
&lt;li&gt;struct.calcsize(fmt)： 计算对应的fmt的长度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更家详细的封装语法，请查看struct对应的链接。此处仅对常用语法进行介绍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;！：大端存储&lt;/li&gt;
&lt;li&gt;c: char&lt;/li&gt;
&lt;li&gt;B： 一个字节长度，unsigned char.&lt;/li&gt;
&lt;li&gt;H：两个字节，16位&lt;/li&gt;
&lt;li&gt;I： 4个字节，int型&lt;/li&gt;
&lt;li&gt;Q: 64bits&lt;/li&gt;
&lt;li&gt;x: padding&lt;/li&gt;
&lt;li&gt;3x：3个字节的padding&lt;/li&gt;
&lt;li&gt;5s: 5字节的字符串&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Ryu对OpenFlow协议的支持非常好，入门也比较容易，网上的资源也比较多，是一个非常值得推荐的SDN控制器。本篇对Ryu中从底层的数据收发到OpenFlow报文的解析的代码进行简要的分析，希望对读者有一定的帮助。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 24 Jul 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-07-24:pages/2015/07/24/ryuopenflowxie-yi-yuan-ma-fen-xi.html</guid><category>ryu</category><category>openflow</category></item><item><title>SDN网络感知服务与最短路径应用</title><link>http://www.muzixing.com/pages/2015/07/08/sdnwang-luo-gan-zhi-fu-wu-yu-zui-duan-lu-jing-ying-yong.html</link><description>&lt;p&gt;本文将介绍RYU中的网络感知服务，与基于网络服务的最短路径应用，主要内容包括网络资源感知模块，网络监控模块和基于网络信息的最短路由模块介绍。在一个真实的网络环境下，需掌握网络的实时动态，包括网络的资源以及网络流量状况，其中网络的信息包括交换机，端口，主机的信息，以及基于流的流量统计信息和基于端口的流量统计信息。在掌握这些关键的网络信息后，控制器就可以根据这些信息作出当下最正确的路由决策，完成网络的通信。&lt;/p&gt;
&lt;h3&gt;网络资源感知&lt;/h3&gt;
&lt;p&gt;网络资源感知模块用于感知网络资源的实时变化，包括拓扑信息以及主机信息的变化。任何网络应用，可达性都是最基本的要求。SDN网络的集中控制，使得控制器可以根据全局的信息作出最佳决策而无需在交换节点上采用分布式的路由算法。所以感知网络资源是SDN应用最基础的一项服务。网络资源感知模块源码链接：&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_awareness/network_awareness.py"&gt;Network_Awareness&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;实现该模块的类为NetworkAwareness类，该类描述如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NetworkAwareness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;OFP_VERSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;SLEEP_PERIOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="n"&gt;IS_UPDATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NetworkAwareness&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;topology_api_app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;awareness&amp;quot;&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link_to_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;       &lt;span class="c"&gt;# (src_dpid,dst_dpid)-&amp;gt;(src_port,dst_port)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;access_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;       &lt;span class="c"&gt;# {(sw,port) :[host1_ip]}&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switch_port_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;  &lt;span class="c"&gt;# dpip-&amp;gt;port_num&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;access_ports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;       &lt;span class="c"&gt;# dpid-&amp;gt;port_num&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interior_ports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;     &lt;span class="c"&gt;# dpid-&amp;gt;port_num&lt;/span&gt;

        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DiGraph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pre_graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DiGraph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pre_access_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pre_link_to_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shortest_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discover_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_discover&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其中数据结构与其作用关系如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;link_to_port字典存储交换机之间链路与端口的映射关系；&lt;/li&gt;
&lt;li&gt;access_table字典存储主机的接入信息；&lt;/li&gt;
&lt;li&gt;switch_port_table存储交换机端口列表；&lt;/li&gt;
&lt;li&gt;access_ports存储外向端口（与终端连接的接口）；&lt;/li&gt;
&lt;li&gt;interior_ports存储内部端口;&lt;/li&gt;
&lt;li&gt;grap存储网络拓扑图, pre_graph是上一次的网络拓扑，均用 networkx的有向图存储；&lt;/li&gt;
&lt;li&gt;pre_link_to_port等带有pre前缀的数据结构用于保存上一次获取的信息，用于和当前获取信息做比较。&lt;/li&gt;
&lt;li&gt;_discover函数是主循环函数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在_discover函数中，周期执行get_topology和是show_topology函数。在get_topology函数中，控制器可以获取到网络中的交换机和端口信息、链路信息、主机接入信息等。此外，控制器通过实时检测网络变化的异步事件来更新网络资源信息。show_topology函数则是将网络信息格式化地展示在终端中。由于前端开发能力有限，目前仅仅简单将后台数据展现在终端。&lt;/p&gt;
&lt;p&gt;Note that:可以通过置位IS_UPDATE来控制是否输出信息。此外，若拓扑信息不发生变化，将不打印，即仅打印拓扑一次，直至拓扑更新。可以将判断中的and 修改为or,即可每次都打印。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="network info" src="http://ww1.sinaimg.cn/mw690/7f593341jw1f48kxj1gewj20hk0c7jub.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图1.网络资源信息&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;网络流量监控&lt;/h3&gt;
&lt;p&gt;网络的信息除了物理资源信息以外，还包括逻辑链路等信息；获取流表信息可获得对应的逻辑连接信息。此外，获取网络的数据流量的统计情况对防止网络故障，合理优化网络等方面起到了重要的作用。网络流量监控模块实现了对端口流量和流表项流量的监控。应用可周期获取到流量信息，并在终端中输出展示。源码链接：&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_awareness/network_monitor.py"&gt;Network_Monitor&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;实现网络流量监控的类为：Network_Monitor,具体描述如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NetworkMonitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;OFP_VERSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;SLEEP_PERIOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NetworkMonitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;monitor&amp;#39;&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapaths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flow_stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flow_speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;monitor_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_monitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其中数据结构的作用如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;datapaths记录与控制器连接的datapath;&lt;/li&gt;
&lt;li&gt;port_stats保存端口的统计信息；&lt;/li&gt;
&lt;li&gt;port_speed保存端口的速率信息；&lt;/li&gt;
&lt;li&gt;flow_stats保存流的统计信息；&lt;/li&gt;
&lt;li&gt;flow_speed保存流的速率信息；&lt;/li&gt;
&lt;li&gt;stats保存所有的统计信息；&lt;/li&gt;
&lt;li&gt;port_link保存link的特性信息；&lt;/li&gt;
&lt;li&gt;_monitor函数为主循环函数；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在主循环函数中，周期调用了self._request_stats和self.show_stat函数，前者用于下发统计信息请求报文，后者用于展现统计信息。统计信息回复报文处理函数为：_flow_stats_reply_handler和_port_stats_reply_handler，两者分别使用的@set_ev_cls装饰符，注册监听了对应的事件。至此流量统计模块已经完成了闭环，可以作为底层的服务为上层的应用提供实时的流量统计信息。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="port stats" src="http://ww1.sinaimg.cn/mw690/7f593341jw1etvgsxtlpfj21040f5thy.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图2. 端口流量统计信息&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="flow stats" src="http://ww2.sinaimg.cn/mw690/7f593341jw1etvgsx513ij20mt0ctgs9.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图3. 流表项流量统计信息&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;基于网络资源的最短路径&lt;/h3&gt;
&lt;p&gt;基于以上的网络资源感知模块与网络流量监控模块提供的数据，我们可以做很多事情，比如负载均衡等流量调度应用，有比如安全接入等安全应用。本小节介绍基于网络资源的最短路径应用。衡量最短路径的参考系是跳数，稍加修改可以变为剩余带宽，延时或者多参考系加权的方案。源代码链接：&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/network_awareness/shortest_forwarding.py"&gt;shortest_forwarding&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;最短路径应用流程图如下：
&lt;center&gt;&lt;img alt="shortest path" src="http://ww3.sinaimg.cn/mw690/7f593341jw1etvhwx97yjj20870dxq31.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图4, 最短路由流程图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;首先，查询主机表，若查找成功，则查询主机位置表，之后直接由控制器将ARP数据包发送给对应的端口，此时控制器并不做ARP的代理。当目标主机回复ARP时，将数据包直接发送到源主机的接入端口。从而完成了ARP的学习过程。由于此时已经掌握了主机的接入信息以及网络信息，当ICMP或其他数据包出发packet_in事件时，则可根据源目两个IP查询到接入交换机，再依据拓扑信息，计算最短路径，从而完成最短路由。若希望使用其他的参考标准来计算最短路径，只需修改计算最短路径的算法即可。&lt;/p&gt;
&lt;p&gt;在网络初始化时，控制器并没有办法发现沉默的主机，原因在于我们没有进行DHCP分配，导致控制器没有掌握主机的IP/MAC信息。所以第一步我们需要处理的数据包是ARP。处理流程具体如下所示：&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="arp_handler" src="http://ww4.sinaimg.cn/mw690/7f593341jw1etvhwx229pj209y0aujri.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图5. ARP处理流程图&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note that&lt;/strong&gt;:本应用假设主机发起通信时需先发起ARP，不可通过其他途径获取到ARP的信息，否则控制器无法获得目的端主机接入信息，则无法完成路由。对于域外的主机，只需在找不到目的端时，将其送给出口网关即可。此时需使用到子网掩码，网段，路由等概念。本应用仅针对简单局域网计算路径。&lt;/p&gt;
&lt;p&gt;&lt;center&gt;&lt;img alt="shortest path" src="http://ww3.sinaimg.cn/mw690/7f593341jw1etvgsxenqtj20gy0cradi.jpg" /&gt;&lt;/center&gt;
&lt;center&gt;图6. 最短路径转发&lt;/center&gt;&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;网络感知服务对于SDN网络而言非常重要，是一切网络应用的基础。充分利用网络资源的信息，可以对网络进行优化，提高网络的安全性。以上的Network_aware和monitor模块均可以直接做为APP的service app（在RYU中需在_CONTEXTS添加）提供数据服务，希望可以给有需要的读者提供一些帮助。&lt;/p&gt;
&lt;h3&gt;更新&lt;/h3&gt;
&lt;p&gt;由于之前的设计不够好，都是自己造的一些轮子，不够优美。所以在2016年4月13日将这份代码重构了。更多详情请关注github。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 08 Jul 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-07-08:pages/2015/07/08/sdnwang-luo-gan-zhi-fu-wu-yu-zui-duan-lu-jing-ying-yong.html</guid><category>SDN</category><category>ryu</category><category>network_aware</category></item><item><title>初学者的SDN学习之路</title><link>http://www.muzixing.com/pages/2015/06/22/chu-xue-zhe-de-sdnxue-xi-zhi-lu.html</link><description>&lt;p&gt;Software Defined Network顾名思义软件定义网络，可以简单地分为网络和软件两个部分：软件和网络。此外，通过使用OpenFlow协议来实现SDN是一种较为普遍的方式，
所以本篇将从软件和网络以及OpenFlow三个方面进行介绍。在研究SDN的研究者之中，有相当大比例的网络工程师，他们了解网络，精通网络，然而却并不了解软件开发。除此之外，还有很大比例的研究者是软件工程师，他们软件开发能力出色，然而并不了解网络运作的机制，在接触SDN之前，他们的范围仅仅只是应用层，底层的东西交给全交给主机的协议栈了。还有一部分同学是像我这样，通信工程出身，学的是物理层的编码解码，误码率，电磁波。不像计算机专业那些学生一样，学习各种语言，操弄各种编译器，混迹于github这种全球最大的男性交友网站。剩下最后一种就是又懂网络，又懂编程。这种人，我一般称之为老师，是用来请教问题的，比如地球-某某老师。一般的,他们不屑于看到这种文章，太low。&lt;/p&gt;
&lt;p&gt;本篇主要的目标用户是对网络和软件开发都不太了解，或者网络和编程开发只擅长一种的研究者。由于我也是一个初学者，所以仅当做经验分享吧。如有表达不对的地方，敬请指出，万分感谢。&lt;/p&gt;
&lt;h2&gt;网络&lt;/h2&gt;
&lt;p&gt;软件定义网络，如果不了解网络，那如何去定义一个你不了解的东西？如果不知道网络中存在的问题，如何使用SDN来改善？所以网络知识至关重要。然而作为一个初学者，并不需要网络各个方面都精通，也做不到，仅需学习基础知识，并选择一个研究场景即可。&lt;/p&gt;
&lt;h3&gt;计算机网络&lt;/h3&gt;
&lt;p&gt;学习网络的必修课是计算机网络。计算机网络讲述的是计算机网络的运作机制，都是极其基础重要的知识。谢希仁前辈的《计算机网络》是从底层往上层介绍，从物理层的hub到数据层的网桥和交换机，到网络层的路由器，最后讲到TCP/UDP的传输层，止于应用层，适合有通信背景的学习者。《计算机网络：自顶向下方法》则是从另一个角度出发，从应用层向下介绍，摆脱了物理层的枯燥，这样的思路更适合学习计算机出门的学习者。《CCNA学习指南》也是推荐的书籍之一，前部分内容讲解计算机网络非常简单明了，更贴近于真实网络规划，可以当做计算机网络的进阶书籍阅读。&lt;/p&gt;
&lt;p&gt;学习完计算机网络之后，学习者应该懂得二层交换、三层路由，了解到OSI七层协议栈，也了解了TCP/IP，ARP,ICMP,DNS, DHCP。作为检验标准，读者可以尝试介绍一个客户端主机和跨网段的服务器进行通信的流程。&lt;/p&gt;
&lt;p&gt;关于网络协议，只需了解主要的一两种，其他了解其作用即可，因为协议实在太多了，没有必要学完。RIP、BGP、OSPF和IS-IS需要了解。如果研究的课题与路由协议相关，则可详细学习，初期不建议深入学习。学习成果检验是对比路由协议的差异，如RIP的广播路由信息和OSPF的告知邻居。&lt;/p&gt;
&lt;p&gt;ARP,ICMP，DNS,DHCP这几种功能型报文非常重要，均需了解其工作流程，具体的报文格式，可适当了解关键字段。项目需要时再深入研究。&lt;/p&gt;
&lt;p&gt;TCP/UDP的差别需要牢记，适合的应用场景也许了解。关于TCP的状态机，建议尝试记忆，TCP的三次握手建立连接，四次握手释放连接是面试高频题。&lt;/p&gt;
&lt;p&gt;应用层的仅需了解若干常用协议如SMTP,POP3，HTTP及其对应的传输层的端口号即可。&lt;/p&gt;
&lt;h3&gt;网络场景&lt;/h3&gt;
&lt;p&gt;当学习了基础的网络知识，学习者已经具备了一定知识储备，对网络也有了基础的了解。然而现网之复杂，并不是看了一本《计算机网络》就可以了解的。网路可以按照规模分为局域网，城域网，广域网，也可以按照功能划分成接入网，传输网和核心网。当然按照场景划分就更多了。云计算网络的典型场景数据中心网络是目前研究的热门领域。以校园网为代表的园区网也是较为常见的SDN应用部署场景。跨数据中心的互连互通、WAN的研究则是研究的另一个大方向。&lt;/p&gt;
&lt;p&gt;选择一个自己喜欢的应用场景，进行深入研究，并根据需求学习相关知识，会大大提高学习的效率。比如我选择学习数据中心网络，所以我需要学习一些云计算的知识，需要了解数据中心中的网络架构。我推荐《腾云：云计算和大数据时代的网络技术揭秘》作为云计算网络知识的科普书籍。书中介绍了很多有用的知识，包括云计算的起源，云计算和网络的关系，网络安全，以及数据中心网络中的一些关键网络技术。读完你应该了解到什么是TOR和EOR，知道了刀片服务器，了解到VN-TAG是用来标识虚拟机到TOR的流量的，了解到VXLAN和NVGRE的作用，了解到交换机还可以组装的，除了OVS之外还有NEXUS 1000v等产品。读完这本书，能对现网的一些技术，以及产品有一些科普性质的了解，对后续深入学习研究有很大帮助。&lt;/p&gt;
&lt;p&gt;相信有了前面计算机网络知识作为铺垫，再选定一个特定的研究场景，网络方面的学习已经不成问题。&lt;/p&gt;
&lt;h2&gt;软件开发&lt;/h2&gt;
&lt;p&gt;软件开发是SDN学习中另一个重要方面，这方面我同样不是行家，我也是新手，所以一下言论仅当做自己的经验介绍。&lt;/p&gt;
&lt;h3&gt;选择一门语言，选择一个控制器&lt;/h3&gt;
&lt;p&gt;根据自己的喜好，选择一门语言，然后根据语言，选择一个对应的控制器，这是开发的第一步。如我自己，在折腾了C/C++,Java,Python之后，最终还是皈依到了Python大法的旗下。根据Python语言，我选择了由Python语言写的POX。POX无需安装，直接可以运行。同时，POX代码简单，初学者只需阅读pox/forwarding文件夹下的代码即可。&lt;/p&gt;
&lt;p&gt;根据我们已有的网络知识，我们基本可以看懂pox/forwarding文件夹下的程序逻辑。以l2_learning.py为例，该文件完成了一个简单的二层交换的应用，其逻辑为：记录MAC地址和Port的对应关系，转发时，查询MactoPort表，若查询成功，则转发，若失败则泛洪。后来RYU出现了，封装更好的，性能更好的RYU成为了我的首选。&lt;/p&gt;
&lt;p&gt;在编程的过程中，需要进行程序设计，其中设计的算法以及数据结构的知识在这里不多介绍，有兴趣的读者可以自行学习。&lt;/p&gt;
&lt;h3&gt;以项目为导向，先写起来&lt;/h3&gt;
&lt;p&gt;阅读源码需要有明确的目的性。最开始可以先尝试读一些简单的如Simple switch之类的代码，掌握一些简单的API的使用，理解基础的内容，然后再进行深入的源码阅读。&lt;/p&gt;
&lt;p&gt;在进一步学习SDN开发时，建议以项目为导向，先写起来，在尝试中去解决问题。在写的过程中遇到问题再去查看源码找关键点，如此一来学习非常有效率，且学到的东西很快就可以用上，学习效果好。特别是在OpenFlow协议已经经过多个版本的扩张，目前内容已经非常多的情况下，选择性学习能帮助你降低学习的压力，提高学习的效率。&lt;/p&gt;
&lt;p&gt;时间充裕的情况下，你可以选择好好阅读那些你认为重要的代码。比我在经历了多个APP开发之后，我觉得我需要好好了解一下RYU的内部机制了。所以我花了三天，把从底层socket到协议解析，到事件分发到handler注册的代码认真看了一遍，收益颇多。&lt;/p&gt;
&lt;h3&gt;学会Debug&lt;/h3&gt;
&lt;p&gt;写程序容易，调程序难。掌握正确的调试方法能大大提高开发的效率。&lt;/p&gt;
&lt;p&gt;为提高调试的效率，在程序设计的时候就需要非常注意。写程序时需要注意程序的设计，比如成端的逻辑尽可能写成函数；一个函数不得过长，最好别超过一个屏幕的行数；尽可能模块化地编程，可以提高代码的重用率，将错误域缩小到某模块，某函数，容易定位错误。在调试的过程中，控制变量的思维方式可以大大提升效率。其他编码风格方面的要求，建议按照google的PEP8风格进行代码编写。&lt;/p&gt;
&lt;p&gt;对操作系统的熟悉和理解也将大大提高开发效率。熟悉Linux的基本操作是必须的，如果不清楚，你可能需要自学一下linux和shell。在调试的过程中，错误显示一般是英文，所以能读懂错误信息，并学会谷歌是一项必备的技能。一般的问题谷歌都可以解决。另外，加几个SDN的技术群也是提高DEBUG效率的一个重要手段。&lt;/p&gt;
&lt;p&gt;关于开发的建议还有，构建一套适合自己的、高效的开发环境，以及做好版本控制。比如我自己，我只用sublime编译器，编译运行和调试都直接在终端中进行。版本控制使用git。版本控制的重要性不许赘述，详情谷歌。&lt;/p&gt;
&lt;h2&gt;OpenFlow&lt;/h2&gt;
&lt;p&gt;目前应用最广泛的SDN实现协议:OpenFlow,是学习SDN中必须要学的核心内容。在设计一个SDN的应用时，需要以下的步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;明确网络应用的逻辑&lt;/li&gt;
&lt;li&gt;明确对应的操作所采用的OpenFlow报文&lt;/li&gt;
&lt;li&gt;根据应用逻辑以及OpenFlow协议进行编程开发&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如一个简单的二层交换机，首先我们明确了他的运作机理是MAC学习和转发，然后明确转发所需要使用的OpenFlow报文是:packet_out和Flow_mod，最后根据应用逻辑以及OpenFlow协议对应的报文，进行编程开发。&lt;/p&gt;
&lt;p&gt;所以我们可以知道OpenFlow在SDN应用中的重要性。&lt;/p&gt;
&lt;p&gt;OpenFlow经过这几年的发展已经从1.0版本发展到了1.5版本，初学者在学习的时候需要注意顺序。建议先学习OF1.0版本，再学习OF1.3版本，更高版本根据需要进行学习。&lt;/p&gt;
&lt;p&gt;OpenFlow1.0版本是OpenFlow火起来时的第一个版本，其内容并不多，Match域仅有12个字段，动作种类也不多，同时也是单流表。对于初学者而言，学习1.0版本可以大大降低学习压力，掌握OpenFlow核心内容。在正确理解SDN，以及可以使用OpenFlow1.0协议开发SDN应用之后，可尝试学习1.3版本协议。1.3版本较1.0版本内容大幅增加。经过几个版本的迭代，OpenFlow1.3版本协议已经有了三种表：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;flow table&lt;/li&gt;
&lt;li&gt;group table&lt;/li&gt;
&lt;li&gt;meter table&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;动作种类也得到了拓展，多流表的概念也变得成熟，Match匹配域已经多达几十个，所以这时OpenFlow已经将Match域分成几类,并以OXM的形式呈现出来。多控制器写作的概念在1.3版本中也已经相当成熟。&lt;/p&gt;
&lt;p&gt;OpenFlow1.3版本为SDN应用开发提供了很多便捷，开发人员可以利用多流表，设计更多复杂的应用逻辑。作为一个比较稳定的版本，1.3版本成为继1.0版本之后控制器支持最多的版本，所以此版本是SDN学习者应该要学习的。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;SDN学习与其他研究方向相比，要求较高，需要了解软件开发以及网络，学习起来，并不太容易。同样作为初学者，我从大三开始接触，有幸有学长带着入门，再后来由于网络知识的缺陷，一度陷入不知道做什么的状态。恶补了网络知识之后，才慢慢走上正轨。然后最近我又遇到了编程上的难题，急需恶补，急需努力提升自己的开发能力。本篇学习笔记，是几年来学习的粗略总结，希望对SDN初学者有帮助。&lt;/p&gt;
&lt;p&gt;最后，兴趣是最好的老师，如果你喜欢SDN这个方向，就会学得很快，比如最近一个学弟兼老乡北邮-毛健炜就进步飞快。如果在学习的过程中没有成就感，没有乐趣，也可以试试别的方向，做自己喜欢的事最重要。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Mon, 22 Jun 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-06-22:pages/2015/06/22/chu-xue-zhe-de-sdnxue-xi-zhi-lu.html</guid><category>SDN</category></item><item><title>Graph algorithms: Prim,Kruskal, Dijkstra, Floyd</title><link>http://www.muzixing.com/pages/2015/05/31/graph-algorithms-primkruskal-dijkstra-floyd.html</link><description>&lt;p&gt;最近有了一点点空闲时间，想想以后的项目肯定是需要用到图中的路径算法，于是花了一些时间把4大经典算法实现了一遍。算法实现水平不高，时间复杂度都太高了一点。但是逻辑相对比较清晰，测试结果正确。如果读者发现算法中的问题，敬请指出，万分感谢。&lt;/p&gt;
&lt;h3&gt;Prim&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://zh.wikipedia.org/wiki/%E6%99%AE%E6%9E%97%E5%A7%86%E7%AE%97%E6%B3%95"&gt;Prim&lt;/a&gt;算法是最小生成树算法的一种，其算法逻辑为：&lt;/p&gt;
&lt;p&gt;从单一顶点开始，普里姆算法按照以下步骤逐步扩大树中所含顶点的数目，直到遍及连通图的所有顶点。
输入：一个加权连通图，其中顶点集合为V，边集合为E；&lt;/p&gt;
&lt;p&gt;初始化：Vnew = {x}，其中x为集合V中的任一节点（起始点），Enew = {}；
重复下列操作，直到Vnew = V：&lt;/p&gt;
&lt;p&gt;1：在集合E中选取权值最小的边（u,v），其中u为集合Vnew中的元素，而v则是V中没有加入Vnew的顶点（如果存在有多条   满足前述条件即具有相同权值的边，则可任意选取其中之一）；
2：将v加入集合Vnew中，将（u, v）加入集合Enew中；&lt;/p&gt;
&lt;p&gt;输出：使用集合Vnew和Enew来描述所得到的最小生成树。&lt;/p&gt;
&lt;p&gt;算法实现采用数据结构为邻接矩阵,实现如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;prim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;

        &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;inf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="k"&gt;continue&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                        &lt;span class="n"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
                        &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;


    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;graph_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph_dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;s12&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Kruskal&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://zh.wikipedia.org/wiki/%E5%85%8B%E9%B2%81%E6%96%AF%E5%85%8B%E5%B0%94%E6%BC%94%E7%AE%97%E6%B3%95"&gt;Kruskal&lt;/a&gt;是另一种最小生成树的算法，相比Prim算法，Kruskal算法采用避圈法进行最小树生长。算法逻辑为：&lt;/p&gt;
&lt;p&gt;1：新建图G，G中拥有原图中相同的节点，但没有边
2：将原图中所有的边按权值从小到大排序
3：从权值最小的边开始，如果这条边连接的两个节点于图G中不在同一个连通分量中，则添加这条边到图G中
4：重复3，直至图G中所有的节点都在同一个连通分量中&lt;/p&gt;
&lt;p&gt;实现代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;kruskal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;

        &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   
        &lt;span class="n"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;inf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="k"&gt;continue&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                        &lt;span class="n"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
                        &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;

            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;


    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;graph_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kruskal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Dijkstra&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://zh.wikipedia.org/wiki/%E6%88%B4%E5%85%8B%E6%96%AF%E7%89%B9%E6%8B%89%E7%AE%97%E6%B3%95"&gt;Diikstra&lt;/a&gt;算法是用于计算某源点到其他节点的最短路径的算法。其算法逻辑为：&lt;/p&gt;
&lt;p&gt;这个算法是通过为每个顶点 v 保留目前为止所找到的从s到v的最短路径来工作的。初始时，原点 s 的路径长度值被赋为 0 （d[s] = 0），若存在能直接到达的边（s,m），则把d[m]设为w（s,m）,同时把所有其他（s不能直接到达的）顶点的路径长度设为无穷大，即表示我们不知道任何通向这些顶点的路径（对于 V 中所有顶点 v 除 s 和上述 m 外 d[v] = ∞）。当算法结束时，d[v] 中存储的便是从 s 到 v 的最短路径，或者如果路径不存在的话是无穷大。 Dijkstra 算法的基础操作是边的拓展：如果存在一条从 u 到 v 的边，那么从 s 到 v 的最短路径可以通过将边（u, v）添加到尾部来拓展一条从 s 到 v 的路径。这条路径的长度是 d[u] + w(u, v)。如果这个值比目前已知的 d[v] 的值要小，我们可以用新值来替代当前 d[v] 中的值。拓展边的操作一直运行到所有的 d[v] 都代表从 s 到 v 最短路径的花费。这个算法经过组织因而当 d[u] 达到它最终的值的时候每条边（u, v）都只被拓展一次。
算法维护两个顶点集 S 和 Q。集合 S 保留了我们已知的所有 d[v] 的值已经是最短路径的值顶点，而集合 Q 则保留其他所有顶点。集合S初始状态为空，而后每一步都有一个顶点从 Q 移动到 S。这个被选择的顶点是 Q 中拥有最小的 d[u] 值的顶点。当一个顶点 u 从 Q 中转移到了 S 中，算法对每条外接边 (u, v) 进行拓展。&lt;/p&gt;
&lt;p&gt;算法实现如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dijkstra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;type_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;type_&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type_&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:[]}}&lt;/span&gt;
        &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;distance_graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;inf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                 &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;new_dist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new_dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_dist&lt;/span&gt;
                        &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
                        &lt;span class="n"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
                        &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_dist&lt;/span&gt;


            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;distance_graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;

            &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;distance_graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;


    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;graph_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

        &lt;span class="n"&gt;graph_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dijkstra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;#print distance, &amp;#39;\n&amp;#39;, path&lt;/span&gt;
        &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dijkstra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph_dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;s1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Floyd&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://zh.wikipedia.org/wiki/Floyd-Warshall%E7%AE%97%E6%B3%95"&gt;Floyd&lt;/a&gt;是一种计算图中所有点到其他点最短路径的算法。与Dijkstra算法相比，可以允许边值为负数。算法逻辑如下：&lt;/p&gt;
&lt;p&gt;设D_{i,j,k}为从i到j的只以(1..k)集合中的节点为中间节点的最短路径的长度。&lt;/p&gt;
&lt;p&gt;若最短路径经过点k，则D_{i,j,k}=D_{i,k,k-1}+D_{k,j,k-1}；
若最短路径不经过点k，则D_{i,j,k}=D_{i,j,k-1}。&lt;/p&gt;
&lt;p&gt;因此，D_{i,j,k}=\mbox{min}(D_{i,j,k-1},D_{i,k,k-1}+D_{k,j,k-1})。&lt;/p&gt;
&lt;p&gt;代码实现如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;floyd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;

                &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="n"&gt;new_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="k"&gt;continue&lt;/span&gt;

                    &lt;span class="n"&gt;new_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;new_len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_len&lt;/span&gt;
                        &lt;span class="n"&gt;new_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new_node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;floyd_dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;
                &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="n"&gt;new_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="k"&gt;continue&lt;/span&gt;

                    &lt;span class="n"&gt;new_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;new_len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_len&lt;/span&gt;
                        &lt;span class="n"&gt;new_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new_node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;


    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;ini&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;inf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;graph_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

        &lt;span class="n"&gt;graph_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;#new_graph, path= floyd_dict(graph_dict)    &lt;/span&gt;
        &lt;span class="n"&gt;new_graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;floyd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;new_graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n\n\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;这几个算法都是图论中的经典算法，会在网络应用中经常用到。然而我的实现只是最简单逻辑的实现，并没有考虑太多性能上的问题。如果需要追求性能，我想还是需要谷歌一下，或者到Github上随意挑选。获取代码可点击链接：&lt;a href="https://github.com/muzixing/graph_algorithm"&gt;graph algorithms&lt;/a&gt;。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 31 May 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-05-31:pages/2015/05/31/graph-algorithms-primkruskal-dijkstra-floyd.html</guid><category>graph algorithm</category></item><item><title>RYU中WSGI学习笔记与RESTAPI开发</title><link>http://www.muzixing.com/pages/2015/05/13/ryuzhong-wsgixue-xi-bi-ji-yu-restapikai-fa.html</link><description>&lt;p&gt;另一篇博文中已经介绍如何使用RYU的RESTAPI，本篇将继续介绍相关内容，主要分为WSGI学习总结和以ofctl_rest.py为例的RESTAPI的实现与内部机制。由于第一次学习WSGI，还有许多地方不是特别理解，所学知识均来自Google。文中若有错误之处，敬请指出，谢谢。&lt;/p&gt;
&lt;h3&gt;WSGI&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://zh.wikipedia.org/wiki/Web%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BD%91%E5%85%B3%E6%8E%A5%E5%8F%A3"&gt;Web服务器网关接口&lt;/a&gt;（Python Web Server Gateway Interface，缩写为WSGI）是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。为了理解WSGI，可以尝试一下的小例子。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cgi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;parse_qs&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cgi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;escape&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse_qs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;QUERY_STRING&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;World.&amp;#39;&lt;/span&gt;

    &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;200 OK&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Context-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;text/html&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&amp;#39;Hello &lt;/span&gt;&lt;span class="si"&gt;%(subject)s&lt;/span&gt;&lt;span class="s"&gt;&lt;/span&gt;
&lt;span class="s"&gt;    Hello &lt;/span&gt;&lt;span class="si"&gt;%(subject)s&lt;/span&gt;&lt;span class="s"&gt;!&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;wsgiref.simple_server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;make_server&lt;/span&gt;
    &lt;span class="n"&gt;IP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;make_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;LOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;wsgi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;listening on &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serve_forever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;运行之后，在浏览器地址栏输入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost:8080&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;可以观察到浏览器输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在写这个小例子的时候，我遇到一个让我非常疑惑的地方，函数hello_world的参数在哪里赋值？为什么网上的例子参数都是environ和start_response，难道这两个名字是特殊的？在运行时会默认已经被赋值？经过一系列谷歌以及查看源码之后，我终于还是没有搞明白。&lt;/p&gt;
&lt;p&gt;这不科学！！&lt;/p&gt;
&lt;p&gt;于是我尝试修改一下形参的名字，果然，还是可以运行的。这验证了这并不是特殊的名字，那么只有一种可能就是在创建对象的时候，已经给赋值了。那么输出一下这两个变量的内容是不错的尝试。尝试之后发现后者是一个对象，前者是一些列的内容。这验证了谷歌出来的各种说法：environ和start_response，environ是一个字典包含了CGI中的环境变量，start_response也是一个callable，接受两个必须的参数，status（HTTP状态）和response_headers（响应消息的头）。而这个赋值过程并不需要开发者去开发，在初始化时已经完成赋值。&lt;/p&gt;
&lt;p&gt;为了进一步验证想法，找到了ryu使用的eventlet相关的文件：/usr/lib/python2.7/dist-packages/eventlet/wsgi.py。在这个文件中定义了class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler)。在该类中定义了函数： handle_one_request和handle_one_response。在handle_one_request函数中初始化了如下两个重要的内容(line:227)：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_environ&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在handle_one_request函数中还调用了handle_one_response。在handle_one_response函数中，定义了函数start_response。查看代码时，终于发现了一句极为重要的语句(line:336)：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;start_restart函数在这句语句之前有定义(line:316)。至此，终于明白，为什么没有给形参赋值，实际上，这都是背后的故事。&lt;/p&gt;
&lt;p&gt;wsgi.py文件中定义了Server类，用于开启一个服务端socket，处理socket通信。文件中还定义了一个重要的接口函数：server。server函数主要完成了功能是启动一个wsgi server去处理来自客户端的请求。启动之后将永久循环，直到被关闭。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Start&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="n"&gt;handling&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;supplied&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;
&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;  &lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;loops&lt;/span&gt; &lt;span class="n"&gt;forever&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;  &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;closed&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="n"&gt;exits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;underlying&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;descriptor&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;so&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;dup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="n"&gt;usable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在RYU中，同样也有一个wsgi.py文件。该文件定义了一系列的WSGI的类，用于实现WSGI，为webapp提供支持。此外，hub.py文件中也有对应的内容，这些内容的分析将在下一小节ofctl_rest模块进行分析。&lt;/p&gt;
&lt;h3&gt;Ofctl_rest.py&lt;/h3&gt;
&lt;p&gt;在ofctl_rest.py文件中定义了class RestStatsApi(app_manager.RyuApp)和class StatsController(ControllerBase)。其中class RestStatsApi(app_manager.RyuApp)是一个RYUAPP模块，实现了 statistic相关的相关RESTAPI; class StatsController则是具体的API运行实体。class RestStatsApi(app_manager.RyuApp)部分源码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RestStatsApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;OFP_VERSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;ofproto_v1_2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;_CONTEXTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;&amp;#39;dpset&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dpset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DPSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;#39;wsgi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WSGIApplication&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RestStatsApi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;dpset&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;wsgi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;wsgi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waiters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;dpset&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpset&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;waiters&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waiters&lt;/span&gt;
        &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;

        &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;registory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;StatsController&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/stats&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/switches&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;OFP_VERSIONS指的是支持的OpenFlow的协议版本。
_CONTEXTS部分的内容是依赖的模块。dpset模块的DPSet类是一个RYUAPP类，会被当作一个service启动。DPSet类中主要完成了datapath链接的管理，比如dps字典内容的构建，交换机端口的信息收集，以及负责switches_features和port_status等消息的处理。具体细节，读者可自行查看/ryu/controller/dpset.py文件。wsgi模块负责完成了       请求路由的功能，相信内容直接查看wsgi.py介绍部分，此处不赘述。_CONTEXT中的'wsgi'值为WSGIApplication，所以在启动的时候需要将其作为RYU service启动。然而，这只是一个APPLICATION的类，启动WSGIServer另有玄机。很难发现到底在哪里启动了WSGIServer模块，我们只能在wsgi.py中找到一个没有被本文件使用的全局函数：start_service(app_mgr),一切线索似乎都断了。&lt;/p&gt;
&lt;p&gt;山重水复疑无路，柳暗花明又一村。&lt;/p&gt;
&lt;p&gt;这么好玩的源码解析，怎么能就这么结束了呢。从参数中我们发现app_mgr，难道！记忆深处，还记得大明湖畔的那个&lt;a href="http://www.muzixing.com/pages/2014/12/27/ryujie-du-ofphandlercontrollerryuapphe-appmanager.html"&gt;启动函数&lt;/a&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="sd"&gt;    more code &lt;/span&gt;
&lt;span class="sd"&gt;    &amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
    &lt;span class="c"&gt;# keep old behaivor, run ofp if no application is specified.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu.controller.ofp_handler&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;app_mgr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;contexts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_contexts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instantiate_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;webapp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;here&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="err"&gt;!!!&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;webapp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;thr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webapp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从代码中可以看到，启动RYU的时候，肯定会执行wsgi.start_service()函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;WSGIApplication&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;WSGIServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;返回了WSGIServer(WSGIServer instance)的对象，该对象作为一个模块在RYU中得到启动。class WSGIServer类的基类是hub.WSGIServer类，终于我们找到了在hub.WSGIServer中找到了eventlet.wsgi的实例。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;#wsgi.WSGIServer&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WSGIServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WSGIServer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WSGIServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wsapi_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wsapi_port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                                         &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serve_forever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;#hub.WSGIServer&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WSGIServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StreamServer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;serve_forever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LoggingWrapper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;至此函数调用链终于被发现。函数调用举例：
ofctl_rest.py模块被运行，RestStatsApi被加载之前_CONTEXT的内容被当作service加载。启动RYU时，调用wsgi.start_service函数，因为WSGIApplication放到了app_list内，所以判断WSGIApplication成功，将WSGIServer加载。至此WSGIServer和WSGIApplication以及其他模块加载完成。&lt;/p&gt;
&lt;p&gt;在WSGIApplication类中使用到了routes模块的&lt;a href="http://routes.readthedocs.org/en/latest/introduction.html"&gt;Mapper&lt;/a&gt;和URLGenerator,前者用于URL的路由，后者用于URL的产生。RYU运行之后，WSGIServer负责完成请求到APPlication的分发。WSGIApplication收到请求之后，通过mapper，将对应的请求分发给制定的处理函数。处理函数解析请求，并回复请求。mapper在初始化的时候，添加的connect规则如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;stats&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/flow/{dpid}&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;stats&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;StatsController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;get_flow_stats&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="n"&gt;conditions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;映射的分类属于stats分类，或者路径为stats。uri为/stats/flow/{dpid},dpid数值将在请求中被实例化为某一数值。交给的controller是StatsController，action是该类的get_flow_stats函数，请求的类型是GET或者POST，具体种类由请求明确。get_flow_stats函数具体如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_flow_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;_kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;flow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;flow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;literal_eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;SyntaxError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;invalid syntax &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isdigit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;invalid dpid &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_ofp_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;

    &lt;span class="n"&gt;_ofctl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;supported_ofctl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_ofp_version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_ofctl&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;flows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_ofctl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_flow_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waiters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Unsupported OF protocol&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;501&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;函数获取了req之后，进行解析。先获取了flow的信息，然后在调用_ofctl.get_flow_stats(dp, self.waiters, flow)函数获取到了flow的统计信息，然后使用json格式编码，最后返回一个Response.Response是webob的模块的一个类，用于返回一个WSGI的回应。详情可以查看&lt;a href="http://webob.readthedocs.org/en/latest/reference.html#id2"&gt;webob文档&lt;/a&gt;。最后我们就可以在网页上查看到我们获取的信息了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;webob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt; &lt;span class="n"&gt;everything&lt;/span&gt; &lt;span class="n"&gt;necessary&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;WSGI&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Instances&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fact&lt;/span&gt; &lt;span class="n"&gt;WSGI&lt;/span&gt; &lt;span class="n"&gt;applications&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;also&lt;/span&gt; &lt;span class="n"&gt;represent&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;calling&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;WSGI&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as&lt;/span&gt;     &lt;span class="n"&gt;noted&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Calling&lt;/span&gt; &lt;span class="n"&gt;WSGI&lt;/span&gt; &lt;span class="n"&gt;Applications&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;It&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;also&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;way&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;accumulating&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;WSGI&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;至此RYU中以ofctl_rest.py为例子的REST相关源码分析结束。&lt;/p&gt;
&lt;h3&gt;开发RESTAPI&lt;/h3&gt;
&lt;p&gt;本部分内容将以RYUBOOK上的一个简单案例介绍如何在RYU上开发RESTAPI。更多详细的内容大家可以点击&lt;a href="http://osrg.github.io/ryu-book/en/html/rest_api.html"&gt;原链接&lt;/a&gt;查看。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;simple_switch_13&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;webob&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.controller&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ofp_event&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.controller.handler&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CONFIG_DISPATCHER&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.controller.handler&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;set_ev_cls&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.app.wsgi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WSGIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ryu.lib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;dpid_lib&lt;/span&gt;

&lt;span class="n"&gt;simple_switch_instance_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;simple_switch_api_app&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/simpleswitch/mactable/{dpid}&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleSwitchRest13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;simple_switch_13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SimpleSwitch13&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;_CONTEXTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;wsgi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WSGIApplication&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SimpleSwitchRest13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="n"&gt;wsgi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;wsgi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SimpleSwitchController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;simple_switch_instance_name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nd"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPSwitchFeatures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CONFIG_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;switch_features_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SimpleSwitchRest13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switch_features_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_mac_to_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;mac_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switches&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;entry_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;port&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;entry_mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mac&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entry_port&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mac_table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;

                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mac_table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;

                    &lt;span class="c"&gt;# from known device to new device&lt;/span&gt;
                    &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry_port&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
                    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;entry_mac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="c"&gt;# from new device to known device&lt;/span&gt;
                    &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
                    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;entry_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="n"&gt;mac_table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;entry_mac&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry_port&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mac_table&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleSwitchController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ControllerBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SimpleSwitchController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;simpl_switch_spp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;simple_switch_instance_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nd"&gt;@route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;simpleswitch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;dpid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dpid_lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DPID_PATTERN&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_mac_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;simple_switch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;simpl_switch_spp&lt;/span&gt;
        &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dpid_lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str_to_dpid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;dpid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;simple_switch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;mac_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;simple_switch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac_table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;simpleswitch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;dpid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dpid_lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DPID_PATTERN&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;put_mac_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="n"&gt;simple_switch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;simpl_switch_spp&lt;/span&gt;
        &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dpid_lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str_to_dpid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;dpid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;new_entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;simple_switch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;mac_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;simple_switch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_mac_to_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac_table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;上述应用的代码中主要定义了两个类：SimpleSwitchRest13和SimpleSwitchController。其中SimpleSwitchRest13是SimpleSwitch13的派生类。此外，还需要启动一个WSGIApplication模块和WSGIServer模块提供服务。SimpleSwitchController类是作为WSGIApplication的controller类存在，用于实现对应的RESTAPI的内容。整个应用提供了两个RESTAPI的接口：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;获取MAC地址表 API&lt;/p&gt;
&lt;p&gt;获取Switching hub中MAC Table的内容，并以JSON格式返回MAC：PORT内容:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nd"&gt;@route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;simpleswitch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;dpid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dpid_lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DPID_PATTERN&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_mac_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;添加MAC地址表项 API&lt;/p&gt;
&lt;p&gt;将指定的MAC：PORT信息加入到MAC Table中，同时根据更新后的MAC Table内容，添加对应的Flow enrties.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nd"&gt;@route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;simpleswitch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;dpid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dpid_lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DPID_PATTERN&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;put_mac_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;对应的执行函数被route装饰器修饰，当route收取到对应的信息，如URL为：host:port/simpleswitch/mactable/{dpid}，动作类型为GET时，就会调用list_mac_table函数，返回mac_table的信息。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;运行验证&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;将以上的代码写入yourapp.py&lt;/li&gt;
&lt;li&gt;然后使用ryu-manager运行yourapp.py&lt;/li&gt;
&lt;li&gt;启动mininet连接控制器，并pingall&lt;/li&gt;
&lt;li&gt;使用POSTMAN（或其他）下发RESTAPI请求验证。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实验截图如下：&lt;/p&gt;
&lt;p&gt;RYU运行截图如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341jw1es2fi9cv7pj20k80auwih.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;POSTMAN获取信息截图如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1es2fi9n5kwj20yh0cimyj.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;另一个验证不再贴图，以此类推即可。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;在学习RYU的过程中会接触到许多之前没有接触的技术，沉下心来认真读一读代码，越发感觉工程师在设计RYU时的精妙之处。写程序并不是逻辑的堆砌，而是一个half art, half science的存在。不仅需要追求性能上的优越，满足科学的要求，还需要注意到在实现过程中充满艺术感的设计过程。模块的划分，逻辑的抽象，以及系统结构的设计与搭建，都是非常重要的，直接影响到运行的效率。希望RYU源码分析之旅，能让我学会更多SDN的知识。当文章写得越来越偏向程序，代码分析的时候，就显得不够SDN，但是事实上，我们除了Network,以及实现SDN的OpenFlow协议以外，SDN的S也是值得学习的地方之一。希望我的学习记录能够帮助到更多的人。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 13 May 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-05-13:pages/2015/05/13/ryuzhong-wsgixue-xi-bi-ji-yu-restapikai-fa.html</guid><category>wsgi</category><category>ryu</category></item><item><title>Getting started with RESTAPI of RYU</title><link>http://www.muzixing.com/pages/2015/05/10/getting-started-with-restapi-of-ryu.html</link><description>&lt;p&gt;在使用RYU的过程中，有时需要使用web拓扑，有时也需要通过API去下发流表等操作。这些操作在RYU中都会使用到RESTAPI。在学习RYU的过程中多次涉及到REST相关的内容，总是不知道如何实现和使用。最近在做实验需要这方面的知识，才有机会去学习REST并总结成博文。希望能给其他学习者提供帮助。本篇博文将简要介绍两部分内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is REST?&lt;/li&gt;
&lt;li&gt;How to use REST API in RYU?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is REST&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://zh.wikipedia.org/zh/REST"&gt;REST&lt;/a&gt;:表征性状态传输（英文：Representational State Transfer，简称REST）是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。更多REST的相关介绍可以查看&lt;a href="http://www.restapitutorial.com/lessons/whatisrest.html"&gt;视频介绍&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;REST架构风格中，资源是通过URI来描述的。对资源的操作采用了HTTP的GET，POST，PUT和DELETE方法相对应。资源的表现形式可以是json或xml。REST的架构是Client-Server架构，同时链接是无状态的。所以要求在传输的过程中需要包含状态信息。此外，可以使用cache机制增进性能。在上述视频中提到REST的6中限制为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Uniform Interface&lt;/li&gt;
&lt;li&gt;Stateless&lt;/li&gt;
&lt;li&gt;Cacheable&lt;/li&gt;
&lt;li&gt;Client-Server&lt;/li&gt;
&lt;li&gt;Layered System&lt;/li&gt;
&lt;li&gt;Code on Demand (optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;满足以上的API才是符合REST风格的API。&lt;/p&gt;
&lt;h2&gt;How to use REST API in RYU&lt;/h2&gt;
&lt;p&gt;在SDN控制器RYU的源代码中，我们可以发现RYU已经完成了一些RESTAPI的定义，实验人员可以直接使用对应的RESTAPI来进行编程。&lt;/p&gt;
&lt;p&gt;在ryu的app目录，可以发现许多rest相关的文件，比如ofctl_rest.py，rest.py,和rest_topology.py等。其中rest.py提供了基本的RESTAPI，ofctl_rest.py提供了与OpenFlow相关的RESTAPI，如查看、添加、修改流表等API。以ofctl_rest.py举例如何使用RYU中的RESTAPI。&lt;/p&gt;
&lt;h3&gt;启动RYU相关组件&lt;/h3&gt;
&lt;p&gt;在终端中输入如下命令，打开RYU运行ofctl_rest.py以及其他需要的模块，本案列中打开了simple_swich_13.py模块。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="n"&gt;ofctl_rest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;simple_switch_13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;运行RYU之后，可以查看到wsgi启动，监听端口为8080。&lt;/p&gt;
&lt;p&gt;&lt;img alt="ryu_rest" src="http://ww2.sinaimg.cn/mw690/7f593341jw1erzfzm7vthj20k50cwgq2.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;在ofctl_rest.py源码的前面部分，我们可以查看到写成注释形式的RESTAPI的使用方法，节选如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# REST API&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Retrieve the switch stats&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# get the list of all switches&lt;/span&gt;
&lt;span class="c"&gt;# GET /stats/switches&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# get the desc stats of the switch&lt;/span&gt;
&lt;span class="c"&gt;# GET /stats/desc/&amp;lt;dpid&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# get flows stats of the switch&lt;/span&gt;
&lt;span class="c"&gt;# GET /stats/flow/&amp;lt;dpid&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# get flows stats of the switch filtered by the fields&lt;/span&gt;
&lt;span class="c"&gt;# POST /stats/flow/&amp;lt;dpid&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# get aggregate flows stats of the switch&lt;/span&gt;
&lt;span class="c"&gt;# GET /stats/aggregateflow/&amp;lt;dpid&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# get aggregate flows stats of the switch filtered by the fields&lt;/span&gt;
&lt;span class="c"&gt;# POST /stats/aggregateflow/&amp;lt;dpid&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# get ports stats of the switch&lt;/span&gt;
&lt;span class="c"&gt;# GET /stats/port/&amp;lt;dpid&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;打开mininet连接控制器&lt;/h3&gt;
&lt;p&gt;打开mininet，运行任意拓扑，连接控制器RYU。并执行pingall,检测网络联通性。&lt;/p&gt;
&lt;p&gt;&lt;img alt="mininet" src="http://ww4.sinaimg.cn/mw690/7f593341jw1erzg3km6n7j20k10cqjv4.jpg" /&gt;&lt;/p&gt;
&lt;h3&gt;使用RESTAPI&lt;/h3&gt;
&lt;p&gt;推荐使用chrome插件&lt;a href="https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm"&gt;POSTMAN&lt;/a&gt;来操作RESTAPI，取代终端的curl命令。
在POSTMAN中输入正确的内容就可以下发请求信息。如请求dpid为1的交换机上的流表信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost:8080&lt;/span&gt;&lt;span class="sr"&gt;/stats/&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;选择动作类型为GET，点击send，可以马上获得交换机1上的流表信息。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341jw1erzgdc9pobj217k0h6aen.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;详细流表内容如下。可见目前交换机上有三条流表项，其中第一条是默认的miss_table_entry.后两条是h1和h2通信的双向流表项。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341jw1erzgeh5iz5j20mg0no78j.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;尝试对流表进行修改，可以使用POST动作类型，下发一个flow_mod消息，对现有流表进行操作。输入资源URI如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost:8080&lt;/span&gt;&lt;span class="sr"&gt;/stats/&lt;/span&gt;&lt;span class="n"&gt;flowentry&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;modify&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;message body 如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;dpid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;match&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;dl_dst&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;00:00:00:00:00:02&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;in_port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;actions&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;send之后，返回200状态码，提示成功。RYU返回消息内容为1.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1erzgehkqtaj20yc0g7jtm.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;此时重新获取交换机上的刘表，可以观察到流表修改已经成功。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1erzgehwfpmj20ka0n0wiq.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;在Mininet中重新pingall测试联通性，果然不通，修改流表结果正确。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1erzgei7hyjj20k60csjub.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;其他RESTAPI的示例不再赘述，读者可自行尝试。  由于篇幅限制，后续的源码分析部分将在另一个文章中详细介绍。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 10 May 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-05-10:pages/2015/05/10/getting-started-with-restapi-of-ryu.html</guid><category>RYU</category><category>REST</category></item><item><title>RYU3.16 GUI安装与Topology模块分析</title><link>http://www.muzixing.com/pages/2015/04/21/ryu316-guian-zhuang-yu-topologymo-kuai-fen-xi.html</link><description>&lt;p&gt;最近很多SDN研究人员问起如何安装RYU的GUI，网上也有一些教程。但是由于RYU版本问题，导致安装没有成功。本片博文将介绍RYU3.16版本下如何安装GUI，以及对RYU拓扑模块进行简单分析。&lt;/p&gt;
&lt;h3&gt;安装GUI&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://linton.tw/2014/02/11/note-how-to-set-up-ryu-controller-with-gui-component/"&gt;Linton的博客&lt;/a&gt;已经有详细介绍，我在这里将一些可能出现问题的地方再提醒一次。&lt;/p&gt;
&lt;h4&gt;第一步：依赖安装及修改代码&lt;/h4&gt;
&lt;p&gt;建议查看&lt;a href="http://linton.tw/2014/02/11/note-how-to-set-up-ryu-controller-with-gui-component/"&gt;Linton的博客&lt;/a&gt;，比较简单，不赘述。&lt;/p&gt;
&lt;h4&gt;第二步：运行相关组建&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;运行RYU相关APP&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;observe&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;simple_switch_13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;topology&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switches&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rest_topology&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofctl_rest&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;img alt="运行截图" src="http://ww2.sinaimg.cn/mw690/7f593341jw1erdi3oujndj20k60co75c.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;运行截图如下：
&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341jw1erdi90ztcij20jx0cqqa0.jpg" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;运行controller.py文件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;进入到gui目录，运行controller.py文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1erdi91ct7ej20mh0im12r.jpg" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;访问页面&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;打开浏览器，访问http://127.0.0.1:8000页面。查看到connected to 127.0.0.1:8080信息则为连接成功。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341jw1erdi91p3wbj20md07kab5.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Note that: 如果没有显示connected to 127.0.0.1:8000等信息，而显示Disconnected, 那么需要重新启动RYU的相关APP，再刷新网页，重新链接。运行controller.py的终端不需要动。&lt;/p&gt;
&lt;p&gt;若连接成功，启动mininet与控制器连接，则可发现网页逐步在显示网络拓扑，点击交换机图标可查看详细信息。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341jw1erdi923lypj20mb0hy0wf.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;众多网友表示3.19+版本无法成功使用GUI，可参考：&lt;a href="http://ryu.readthedocs.org/en/latest/gui.html"&gt;RYU3.20 GUI DOC&lt;/a&gt; 进行安装使用。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TOPOLOGY源码分析&lt;/h3&gt;
&lt;p&gt;有一个小伙伴已经在我之前发布了详细的代码介绍，我不再赘述，大家有兴趣的可以前往查看：&lt;a href="http://blog.csdn.net/sdnexplorer/article/details/44940907"&gt;Ryu拓扑发现原理分析&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在topology目录中，switches.py最重要。在switches.py文件中，核心的类是class Switches。&lt;/p&gt;
&lt;p&gt;在Switches类中，我们仅仅需要关注几个重要的函数即可将大体的拓扑发现逻辑理清。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;__init__()&lt;/p&gt;
&lt;p&gt;初始化函数初始化了一些重要的内容，如dps,ports,links等。并将lldp_loop和link_loop这两个函数加入线程（协程）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;packet_in_handler()&lt;/p&gt;
&lt;p&gt;此函数用于解析LLDP报文，从而提取出对应的信息，得到link信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;lldp_loop()&lt;/p&gt;
&lt;p&gt;调用了send_lldp_packet()函数，循环发送LLDP报文的函数。 &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;link_loop()&lt;/p&gt;
&lt;p&gt;实时检测link事件，及时发现拓扑变化，生产对应的event，并通过send_event_to_observers提供和观察者。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;使用Switches模块&lt;/h4&gt;
&lt;p&gt;在实验过程中，实验人员往往需要得到网络拓扑的信息，不仅仅是dpid,link,port这些零散的元素，而是一张图。这张图往往由邻接矩阵或关联矩阵。所以一下的内容将介绍如何将dpid,link等信息转化成邻接矩阵和关联矩阵，以便后续的算路算法使用。&lt;/p&gt;
&lt;p&gt;在你开发的模块中，将Switches作为context加载，并在__init__函数中将其赋值给某一变量。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;_CONTEXTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;switches&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;switches&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Switches&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yourapp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;switches&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_link_monitor&lt;/span&gt;&lt;span class="p"&gt;),])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;self.threads用于保存线程。将_link_monitor函数作为执行体，加入线程执行。函数简单定义如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_link_monitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp_tracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp_tracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dps&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp_tracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从_link_monitor函数中可以获取到dps,links等数据。这些数据需要整理存储，以便使用，get_graph函数就是用于将数据存储在图中的函数：定义函数get_graph，函数返回值是两张图，其中图graph_cap记录两个交换机之间的链路能力，图graph_port则记录的是从src到dst的源端口，目的端口信息保存在图的对称节点上。详细代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;graph_cap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="n"&gt;graph_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;dpid:&lt;/span&gt;
                    &lt;span class="n"&gt;graph_cap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
                    &lt;span class="n"&gt;graph_port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
                    &lt;span class="n"&gt;neighbor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;
                    &lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;curr_speed&lt;/span&gt;
                    &lt;span class="n"&gt;graph_cap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;
                    &lt;span class="n"&gt;graph_port&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;graph_cap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;graph_port&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;至此，网络拓扑图生成完毕。在运行最短路径或者其他的路径计算算法时，可使用get_graph返回的数据。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;一直以来做实验并不需要可视化拓扑界面，直到最近发现许多研究者频繁提问，才想起来尝试这个实验。但事实上，我觉得Switches模块的使用是一个更重要的内容。很多情况下，我们需要的是原始的数据，而不是展示出来的界面。本文内容比较简单，希望能帮助到一些SDN学习者。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 21 Apr 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-04-21:pages/2015/04/21/ryu316-guian-zhuang-yu-topologymo-kuai-fen-xi.html</guid><category>ryu</category></item><item><title>站在十字路口的一年</title><link>http://www.muzixing.com/pages/2015/03/08/zhan-zai-shi-zi-lu-kou-de-nian.html</link><description>&lt;p&gt;时光荏苒，岁月如梭，留不住的是青春，触不到的是未来，我只好关注现在。再回首，大学不再是每天一起上课的时光，没有夜里对未来的迷茫，只剩下难以名状的念想，说不出口，暗自埋藏。大学之后，我选择了读研究生，继续当一个穷到养不起自己的学生，假装看不见同龄人已在职场。内心的彷徨与不安，躁动与挣扎是这一年的主旋律。躁动是因为浮夸，不安是因为自己太差。如今又是一年的开始，过去的岁月需要总结，未来的生活需要计划，只有把过去内心的种种写下才能坦然，也只有对未来有所规划，才不会失去方向。&lt;/p&gt;
&lt;h2&gt;步履蹒跚&lt;/h2&gt;
&lt;p&gt;去年的前半年我还是一个“大四狗”，面对着毕业，也面对着对未来的选择。由于在大四上的时候已经确定自己要读研究生，所以也就没有尝试找工作，现在觉得是失策了，应该趁着nothing to lose的机会好好在就业大潮中体验一下的，万一拿到一个好Offer，不读也罢。&lt;/p&gt;
&lt;p&gt;去年3月份的时候，我选择去南京未来网研究院实习，最后也在那里完成了自己的毕业设计：一个在工信部实习时就完成的项目。因为运气好，最后还获得了优秀学士毕业论文的奖项，也是毕业时意外的惊喜之一。&lt;/p&gt;
&lt;p&gt;在南京的生活和工作没有区别，唯一不同的是薪水是可怜2000。每天和学长们一起坐班车去无线谷上班，下午再一起回来。但是在一个陌生的城市工作的感觉很孤独，除了办公室的同事，以及一起住的两个学长，再也没有其他什么朋友。所以夜生活，周末生活都过得及其无聊，那时候我们几个有好几次无聊去公司加班写代码。在那里我学会了如何工作，学会了如何和同事相处，也充分体验到了工作的生活，那时候我唯一想做的就是回北京。因为北京有我的女朋友，同学和朋友，每天都过得很舒服，可以规律健身，打篮球，约会。但是现实是我在南京待了半年，因为实习的原因也让原本应该很美好的大学多了一些遗憾。&lt;/p&gt;
&lt;p&gt;刚去南京的第一天，阿里暑期实习的电话面试来了。第一个组给的offer是Nginx脚本工作，可惜我觉得没有什么前途拒绝了。第二组是系统保障部的SDN小组，可惜最终还是挂在了终面，原因未知，可能我还不够好，或者不够合适吧。因为这事还忧伤过几天，不过很快就化成了动力，希望以后不会被别人嫌弃。&lt;/p&gt;
&lt;p&gt;另一个遗憾是篮球赛。 大一的时候我们班篮球赛是冠军，大四“滚蛋杯”的时候身为队长的我却离开北京，去南京实习了。离开之间就很纠结这个事情，没想到最后还真的因为这个事情落下了大学最大的遗憾。最后一场淘汰赛，和对面打了3个加时，最后输了。回来的时候听说大家都很难过，而我也理所应当地成为了失败原因之一。这个时候我真切地感到了对现实的无力感。失败已成事实，无法改变，也确实和我有着很大的关系，大家的想法也是很正常的，一切都自然地让我措手不及。四年以来，所有体育活动我都是组织者，不管结局如何，我们班都很团结，玩得很开心。可是在最关键的时候，却是我第一个不负责任地离开。这就是选择的代价吧，我无言以对，只想说声抱歉，以后我会做得更好，不会让其他人对我失望。&lt;/p&gt;
&lt;p&gt;2个月后，我读了研究生，每个月靠着不好意思说出口的补贴以及助学金奖学金来维持生活，连学费都交不起，我第一次感受到生存的压力。我试图去做一个非常豪放的人，不在乎那些经济上的小事，但是只有身处其中才感受真切，独立真的不简单。&lt;/p&gt;
&lt;p&gt;读研的第一个学期，需要交8000的学费，我没有向家里要，打算自己贷款，然后以后再还。奖学金8000,助学金6000，全部拿来当生活费的花，基本上每个月有1100+的收入，再加上实验室一点点补贴，每个月都过得很艰难。当人处于一种经济的窘迫之中时，就会变得非常焦虑，目光短浅。当时很羡慕那些年薪动不动就20W的同学，他们每一天的工作都可能获得不错的报酬，可以养活自己，可以追求美好的生活，而我还在另一个层面上挣扎。但是后来发现这并不是个例，很多研究生都苦于无法自立，只不过家里条件好的情况就好一些，起码不需要思考没钱了怎么办的事情。所以后来也就稍微坦然了一些。&lt;/p&gt;
&lt;p&gt;读研究生很多时候需要背负很大的压力，有时候会质疑自己，到底这么做对吗？答案还是交给时间吧。&lt;/p&gt;
&lt;h2&gt;柳暗花明&lt;/h2&gt;
&lt;p&gt;生活总不能都是困难和忧伤，何况是我这么乐观的人。&lt;/p&gt;
&lt;p&gt;经过一年的学习和积累，在SDN方向上，基础掌握得还不错，也在各大QQ群中认真地培养了存在感。由此获得的益处真的是之前的我完全没有想象过的存在。&lt;/p&gt;
&lt;p&gt;由于个性生动活泼，喜欢讨论技术，所以在技术群里经常和各种工程师老师学习专业知识，也喜欢帮助别人解决一些技术问题，就这样慢慢地在技术群里得到了一些认可。拥有认可之后，更喜欢学习研究，从而幸运地进入了一个良性循环。&lt;/p&gt;
&lt;p&gt;获得认可的另一个重要途径是通过维护运营我自己的&lt;a href="www.muzixing.com"&gt;博客:www.muzixing.com&lt;/a&gt;。我会把我的学习总结写成博文，发表在我的博客，大多都是一些技术细节，初级入门的水平，之所以缺少高水平，大局观的分析评论是因为自己涉猎太少，接触不到业界工业产品，所以无法写出有说服力的文章。不过这个博客确实给我带来了很多成就感。人们通过google, baidu等搜索引擎找到对应的内容，然后在我的博客得到帮助，我就很高兴；每一条评论我都很认真对待，因为我觉得我在用我小小的力量在给别人帮助，让世界上不同角落的人生活更美好，想想还有点小激动呢。&lt;/p&gt;
&lt;p&gt;在获得一定认可之后，就会得到一些之前不会得到的机会。&lt;/p&gt;
&lt;h3&gt;猎头邮件&lt;/h3&gt;
&lt;p&gt;偶尔会收到猎头的邮件，内容一般是某某公司在寻找某方面的人才，希望保持联系之类的。虽然这种邮件的意义不大，因为可能发邮件是广撒网策略，收到的人会很多。 但是我还是觉得这是对我的一种认可，起码我的信息可以在互联网上被获取到，而且在筛选的过程中被选中。随着收到的猎头邮件逐渐增多，就会慢慢发现那些写着我的名字，写着如何找到我的信息，找我的目的等等具体信息的邮件才是真正有意义的，也真正能让我兴奋。&lt;/p&gt;
&lt;h3&gt;创业寻求&lt;/h3&gt;
&lt;p&gt;创业机会大多来自与网络社区的前辈，他们大多是外企的员工，想抓住SDN的创业机会看看是否有什么发展。聊过不少，但是有吸引力的不太多，一方面创业还处于非常初期，找我过去也只是让我帮忙开发。谢谢那些认可我的前辈，祝福你们成功。&lt;/p&gt;
&lt;h3&gt;工作机会&lt;/h3&gt;
&lt;p&gt;这是最让我纠结的机会，因为这意味着如果我接受，我就要放弃读研，虽然我才读研半年。不过一般情况下大家更多的是提供机会，询问何时毕业等，少数会直接一些，会问如果现在入职是否可以之类的。真的非常感谢这些前辈的认可，让我觉得我有很多的机会去选择我的未来。不过一直没有人提薪金的事，让我有点纠结啊，可能经过HR之后才会到谈钱吧，我也不太清楚。也曾多次想过像那些著名的前辈那样，本科辍学创业，或者半途工作，但是反观自己的能力，就返现目前还不是很好的时机，抓紧时间让自己变强才是最重要的事情，目前时机还不成熟。&lt;/p&gt;
&lt;h3&gt;实习机会&lt;/h3&gt;
&lt;p&gt;相比工作机会而言，实习机会更切实际。但是实验室目前工作繁重，每天刷卡，实在无法脱身，所以实习也成为一种奢望。 感谢某Stack等公司提供的远程实习机会，希望等我有机会实习的时候，可以和你们建立一个和谐的合作关系。&lt;/p&gt;
&lt;p&gt;在北京的好处就是，不仅可以方便地参观公司，还可以方便地和HR聊天。这半年和几家公司有过相关的交流，也从交流中学会了很多工作上的知识，认识了一些业界的前辈。希望今年能拿到一个实习/兼职机会解决生活费。只有没有了经济上的忧虑，才会更专注于学习研究吧。&lt;/p&gt;
&lt;h3&gt;交流分享&lt;/h3&gt;
&lt;p&gt;很有幸的，我参加了一个SDN的meetup, 人数不多，但是相处之中也算愉快。在参加meetup的过程中，可以讲我当前的研究内容和大家分享。 其他形式的交流还有不少，不过更多的是个人的交流而不是组织形式的，比如在南京的时候，和东南大学的研究生学长的聊天，吃饭，在陌生地方，被网友请吃饭感觉好奇妙，嘿嘿。 在北邮，交流会更常见，因为研究SDN的北邮人真的太多了， 网研院的小伙伴就在开学的时候来实验室交流了一回。 在交流的过程，我不仅可以发表我的看法，给别人提供帮助，还可以从别人身上学习到很多知识，在思想的碰撞中，也会找到一些聊得来的小伙伴。&lt;/p&gt;
&lt;h3&gt;有偿帮助&lt;/h3&gt;
&lt;p&gt;从一年以前，就有网络上的网友找我帮忙，有偿的，无偿的都有。有偿的大多是毕业设计或者实验室项目，论文实验等内容，难度不大。找我的愿意，我觉得是因为我个人信息非常透明，在网络社区内也经常发言，所以大家比较相信我吧。 不过有偿帮助的案例对于我而言就比较尴尬，因为并不是每一个客户都非常可信，他们都不愿意我知道他们是谁，信息上，我们是极其不对等的。 其中就有一个项目因为对方的措辞有明显的逻辑漏洞，从而变得非常不愉快，最后也就流产了。不过总的来说，实验室工作繁重，能接单子的时间有限，一般只是在假期里才会接受。 如果在学期中接受项目，就只好挑晚上和周末来完成，所以生活压力巨大，不适合长期发展。&lt;/p&gt;
&lt;p&gt;去年寒假接了一个单子，由于时间紧迫，第一次选择和小伙伴一起完成。我负责谈判，接洽，交付，以及部分代码开发，他负责部分开发和测试。两个人在合作的过程中，发生了很多事情，也学会了很多教训。以前做项目都是自己做，自己有规划，有确定的时间节点，也会动态调整工作时间，以完成任务。但是两个人则完全不同，首先分工就是一门学问。不仅要把工作分割成能作为独立单元完成，还要注意相互之间的合作和相互帮助，接口的统一，数据结构的确定，时间节点的协调等等。由于第一次分工合作，在接口的制定上出了大问题：没有明确文档指定相关接口的功能，导致做着做着就做成自己想象那样了。时间协调上也出现了一点的问题：由于寒假远程工作，又因为接近春节，导致一起工作的时间非常短，沟通不及时不充分，最后工期拖了一个周。 工作过程中还发现版本控制太重要了！两个人相互传着不同版本的文件，没多久就乱了，所以以后还是需要使用git或者svn才行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;读研是一种投资，既然是投资就有付出，也渴望有回报。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;投资了快三年的宝贵青春，承受着经济上的压力，但也获得了三年可以做自己喜欢做的事情的美好时光。在没有上研究生之前，我计划研一的时候要看完CCNA，要学习英语，要出一篇论文，要锻炼身体，要多读书。&lt;/p&gt;
&lt;p&gt;目前我把CCNA看完了，但是还没有机会也没有欲望去考CCNA。&lt;/p&gt;
&lt;p&gt;没有参加雅思托福，GRE等培训班，只是参加了PSC(Public Speaking Club)，在这个俱乐部中认识了很多优秀的小伙伴，他们都很有想法，有自己的计划，对未来的生活有着美好的愿望。我很喜欢这样一个俱乐部。我也在俱乐部中学到了很多，每个周四的free talk基本都回去，周天的正式活动也会参加，有时候当speaker,有时候扮演evaluator,无论什么角色，我都享受其中，能在国内畅快地讲英语，练习英语，真的是太幸福了，这比那些阅读理解等要有趣得多。&lt;/p&gt;
&lt;p&gt;上学期试图写论文，才发现自己写论文和做实验不是一回事，需要学习的太多，我最终选择先打基础。庆幸的是，我有一个非常厉害而且非常年轻的导师，希望我能从她身上学到很多，完成一些优秀的学术论文。 &lt;/p&gt;
&lt;p&gt;锻炼身体方面执行地不太好，以前每个周回去3次健身房，而去年每个周也就去2次，导致没有能系统地锻炼，最终效果不是特别好，今年应该要更狠对待自己了。&lt;/p&gt;
&lt;p&gt;大学的时候我没有培养起读书的好习惯，身边的大牛都会保持阅读，所以一直都是很博学的存在。毕业之后，我开始制定读书计划，目前看起来执行得不太好。 过去的一年中，SDN方面的书籍基本都扫过一遍，还看过《大数据时代》、 《世界上最受欢迎的人》、 《看见》、 《乌合之众》， 《CCNA学习指南》等。目前正在阅读的《腾云：云计算时代的网络技术揭秘》。能看书的时间不多，所以要珍惜。&lt;/p&gt;
&lt;p&gt;读研的幸福在于有自己的时间去塑造自己，大学的时候，如果足够聪明，也会有这样的觉悟，但是大多数本科生都没有做到这一点。&lt;/p&gt;
&lt;p&gt;我希望读研的时间内我可以好好规划自己的发展，去健身，去阅读，去学习，去工作，去爱，去享受青春的美好。虽然此时的我经济上存在危机，但是我并不觉得这是什么大问题，不久之后应该就可以解决了，我应该有计划地实践着，享受着我美好的年华才对的。&lt;/p&gt;
&lt;h2&gt;计划与愿望&lt;/h2&gt;
&lt;p&gt;计划：今年的计划还没有制定，应该在写完这篇总结之后就会认真计划一下吧。不过计划的内容应该就是健身，学习相关内容。&lt;/p&gt;
&lt;p&gt;愿望：希望今年能写出自己生平中第一篇正式论文，能发到SCI等级吧。也希望这一年健健康康，学习生活两不误，爱情美满，越来越好。&lt;/p&gt;
&lt;p&gt;站在十字路口的一年，希望我没有走错。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 08 Mar 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-03-08:pages/2015/03/08/zhan-zai-shi-zi-lu-kou-de-nian.html</guid><category>胡思乱想</category></item><item><title>Traffic monitor in RYU</title><link>http://www.muzixing.com/pages/2015/03/04/traffic-monitor-in-ryu.html</link><description>&lt;p&gt;In many scenes, we need to get the real time link bandwidth so that controller can make some decisions in time. For example, load balance, network alert and so on. This article will demostrate how to get the bandwidth of a flow or a port(flow speed or port speed)。&lt;/p&gt;
&lt;p&gt;Actually, I wrote my app base on the simple_monitor at &lt;a href="http://osrg.github.io/ryu-book/en/html/traffic_monitor.html"&gt;Ryu_book Traffic Monitor&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can get my source code at:&lt;a href="https://github.com/muzixing/ryu/blob/master/ryu/app/simple_monitor.py"&gt;simple_monitor&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In my application, I define some new data structures, and init them in function __int__().  The usage of them show below.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;    &lt;span class="c1"&gt;# record the port speed &lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flow_speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;    &lt;span class="c1"&gt;# record the flow speed&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;          &lt;span class="c1"&gt;# the interval of getting statistic&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;      &lt;span class="c1"&gt;# the length of speed list of per port and flow.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;SimpleMonitor&lt;/h2&gt;
&lt;p&gt;The traffic monitor function has been implemented in the SimpleMonitor class which inherited app_manager.RyuApp, therefore, we need to manipulate packet in other application. This design makes SimpleMonitor as a independent application.&lt;/p&gt;
&lt;h3&gt;Stats request&lt;/h3&gt;
&lt;p&gt;First of all, We need to send the OFPPortStatsRequest message and OFPFlowStatsRequest message to request port and flow statistic infomation periodically. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_request_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;send stats request: %016x&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ofproto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;

    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPFlowStatsRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPortStatsRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_ANY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Stats reply&lt;/h3&gt;
&lt;p&gt;We define the _port_stats_reply_handler to manipulate the port stats reply message, so as the flow stats reply message.In function _port_stats_reply_handler, we use (ev.msg.datapath.id, stat.port_no) as the key of self.port_stats, while the value is (stat.tx_bytes, stat.rx_bytes, stat.rx_errors, stat.duration_sec, stat.duration_nsec).&lt;/p&gt;
&lt;p&gt;We use the self._get_speed to calculate port speed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPPortStatsReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_port_stats_reply_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;stat&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;attrgetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;port_no&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;stat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_LOCAL:&lt;/span&gt;
            &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;stat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nb"&gt;stat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tx_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;stat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rx_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;stat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rx_errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nb"&gt;stat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;duration_sec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;stat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;duration_nsec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_save_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_stats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Get port speed.&lt;/span&gt;
            &lt;span class="n"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;period&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sleep&lt;/span&gt;
            &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_stats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;period&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_get_period&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

            &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_get_speed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_stats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_stats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_save_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_speed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;\n Speed:\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_speed&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Fixed-Cycle Processing&lt;/h3&gt;
&lt;p&gt;Finally, we need to create a thread to send requests messages and manipulate reply messages, and the function of thread is _monitor.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;monitor_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_monitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_monitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;True:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapaths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_request_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So far, we have finished the simple monitor application in RYU.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note that&lt;/strong&gt;: I just calculate the speed of port and flow, if you need to get the free bandwidth, you still need to subtract the speed form link bandwidth.&lt;/p&gt;
&lt;p&gt;I hope my work can help you.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 04 Mar 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-03-04:pages/2015/03/04/traffic-monitor-in-ryu.html</guid><category>ryu bandwidth</category></item><item><title>Fattree topo and iperfmulti function in mininet</title><link>http://www.muzixing.com/pages/2015/02/22/fattree-topo-and-iperfmulti-function-in-mininet.html</link><description>&lt;p&gt;This article will show you 1)how to build a &lt;a href="http://ccr.sigcomm.org/online/files/p63-alfares.pdf"&gt;fattree&lt;/a&gt; topo and 2)how to extend the iperfmulti function in mininet.&lt;/p&gt;
&lt;p&gt;本篇博文将讲述1）如何搭建fatree网络拓扑和2）如何在mininet中拓展iperfmulti功能。&lt;/p&gt;
&lt;p&gt;众所周知，数据中心是目前网络研究的一个热门领域。随着云计算的兴起与发展，会对数据中心网络提出更多的需求，也为学术研究提供了更多的课题。TE（Traffic Engineering）是网络研究中最基础的研究之一，在TE中Load balance是比较主要的研究内容之一。 然而由于数据中心网络的流量走势与传统网络不同，导致数据中心网络与传统网络的架构有所不同。在传统网络中上下行流量在总流量中占据很大比重，而相比之下，数据中心的流量分类中，横向流量的比重要远远大于传统网络架构的比重。为了更好解决数据中心网络流量问题，数据中心架构的设计就变得非常重要，在众多网络架构中，Fat-tree架构是比较出名和成功的。&lt;/p&gt;
&lt;p&gt;SDN兴起于校园网，盛开于数据中心，这是一种比较准确的描述。目前SDN的研究领域内，数据中心占据了一席之地。所以很多的研究者都试图通过在控制器开发应用以及使用mininet模拟网络来进行网络实验。博主最近也做了一个关于Fat-tree的实验，在实验过程中，碰到了许多问题，深深觉得这一方面的知识在互联网中还比较缺乏。特此记录下来，分享出去，首先是作为自己的笔记，备忘，其次也给其他同样研究这方面的同学一些帮助。我掉过的坑，我不愿意别人继续掉。&lt;/p&gt;
&lt;p&gt;科学的发展是需要许多人奠定基础，才能逐步发展。而只有分享经验，传递知识，才能让后人能站在前人的基础之上继续前进。重复劳动力在一些基础的无关紧要的环节，是整个社会资源的浪费。特此感谢乐于分享的各种网络中的老师，特别是为人十分和蔼，温和，良师益友@地球-某某老师。&lt;/p&gt;
&lt;h2&gt;Fattree topo&lt;/h2&gt;
&lt;p&gt;这个python文件最初的原型是参考了roan's Blog的博文&lt;a href="http://roan.logdown.com/posts/191753-sdn-lab-2-use-mininet-create-fat-tree-topology"&gt;SDN Lab 2$ Use Mininet create Fat Tree Topology&lt;/a&gt;中给出的代码。并在次基础上做了一些修改。在此感谢台湾的小伙伴的分享。&lt;/p&gt;
&lt;p&gt;在此基础上我进行了修改，可点击&lt;a href="https://github.com/muzixing/fattree/blob/master/fattree_8_4.py"&gt;fattree源码&lt;/a&gt;获取代码。&lt;/p&gt;
&lt;h3&gt;Fattree特征&lt;/h3&gt;
&lt;p&gt;Fattree中，K是一个很重要的参数。如K=8，则core节点个数为(K/2)^2,pod个数为K,每一个POD有K个交换机，每一个交换机有K个inter link（内部链路）。aggregation层有K^2/2=64/2=32个交换机，同理 edge也是K^2/2=32个交换机。host可以是K/2个host，也可以任意指定。在我写的脚本中，K和host density都是可以设置的参数。&lt;/p&gt;
&lt;p&gt;部分源码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Fattree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Topo&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Class Fattree&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;CoreSwitchList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;AggSwitchList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;EdgeSwitchList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;HostList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;density&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  &lt;span class="c1"&gt;# K 为fattree pod个数。 density是tor下的主机个数。&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Class Fattree init&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; 
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iCoreLayerSwitch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iAggLayerSwitch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iEdgeLayerSwitch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;density&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;density&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iEdgeLayerSwitch&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;density&lt;/span&gt;

        &lt;span class="c1"&gt;#Init Topo&lt;/span&gt;
        &lt;span class="n"&gt;Topo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;createTopo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createCoreLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iCoreLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createAggLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iAggLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createEdgeLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iEdgeLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iHost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Create Switch and Host&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;PREFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;00&amp;quot;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;PREFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;switch_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;s&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;PREFIX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;createCoreLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Create Core Layer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CoreSwitchList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;createAggLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Create Agg Layer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AggSwitchList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;createEdgeLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Create Edge Layer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EdgeSwitchList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;createHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Create Host&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;PREFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;h00&amp;quot;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;PREFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;h0&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;PREFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;h&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HostList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PREFIX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Add Link   createLink函数用于创建links,修改了原始版本写死的代码。&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;createLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bw_c2a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bw_a2e&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bw_h2a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Add link Core to Agg.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iAggLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CoreSwitchList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AggSwitchList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="n"&gt;bw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bw_c2a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Add link Agg to Edge.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iAggLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AggSwitchList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EdgeSwitchList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="n"&gt;bw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bw_a2e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Add link Edge to Host.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iEdgeLayerSwitch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;density&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EdgeSwitchList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HostList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;density&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="n"&gt;bw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bw_h2a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;set_ovs_protocol_13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_set_ovs_protocol_13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CoreSwitchList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_set_ovs_protocol_13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AggSwitchList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_set_ovs_protocol_13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EdgeSwitchList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_set_ovs_protocol_13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sw_list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sw_list:&lt;/span&gt;
                &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;sudo ovs-vsctl set bridge %s protocols=OpenFlow13&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;sw&lt;/span&gt;
                &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;createTopo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LV1 Create Fattree&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;topo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Fattree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createTopo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bw_c2a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bw_a2e&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bw_h2a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LV1 Start Mininet&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;CONTROLLER_IP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;CONTROLLER_PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6633&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Mininet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TCLink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;autoSetMacs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;autoStaticArp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;&amp;#39;controller&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;RemoteController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CONTROLLER_IP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CONTROLLER_PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Iperfmulti function&lt;/h2&gt;
&lt;p&gt;在mininet中拓展功能的文章可参考&lt;a href="http://richardzhao.me/"&gt;@赵伟辰&lt;/a&gt;的博客。&lt;/p&gt;
&lt;p&gt;在mininet中增加新功能其实不难。主要分为3步：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修改net.py增加函数实体；&lt;/li&gt;
&lt;li&gt;修改cli.py，增加对应do_function函数，用于命令解析；&lt;/li&gt;
&lt;li&gt;修改mn函数，用于声明命令。 &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;net.py和cli.py均在mininet/mininet目录，mn文件在在mininet/bin目录中。&lt;/p&gt;
&lt;h3&gt;修改net.py&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;iperf_single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hosts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;udpBw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;10M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5001&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Run iperf between two hosts using UDP.&lt;/span&gt;
&lt;span class="s"&gt;           hosts: list of hosts; if None, uses opposite hosts&lt;/span&gt;
&lt;span class="s"&gt;           returns: results two-element array of server and client speeds&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;hosts:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;hosts&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hosts&lt;/span&gt;
        &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;.out&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;*** Iperf: testing bandwidth between &amp;#39;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;%s and %s\n&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;iperfArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;iperf -u &amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;bwArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;-b &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;udpBw&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; &amp;#39;&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;***start server***&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;iperfArgs&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;-s&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; &amp;gt; /home/muzi/log/&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;amp;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;***start client***&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;iperfArgs&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;-t &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; -c &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bwArgs&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;#39; &amp;gt; /home/muzi/log/&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;client&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;amp;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;iperfMulti&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;base_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5001&lt;/span&gt;
    &lt;span class="n"&gt;server_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;client_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;host_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;host_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;cli_outs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;ser_outs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;

    &lt;span class="n"&gt;_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_len&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;host_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="n"&gt;server_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iperf_single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;udpBw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;base_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;.05&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;base_port&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ping -c10&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; &amp;gt; /home/muzi/log/delay.out&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上代码完成iperfmulti函数实现：随机选取SC对，并进行iperf 打流。&lt;/p&gt;
&lt;h3&gt;修改cli.py&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;do_iperfmulti&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Multi iperf UDP test between nodes&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;udpBw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iperfMulti&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;udpBw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;udpBw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;period&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iperfMulti&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;udpBw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;invalid number of args: iperfmulti udpBw \n&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
               &lt;span class="s"&gt;&amp;#39;udpBw examples: 1M\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;修改mn&lt;/h3&gt;
&lt;p&gt;在mininet/bin目录下修改mn文件，将iperfmulti加入到对应的列表中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# optional tests to run&lt;/span&gt;
&lt;span class="n"&gt;TESTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;cli&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;build&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pingall&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pingpair&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;iperf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;all&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;iperfudp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;&amp;#39;none&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;iperfmulti&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;ALTSPELLING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pingall&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pingAll&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;&amp;#39;pingpair&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pingPair&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;&amp;#39;iperfudp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;iperfUdp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;&amp;#39;iperfUDP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;iperfUdp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;&amp;#39;iperfmulti&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;iperfmulti&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;重新安装mininet&lt;/h3&gt;
&lt;p&gt;进入mininet/util目录，输入以下命令重新编译安装mininet core:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;重启mininet，输入iperf，可使用table补全iperfmulti，从而可使用iperfmulti进行测试。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;在做实验的过程中，遇到了很多问题，也学会了很多。学会了谷歌找资料，学会了给论文作者发邮件，也学会了如何协同工作。特别是协同工作这一点，以前写代码，做实验都是自己来，没有明确定义的接口，也更没有分工合作，版本管理也是自己随意定。在这个实验过程中，不仅学到了很多知识，更重要的是学会了和小伙伴北邮-张歌的相处，团队协作是一个非常重要的能力，我将在未来的日子里继续努力学习和提高这方面的能力。希望他的&lt;a href="http://www.zhangge208.com/"&gt;博客&lt;/a&gt;能慢慢写起来，以后一起做更多好玩有用的实验。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 22 Feb 2015 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2015-02-22:pages/2015/02/22/fattree-topo-and-iperfmulti-function-in-mininet.html</guid><category>SDN</category><category>mininet</category><category>fattree</category><category>data center</category></item><item><title>RYU核心源码解读：OFPHandler,Controller,RyuApp和AppManager</title><link>http://www.muzixing.com/pages/2014/12/27/ryuhe-xin-yuan-ma-jie-du-ofphandlercontrollerryuapphe-appmanager.html</link><description>&lt;p&gt;每接触一个控制器我都会习惯性的把控制器的源码读一读，走一走处理流程，RYU也不例外。本篇博文将从main函数入手，讲述RYU的ryuapp基类细节、app_manager类如何load apps，注册并运行application，Event的产生以及分发，还有最重要的应用ofp_handler。文章将以RYU真实运行流程作为主线，详细讲述RYU如何运作。如果文中出现理解错的地方，敬请指出，万分感谢！转载请声明原出处。&lt;/p&gt;
&lt;h2&gt;main()&lt;/h2&gt;
&lt;p&gt;RYU的main函数在ryu/cmd/manager.py文件中。main函数中CONF部分已经在在前一篇&lt;a href="http://www.muzixing.com/pages/2014/12/19/ryuxue-xi-oslo.html"&gt;《RYU学习：oslo》&lt;/a&gt;已经有所介绍，所以这次关注的重点的是后续部分，如app_manager如何工作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu-manager %s&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;default_config_files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/local/etc/ryu/ryu.conf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfigFilesNotFoundError:&lt;/span&gt;
        &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu-manager %s&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init_log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file:&lt;/span&gt;
        &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
        &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pid_file:&lt;/span&gt;
            &lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

    &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
    &lt;span class="c1"&gt;# keep old behaivor, run ofp if no application is specified.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;app_lists:&lt;/span&gt;
        &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu.controller.ofp_handler&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;app_mgr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;contexts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_contexts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instantiate_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;webapp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;webapp:&lt;/span&gt;
        &lt;span class="n"&gt;thr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webapp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;finally:&lt;/span&gt;
        &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;首先从CONF文件中读取出app list。如果ryu-manager 命令任何参数，则默认应用为ofp_handler应用。紧接着实例化一个AppManager对象，调用load_apps函数将应用加载。调用create_contexts函数创建对应的contexts, 然后调用instantiate_apps函数将app_list和context中的app均实例化。启动wsgi架构，提供web应用。最后将所有的应用作为任务，作为coroutine的task去执行，joinall使得程序必须等待所有的task都执行完成才可以退出程序。最后调用close函数，关闭程序，释放资源。以下的部分将以主函数中出现的调用顺序为依据，展开讲解。&lt;/p&gt;
&lt;h2&gt;OFPHandler&lt;/h2&gt;
&lt;p&gt;上文说到，如果没有捕获Application输入，那么默认启动的应用是OFPHandler应用。该应用主要用于处理OpenFlow消息。在start函数初始化运行了一个OpenFlowController实例。OpenFlowController类将在后续介绍。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFPHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OpenFlowController&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;OFPHandler应用完成了基本的消息处理，如hello_handler：用于处理hello报文，协议版本的协商。其处理并不复杂，但是值得注意的一点是装饰器：Decorator的使用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;@set_ev_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPHello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HANDSHAKE_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;hello_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
       &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;hello ev %s&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;
       &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Decorator&lt;/h3&gt;
&lt;p&gt;如果你已经了解Decorator，可以直接跳过本部分。&lt;/p&gt;
&lt;p&gt;装饰器是什么？&lt;a href="https://wiki.python.org/moin/PythonDecorators"&gt;Python Decorator&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;coolshell上的介绍&lt;a href="http://coolshell.cn/articles/11265.html"&gt;Python修饰器的函数式编程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Python Decorator可以看作是一种声明，一种修饰。以下举例参考自Coolshell。举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;@decorator&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;实际上等同于foo = decorator(foo), 而且它还被执行了。举个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="s-Atom"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s-Atom"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s-Atom"&gt;:&lt;/span&gt;    
    &lt;span class="s-Atom"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;you   %s  me!&amp;quot;&lt;/span&gt; &lt;span class="c1"&gt;% fn.__name__[::-1].upper()&lt;/span&gt;

&lt;span class="s-Atom"&gt;@keyword&lt;/span&gt;
&lt;span class="s-Atom"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evol&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s-Atom"&gt;:&lt;/span&gt;
    &lt;span class="s-Atom"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;运行之后，就会输出:you love me。&lt;/p&gt;
&lt;p&gt;多个decorator:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;@decorator_a&lt;/span&gt;
&lt;span class="nv"&gt;@decorator_b&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这相当于：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decorator_a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decorator_b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;而带参数的decorator:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;@decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;相当于&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;decorator(arg1,arg2)将生成一个decorator。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;class式的 Decorator&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;myDecorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;inside myDecorator.__init__()&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;inside myDecorator.__call__()&amp;quot;&lt;/span&gt;


&lt;span class="nv"&gt;@myDecorator&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;aFunction&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;inside aFunction()&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Finished decorating aFunction()&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;aFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;@decorator使用时，__init__被调用，当function被调用是，执行__call__函数，而不执行function,所以在__call__函数中需要写出self.fn = fn&lt;/p&gt;
&lt;p&gt;更多内容可以直接访问&lt;a href="https://wiki.python.org/moin/PythonDecoratorLibrary"&gt;Python Decorator Library&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;OpenFlowController&lt;/h2&gt;
&lt;p&gt;前一部分提到OFPHandle的start函数会将OpenFlowController启动。本小节介绍OpenFlowController类。该类的定义在ryu/cmd/controller.py文件中。OpenFlowController.__call__()函数启动了server_loop()函数，该函数实例化了hub.py中的StreamServer类，并将handler函数初始化为datapath_connection_factory函数，并调用serve_forever()，不断进行socket的监听。StreamServer定义如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;StreamServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listen_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backlog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;ssl_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;backlog&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;
            &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;spawn&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;:&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;listen_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listen_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                              &lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listen_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ssl_args:&lt;/span&gt;
                &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;wrap_and_handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="n"&gt;ssl_args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;server_side&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrap_socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;ssl_args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wrap_and_handle&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;

        &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;serve_forever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;True:&lt;/span&gt;
                &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Datapath&lt;/h3&gt;
&lt;p&gt;Datapath类在RYU中极为重要，每当一个datapath实体与控制器建立连接时，就会实例化一个Datapath的对象。
该类中不仅定义了许多的成员变量用于描述一个datapath，还管理控制器与该datapath通信的数据收发。其中_recv_loop函数完成数据的接收与解析，事件的产生与分发。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;@_deactivate&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_recv_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytearray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;required_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt;

        &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active:&lt;/span&gt;
            &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
                &lt;span class="n"&gt;break&lt;/span&gt;
            &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;required_len:&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;required_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;required_len:&lt;/span&gt;
                    &lt;span class="n"&gt;break&lt;/span&gt;

                &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;#  解析报文&lt;/span&gt;
                &lt;span class="c1"&gt;# LOG.debug(&amp;#39;queue msg %s cls %s&amp;#39;, msg, msg.__class__)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;msg:&lt;/span&gt;
                    &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_msg_to_ev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 产生事件&lt;/span&gt;
                    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_event_to_observers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 事件分发&lt;/span&gt;

                    &lt;span class="n"&gt;dispatchers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispatchers&lt;/span&gt;
                    &lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;
                                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_handlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;
                                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dispatchers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;handlers:&lt;/span&gt;
                        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;required_len:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;required_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_HEADER_SIZE&lt;/span&gt;

                &lt;span class="c1"&gt;# We need to schedule other greenlets. Otherwise, ryu&lt;/span&gt;
                &lt;span class="c1"&gt;# can&amp;#39;t accept new switches or handle the existing&lt;/span&gt;
                &lt;span class="c1"&gt;# switches. The limit is arbitrary. We need the better&lt;/span&gt;
                &lt;span class="c1"&gt;# approach in the future.&lt;/span&gt;
                &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                    &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;@_deactivate修饰符作用在于在Datapath断开连接之后，将其状态is_active置为False。self.ofp_brick.send_event_to_observers(ev, self.state) 语句完成了事件的分发。self.brick的初始化语句可以在self.__init__函数中找到：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_brick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookup_service_brick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ofp_event&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;由上可知，self.ofp_brick实际上是由service_brick（中文可以称为：服务链表？）中的“ofp_event”服务赋值的。在每一个app中，使用@set_ev_cls(ev_cls,dispatchers)时，就会将实例化ofp_event模块，执行文件中最后一句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu.controller.ofp_handler&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;register_service函数实体如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;register_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Register the ryu application specified by &amp;#39;service&amp;#39; as&lt;/span&gt;
&lt;span class="s"&gt;    a provider of events defined in the calling module.&lt;/span&gt;

&lt;span class="s"&gt;    If an application being loaded consumes events (in the sense of&lt;/span&gt;
&lt;span class="s"&gt;    set_ev_cls) provided by the &amp;#39;service&amp;#39; application, the latter&lt;/span&gt;
&lt;span class="s"&gt;    application will be automatically loaded.&lt;/span&gt;

&lt;span class="s"&gt;    This mechanism is used to e.g. automatically start ofp_handler if&lt;/span&gt;
&lt;span class="s"&gt;    there are applications consuming OFP events.&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;frm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmodule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frm&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_SERVICE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其中inspect.stack()[1]返回了调用此函数的caller, inspect.getmodule(frm[0])返回了该caller的模块，当前例子下，module=ofp_event。&lt;/p&gt;
&lt;p&gt;我们可以通过ryu-manager --verbose来查看到输出信息，从而印证这一点。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;muzi&lt;/span&gt;&lt;span class="nv"&gt;@muzi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;OptiPlex&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;390&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/ryu/&lt;/span&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;verbose&lt;/span&gt;
&lt;span class="n"&gt;loading&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_handler&lt;/span&gt;
&lt;span class="n"&gt;instantiating&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_handler&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;OFPHandler&lt;/span&gt;
&lt;span class="n"&gt;BRICK&lt;/span&gt; &lt;span class="n"&gt;ofp_event&lt;/span&gt;
  &lt;span class="n"&gt;CONSUMES&lt;/span&gt; &lt;span class="n"&gt;EventOFPErrorMsg&lt;/span&gt;
  &lt;span class="n"&gt;CONSUMES&lt;/span&gt; &lt;span class="n"&gt;EventOFPEchoRequest&lt;/span&gt;
  &lt;span class="n"&gt;CONSUMES&lt;/span&gt; &lt;span class="n"&gt;EventOFPPortDescStatsReply&lt;/span&gt;
  &lt;span class="n"&gt;CONSUMES&lt;/span&gt; &lt;span class="n"&gt;EventOFPHello&lt;/span&gt;
  &lt;span class="n"&gt;CONSUMES&lt;/span&gt; &lt;span class="n"&gt;EventOFPSwitchFeatures&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;所以当运行ofp_handler应用时，就会注册ofp_event service，为后续的应用提供服务。分发事件之后，还要处理自身订阅的事件，所以首先找到符合当前state的caller,然后调用handler。_caller类可以在handler.py文件中找到，包含dispatchers和ev_source两个成员变量。前者用于描述caller需要的state,后者是event产生者的模块名称。&lt;/p&gt;
&lt;p&gt;对应的发送循环由_send_loop完成。self.send_q是一个深度为16的发送queue。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="nv"&gt;@_deactivate&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_send_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;try:&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active:&lt;/span&gt;
                &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;finally:&lt;/span&gt;
            &lt;span class="sx"&gt;q = &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_q&lt;/span&gt;
            &lt;span class="c1"&gt;# first, clear self.send_q to prevent new references.&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;
            &lt;span class="c1"&gt;# there might be threads currently blocking in send_q.put().&lt;/span&gt;
            &lt;span class="c1"&gt;# unblock them by draining the queue.&lt;/span&gt;
            &lt;span class="n"&gt;try:&lt;/span&gt;
                &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="sx"&gt;q.get(block=False):&lt;/span&gt;
&lt;span class="sx"&gt;                    pass&lt;/span&gt;
&lt;span class="sx"&gt;            except hub.&lt;/span&gt;&lt;span class="n"&gt;QueueEmpty:&lt;/span&gt;
                &lt;span class="n"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;serve函数完成了发送循环的启动和接收循环的启动。启动一个coroutine去执行self._send_loop()， 然后马上主动发送hello报文到datapath(可以理解为交换网桥：Bridge)，最后执行self._recv_loop()。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;send_thr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_send_loop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# send hello message immediately&lt;/span&gt;
        &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;try:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_recv_loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;finally:&lt;/span&gt;
            &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;kill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send_thr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinall&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;send_thr&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;而serve函数又在datapath_connection_factory函数中被调用。当然向外提供完整功能的API就是这个。所以在OpenFlowController类中可以看到在初始化server实例的时候，handler赋值为datapath_connection_factory。其中使用到的contextlib module具体内容不作介绍，读者可&lt;a href="https://docs.python.org/2/library/contextlib.html"&gt;自行学习&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;datapath_connection_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;connected socket:%s address:%s&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;contextlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;closing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Datapath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;datapath:&lt;/span&gt;
        &lt;span class="n"&gt;try:&lt;/span&gt;
            &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;except:&lt;/span&gt;
            &lt;span class="c1"&gt;# Something went wrong.&lt;/span&gt;
            &lt;span class="c1"&gt;# Especially malicious switch can send malformed packet,&lt;/span&gt;
            &lt;span class="c1"&gt;# the parser raise exception.&lt;/span&gt;
            &lt;span class="c1"&gt;# Can we do anything more graceful?&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt;
                &lt;span class="n"&gt;dpid_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;%s&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;dpid_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dpid_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error in the datapath %s from %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dpid_str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;raise&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;到此为止，OFPHandler应用的功能实现介绍完毕。RYU启动时，需要启动OFPHandler，才能完成数据的收发和解析。更多的上层应用逻辑都是在此基础之上进行的。若要开发APP则需要继承RyuApp类，并完成observer监听事件，以及注册handler去完成事件处理。&lt;/p&gt;
&lt;h2&gt;RyuApp&lt;/h2&gt;
&lt;p&gt;RyuApp类是RYU封装好的APP基类，用户只需要继承该类，就可以方便地开发应用。而注册对应的observer和handler都使用@derocator的形式，使得开发非常的简单高效，这也是Python的优点之一吧。RyuApp类的定义在ryu/base/app_manager.py文件中。该文件实现了两个类RyuApp和AppManager。前者用于定义APP基类，为应用开发提供基本的模板，后者用于Application的管理，加载应用，运行应用，消息路由等功能。&lt;/p&gt;
&lt;p&gt;app_manager.py文件中import了&lt;a href="https://docs.python.org/2/library/inspect.html"&gt;instpect&lt;/a&gt;和&lt;a href="https://docs.python.org/2/library/itertools.html"&gt;itertools&lt;/a&gt; module，从而使得开发更方便简洁。inspect模块提供了一些有用的方法，用于类型检测，获取内容，检测是否可迭代等功能。itertools则是一个关于迭代器的模块，可以提供丰富的迭代器类型，在数据处理上尤其有用。&lt;/p&gt;
&lt;h3&gt;_CONTEXT&lt;/h3&gt;
&lt;p&gt;这是一个极其难理解的概念。博主的理解是，_CONTEXT内存储着name:class的key value pairs。为什么需要存储这个内容？实际上这个_CONTEXT携带的信息是所有本APP需要依赖的APP。需要在启动本应用之前去启动，以满足依赖的，比如一个simple_switch.py的应用，如果没有OFPHandler应用作为数据收发和解析的基础的话，是无法运行的。具体文档如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;_CONTEXTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    A dictionary to specify contexts which this Ryu application wants to use.&lt;/span&gt;
&lt;span class="s"&gt;    Its key is a name of context and its value is an ordinary class&lt;/span&gt;
&lt;span class="s"&gt;    which implements the context.  The class is instantiated by app_manager&lt;/span&gt;
&lt;span class="s"&gt;    and the instance is shared among RyuApp subclasses which has _CONTEXTS&lt;/span&gt;
&lt;span class="s"&gt;    member with the same key.  A RyuApp subclass can obtain a reference to&lt;/span&gt;
&lt;span class="s"&gt;    the instance via its __init__&amp;#39;s kwargs as the following.&lt;/span&gt;

&lt;span class="s"&gt;    Example::&lt;/span&gt;

&lt;span class="s"&gt;        _CONTEXTS = {&lt;/span&gt;
&lt;span class="s"&gt;            &amp;#39;network&amp;#39;: network.Network&lt;/span&gt;
&lt;span class="s"&gt;        }&lt;/span&gt;

&lt;span class="s"&gt;        def __init__(self, *args, *kwargs):&lt;/span&gt;
&lt;span class="s"&gt;            self.network = kwargs[&amp;#39;network&amp;#39;]&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;_EVENTS&lt;/h3&gt;
&lt;p&gt;用于记录本应用会产生的event。但是当且仅当定义该event的语句在其他模块时才会被使用到。但是目前我还没有遇见过在哪里使用，如果你知道其正确的用法，恳请告知，相互学习。&lt;/p&gt;
&lt;h3&gt;self.__init__&lt;/h3&gt;
&lt;p&gt;__init__函数中初始化了许多重要的成员变量，如self.event_handler用于记录向外提供的事件处理句柄，而self.observer则刚好相反，用于通知app_manager本应用监听何种类型的事件。self.event是事件队列。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;_kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;        &lt;span class="c1"&gt;# ev_cls -&amp;gt; handlers:list&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;observers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;     &lt;span class="c1"&gt;# ev_cls -&amp;gt; observer-name -&amp;gt; states:set&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;LOGGER_NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOGGER_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;

        &lt;span class="c1"&gt;# prevent accidental creation of instances of this class outside RyuApp&lt;/span&gt;
        &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;_EventThreadStop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;pass&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_event_stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_EventThreadStop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;self.start&lt;/h3&gt;
&lt;p&gt;start函数将启动coroutine去处理_event_loop，并将其加入threads字典中，为什么名字叫threads呢？我也不知道。也许我理解错了？&lt;/p&gt;
&lt;h3&gt;self._event_loop&lt;/h3&gt;
&lt;p&gt;_event_loop函数用于启动事件处理循环，通过调用self.get_handlers(ev, state)函数来找到事件对应的handler，然后处理事件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_handlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Returns a list of handlers for the specific event.&lt;/span&gt;

&lt;span class="s"&gt;        :param ev: The event to handle.&lt;/span&gt;
&lt;span class="s"&gt;        :param state: The current state. (&amp;quot;&lt;/span&gt;&lt;span class="n"&gt;dispatcher&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;                      If None is given, returns all handlers for the event.&lt;/span&gt;
&lt;span class="s"&gt;                      Otherwise, returns only handlers that are interested&lt;/span&gt;
&lt;span class="s"&gt;                      in the specified state.&lt;/span&gt;
&lt;span class="s"&gt;                      The default is None.&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;ev_cls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;
        &lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev_cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_event_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_event_stop:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_handlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;handlers:&lt;/span&gt;
                &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;event dispatch&lt;/h3&gt;
&lt;p&gt;应用中可以通过@set_ev_cls修饰符去监听某些事件。当产生event时，通过event去get observer，得到对应的观察者，然后再使用self.send_event函数去发送事件。在这里，实际上就是直接往self.event队列中put event。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_send_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;send_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Send the specified event to the RyuApp instance specified by name.&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SERVICE_BRICKS:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EventRequestBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;EVENT %s-&amp;gt;%s %s&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt;
                  &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;SERVICE_BRICKS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_send_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;EVENT LOST %s-&amp;gt;%s %s&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt;
                  &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;send_event_to_observers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Send the specified event to all observers of this RyuApp.&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_observers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其他函数如注册handler函数：register_handler，注册监听函数：register_observer等都是非常简单直白的代码，不再赘述。&lt;/p&gt;
&lt;h2&gt;AppManager&lt;/h2&gt;
&lt;p&gt;AppManager类是RYU应用的调度中心。用于管理应用的添加删除，消息路由等等功能。&lt;/p&gt;
&lt;p&gt;首先从启动函数开始介绍，我们可以看到run_apps函数中的代码和前文提到的main函数语句基本一样。首先获取一个对象，然后加载对应的apps，然后获取contexts，context中其实包含的是本应用所需要的依赖应用。所以在调用instantiate_apps函数时，将app_lists内的application和contexts中的services都实例化，然后启动协程去运行这些服务。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;@staticmethod&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;run_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Run a set of Ryu applications&lt;/span&gt;

&lt;span class="s"&gt;    A convenient method to load and instantiate apps.&lt;/span&gt;
&lt;span class="s"&gt;    This blocks until all relevant apps stop.&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;app_mgr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;contexts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_contexts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instantiate_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;webapp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;webapp:&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webapp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;finally:&lt;/span&gt;
        &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;load_apps&lt;/h3&gt;
&lt;p&gt;首先从创建一个apps_lists的生成器（个人理解应该是生成器而非迭代器）。在while循环中，每次pop一个应用进行处理，然后将其本身和其context中的内容添加到services中，再去调用get_dependent_services函数获取其依赖应用，最后将所有的依赖services添加到app_lists中，循环至最终app_lists内元素全都pop出去，完成application的加载。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;load_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
                     &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_iterable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;app_cls_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;context_modules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__module__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contexts_cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;app_cls_name&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;context_modules:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;

            &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;loading app %s&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_cls_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;cls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_cls_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;

            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applications_cls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;app_cls_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;

            &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context_cls&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_iteritems&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contexts_cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context_cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;context_cls&lt;/span&gt;
                &lt;span class="n"&gt;context_modules&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context_cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__module__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;issubclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context_cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_dependent_services&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context_cls&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

            &lt;span class="c1"&gt;# we can&amp;#39;t load an app that will be initiataed for&lt;/span&gt;
            &lt;span class="c1"&gt;# contexts.&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;get_dependent_services&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;context_modules:&lt;/span&gt;
                    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;services:&lt;/span&gt;
                &lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;create_contexts&lt;/h3&gt;
&lt;p&gt;context实例化函数将context中name:service class键值对的内容实例化成对应的对象，以便加入到services 列表中，从而得到加载。首先从列表中取出对应数据，然后判断是否时RyuApp的子类，是则实例化，否则直接赋值service class。load_app函数在读取的时候还会再次判断是否是RyuApp子类。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;create_contexts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contexts_cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;issubclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="c1"&gt;# hack for dpset&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;creating context %s&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;instantiate_apps&lt;/h3&gt;
&lt;p&gt;此函数调用了self._instantiate函数，在_instantiate函数中又调用了register_app()函数，此函数将app添加到SERVICE_BRICKS字典之中，然后继续调用了ryu.controller.handler 中的 register_instance函数，最终完成了应用的注册。此后继续调用self._update_bricks函数完成了服务链表的更新，最后启动了所有的应用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;instantiate_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applications_cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_update_bricks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;report_bricks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt;
            &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;


&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# for now, only single instance of a given module&lt;/span&gt;
    &lt;span class="c1"&gt;# Do we need to support multiple instances?&lt;/span&gt;
    &lt;span class="c1"&gt;# Yes, maybe for slicing.&lt;/span&gt;
    &lt;span class="c1"&gt;#LOG.info(&amp;#39;instantiating app %s of %s&amp;#39;, app_name, cls.__name__)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;OFP_VERSIONS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSIONS&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt;
        &lt;span class="n"&gt;ofproto_protocol&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_app_supported_versions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSIONS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;app_name&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;app_name&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applications&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;register_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applications&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applications&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;_update_bricks&lt;/h3&gt;
&lt;p&gt;此函数完成了更新service_bricks的功能。首先从获取到service实例，然后再获取到service中的方法，若方法有callers属性，即使用了@set_ev_cls的装饰符，拥有了calls属性。（caller类中的ev_source描述了产生该event的source module， dispatcher描述了event需要在什么状态下才可以被分发。如：HANDSHAKE_DISPATCHER，CONFIG_DISPATCHER等。）最后调用register_observer函数注册了observer。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_update_bricks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SERVICE_BRICKS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmembers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ismethod&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;callers&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ev_cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iteritems&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ev_source:&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;

                &lt;span class="n"&gt;brick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_lookup_service_brick_by_mod_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ev_source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;brick:&lt;/span&gt;
                    &lt;span class="n"&gt;brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_observer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev_cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                            &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispatchers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="c1"&gt;# allow RyuApp and Event class are in different module&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;brick&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SERVICE_BRICKS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;itervalues&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ev_cls&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_EVENTS:&lt;/span&gt;
                        &lt;span class="n"&gt;brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_observer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev_cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispatchers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;ryu.controller.handler.register_instance&lt;/h3&gt;
&lt;p&gt;以上的部分介绍了App的注册，observer的注册，handler的查找和使用，但是，始终没有提到handler在何处注册。实际上，handler的注册在register_instance部分完成了。为什么他的位置在handler文件，而不在app_manager文件呢？个人认为可能是为了给其他非Ryu APP的模块使用吧。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;register_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmembers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ismethod&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# LOG.debug(&amp;#39;instance %s k %s m %s&amp;#39;, i, _k, m)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_has_caller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ev_cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iteritems&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev_cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;总体而言，RYU使用了协程，在很大程度上提高了单核性能。同时也使用了许多高效的语句和库，使得代码量非常精简易读。优势方面，RYU开发门槛低，性能好，稳定度强，而且代码迎合OpenStack编写，适合用于数据中心等云场景。劣势方面，RYU还没有实现分布式版本，在大规模网络中只能使用多个单节点分担负载。实现细节上还存在细微的问题，如虽然提供了存储依赖关系的数据结构和获取依赖关系的函数，但是并没有指定一个默认的依赖关系。不过这一点其实並不算大问题，甚至不是问题，因为开发者可以手动去指定。&lt;/p&gt;
&lt;p&gt;认真读完RYU底层的实现代码，觉得学习一门语言需要学习的内容太多，而只有真正去使用时，才会真正的学会和理解。严谨的逻辑，优雅的编码风格，清晰的模块划分能让程序的可读性更高，代码可复用性更强。如果从一个产品的角度讲，RYU算是一个不错的产品，小而美。没有ONOS,OpenDaylight那样庞大，但是作为一个纯SDN控制器而言，用户体验算是非常好的一个了。&lt;/p&gt;
&lt;p&gt;写完这篇之后，估计这个学期就不会再写了，非科研狗非产品狗非bababala狗的渣硕要开始预习期末考试了。希望未来的我会更好。&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;itertools&lt;/strong&gt;：python关于&lt;a href="https://docs.python.org/2/library/itertools.html"&gt;迭代器&lt;/a&gt;的库。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;contextlib&lt;/strong&gt;：&lt;a href="https://docs.python.org/2/library/contextlib.html"&gt;contextlib&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;yield&lt;/strong&gt;：类似与return,但是返回的是一个生成器。&lt;a href="http://pyzh.readthedocs.org/en/latest/the-python-yield-keyword-explained.html"&gt;中文翻译教程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;decorator&lt;/strong&gt;：&lt;a href="https://wiki.python.org/moin/PythonDecorators"&gt;Python Decorator&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;coolshell上的介绍&lt;a href="http://coolshell.cn/articles/11265.html"&gt;Python修饰器的函数式编程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;迭代器&lt;/strong&gt;：就是一个可以迭代的数据结构，可以使用for x in 语法去读取，每次返回一个列表。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;生成器&lt;/strong&gt;：具有可迭代性，但是每一次只能读取一个元素。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sat, 27 Dec 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-12-27:pages/2014/12/27/ryuhe-xin-yuan-ma-jie-du-ofphandlercontrollerryuapphe-appmanager.html</guid><category>ryu</category><category>sdn</category></item><item><title>RYU学习:Oslo</title><link>http://www.muzixing.com/pages/2014/12/19/ryuxue-xi-oslo.html</link><description>&lt;p&gt;前段时间开始认真看了一下RYU的源码，发现OSLO是一个非常方便的命令行解析库，可以用于CLI和CONF的解析。oslo是&lt;a href="https://wiki.openstack.org/wiki/Oslo"&gt;OpenStack&lt;/a&gt;发起的项目，全称为OpenStack Common Libraries,是OpenStack Projects共享的基础库。&lt;/p&gt;
&lt;h3&gt;Oslo&lt;/h3&gt;
&lt;p&gt;在RYU的目录下可以找到cfg.py文件，这个文件中import了oslo的相关模块，以便调用时减少引用数目。从文件中可以发现oslo.config.cfg文件是关键文件，其在系统中的文件位置在：/usr/local/lib/python2.7/dist-packages/oslo/config/cfg.py。想查看源码的读者可以自行查看。在该cfg.py文件中 定义了ConfigOpts类，包含了_opts, _groups等成员变量。该类完成了命令行和配置参数的解析。&lt;/p&gt;
&lt;p&gt;如果要快速学习某一个知识，最好的办法就是把它用起来。所以首先我会介绍一个入门的教程。如果你没有看懂，可以去看原始的&lt;a href="http://www.giantflyingsaucer.com/blog/?p=4822"&gt;教程&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;首先安装&lt;a href="https://virtualenv.pypa.io/en/latest/virtualenv.html"&gt;python-virtualenv&lt;/a&gt;，此python库可以用于创建一个虚拟的，与外界隔离的运行环境，听起来和docker好像有点像。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;virtualenv&lt;/span&gt;
&lt;span class="n"&gt;virtualenv&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;activate&lt;/span&gt;
&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;oslo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;
&lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后修改app.conf。添加了两个group:simple和morestuff。simple组中有一个BoolOpt:enable。morestuff组有StrOpt, ListOpt, DictOpt, IntOpt,和FloatOpt。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;[simple]&lt;/span&gt;

&lt;span class="na"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;[morestuff]&lt;/span&gt;

&lt;span class="c"&gt;# StrOpt&lt;/span&gt;
&lt;span class="na"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Hello World&lt;/span&gt;

&lt;span class="c"&gt;# ListOpt&lt;/span&gt;
&lt;span class="na"&gt;usernames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;[&amp;#39;Licheng&amp;#39;, &amp;#39;Muzixing&amp;#39;, &amp;#39;Distance&amp;#39;]&lt;/span&gt;

&lt;span class="c"&gt;# DictOpt&lt;/span&gt;
&lt;span class="na"&gt;jobtitles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;{&amp;#39;Licheng&amp;#39;: &amp;#39;Manager&amp;#39;, &amp;#39;Muzixing&amp;#39;: &amp;#39;CEO&amp;#39;, &amp;#39;Distance&amp;#39;: &amp;#39;Security Guard&amp;#39;}&lt;/span&gt;

&lt;span class="c"&gt;# IntOpt&lt;/span&gt;
&lt;span class="na"&gt;payday&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;20&lt;/span&gt;

&lt;span class="c"&gt;# FloatOpt&lt;/span&gt;
&lt;span class="na"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;3.14&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;修改app.py文件。首先定义两个group，再对两个group的option进行定义。最后使用register_group和register_opts函数来完成group和option的注册。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;print_function&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;oslo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;


&lt;span class="n"&gt;opt_simple_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;simple&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;A Simple Example&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;opt_morestuff_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;morestuff&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;A More Complex Example&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;simple_opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BoolOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;enable&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;True enables, False disables&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;morestuff_opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StrOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;No data&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;A message&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;usernames&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;A list of usernames&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DictOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;jobtitles&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;A dictionary of usernames and job titles&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;payday&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Default payday monthly date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FloatOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;pi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;The value of Pi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;CONF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;

&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_simple_group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_opts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;simple_opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt_simple_group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_morestuff_group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_opts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;morestuff_opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt_morestuff_group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_config_files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;app.conf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;(simple) enable: {}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;simple&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;(morestuff) message :{}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;morestuff&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;(morestuff) usernames: {}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;morestuff&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usernames&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;(morestuff) jobtitles: {}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;morestuff&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jobtitles&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;(morestuff) payday: {}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;morestuff&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payday&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;(morestuff) pi: {}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;morestuff&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成之后，运行app.py文件。可以查看到相关输出。&lt;/p&gt;
&lt;p&gt;回到RYU中，之前一篇&lt;a href="http://www.muzixing.com/pages/2014/12/10/ryuxue-xi-eventlet.html"&gt;博客&lt;/a&gt;介绍了RYU的main函数。在ryu/ryu/cmd/manager.py文件中我们可以看到如下的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_cli_opts&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;app-lists&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;application module name to run&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MultiStrOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;positional&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;application module name to run&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StrOpt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;pid-file&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;pid file name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上的注册了三个Option，其中的app-lists和app参数是运行ryu-manager时的参数，即APP的名称。在以下的main函数中，我们可以看到首先获取了输入的参数，若参数为空，则默认开启ofp_handler应用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu-manager %s&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;default_config_files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/local/etc/ryu/ryu.conf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfigFilesNotFoundError:&lt;/span&gt;
        &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu-manager %s&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init_log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file:&lt;/span&gt;
        &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
        &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pid_file:&lt;/span&gt;
            &lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

    &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
    &lt;span class="c1"&gt;# keep old behaivor, run ofp if no application is specified.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;app_lists:&lt;/span&gt;
        &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu.controller.ofp_handler&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;oslo模块使用能够使得整个工程的不同模块可以使用同一个配置文件，从而减少了命令冲突的可能，此外，oslo提供的模板，可以让命令解析更方便。在oslo.config之外，还有oslo.db,oslo.messaging等。&lt;/p&gt;
&lt;h3&gt;Argparse&lt;/h3&gt;
&lt;p&gt;oslo模块中使用了&lt;a href="https://docs.python.org/2/howto/argparse.html"&gt;argparse&lt;/a&gt;。argparse是python标准库中的模块。以下以一个简单例子介绍此模块，更详细的中文教程，可以查看&lt;a href="http://lingxiankong.github.io/blog/2014/01/14/command-line-parser/"&gt;《Python中的命令行解析工具介绍》&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;在argparse模块中定义了ArgumentParser类。我们可以调用该类的add_argument函数添加参数。其函数说明如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="n"&gt;nargs&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="n"&gt;metavar&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从以上说明可以看出，add_argument函数可以添加action, type, choices，help等重要的属性。具体参数解释，引用自&lt;a href="http://lingxiankong.github.io/blog/2014/01/14/command-line-parser/"&gt;《Python中的命令行解析工具介绍》&lt;/a&gt;如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;name or flags - 参数的名字.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;action - 遇到参数时的动作，默认值是store。store_const，表示赋值为const；append，将遇到的值存储成列表，也就是如果参数重复则会保存多个值; append_const，将参数规范中定义的一个值保存到一个列表；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;count，存储遇到的次数；此外，也可以继承argparse.Action自定义参数解析；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nargs - 参数的个数，可以是具体的数字，或者是?号，当不指定值时对于Positional argument使用default，对于Optional argument使用const；或者是*号，表示0或多个参数；或者是+号表示1或多个参数.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;const - action和nargs所需要的常量值.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;default - 不指定参数时的默认值.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;type - 参数的类型.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;choices - 参数允许的值.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;required - 可选参数是否可以省略(仅针对optionals). &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;help - 参数的帮助信息，当指定为argparse.SUPPRESS时表示不显示该参数的帮助信息.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;metavar - 在usage说明中的参数名称，对于必选参数默认就是参数名称，对于可选参数默认是全大写的参数名称. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dest - 解析后的参数名称，默认情况下，对于可选参数选取最长的名称，中划线转换为下划线.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用案例举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#filename:prog.py&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# parser.add_argument(&amp;quot;echo&amp;quot;, help=&amp;quot;Print the arguments.&amp;quot;)&lt;/span&gt;

&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;--verbosity&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;increase output verbosity.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;the base&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;the exponent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#parser.add_argument(&amp;quot;square&amp;quot;, help=&amp;quot;Return square of given number.&amp;quot;, type=int)&lt;/span&gt;

&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verbosity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;{} to the power {} equals {}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verbosity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;{}^{} =={}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;可以通过一下命令运行prog.py去查看到相关信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;
&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;  &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;
&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;  &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vv&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;每一个项目都会有自己的CLI或者配置文件，而使用oslo可以简化命令解析的问题。比自己使用sys.argv手动写解析要更高效且优雅。所以推荐大家在工程中使用oslo。后续会继续推出RYU学习系列文章，希望能在记录自己学习过程的同时，给其他人提供更多的帮助。自己对OpenStack没有了解，文中有不正确之处敬请指出，谢谢了！希望在不久的将来能学习OpenStack的Neutron。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 19 Dec 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-12-19:pages/2014/12/19/ryuxue-xi-oslo.html</guid><category>ryu</category><category>oslo</category></item><item><title>RYU学习:eventlet</title><link>http://www.muzixing.com/pages/2014/12/10/ryuxue-xi-eventlet.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;从OpenDaylight转到RYU以来一直都没有机会好好学习RYU的源码,只学会了编写简单的Application。但是如果要熟悉一个控制器，就要熟悉它的运行原理，熟悉它数据结构，熟悉它的设计模式等等。最近终于有时间好好看RYU的代码，但在看代码的过程中却发现RYU并不简单，其编码风格也非常优雅，非常值得学习。本篇博文主要讲述RYU中使用到的eventlet。&lt;/p&gt;
&lt;h2&gt;从RYU开始&lt;/h2&gt;
&lt;p&gt;运行ryu的时候，命令是：ryu-manager app.py。第一个要找到就是ryu-manager到底会触发什么程序。在/cmd中没有找到之后，在/bin中找到了两个可执行文件：ryu和ryu-manager。打开ryu-manager，显示如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;找到/ryu/cmd/manager.py，发现这个文件中的main()函数是整个ryu的入口函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu-manager %s&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;default_config_files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/local/etc/ryu/ryu.conf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfigFilesNotFoundError:&lt;/span&gt;
        &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu-manager %s&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init_log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file:&lt;/span&gt;
        &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
        &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pid_file:&lt;/span&gt;
            &lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

    &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
    &lt;span class="c1"&gt;# keep old behaivor, run ofp if no application is specified.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;app_lists:&lt;/span&gt;
        &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu.controller.ofp_handler&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;app_mgr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;contexts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_contexts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instantiate_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;webapp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;webapp:&lt;/span&gt;
        &lt;span class="n"&gt;thr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webapp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;finally:&lt;/span&gt;
        &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个main()函数的内容主要是完成了RYU的初始化配置和启动。Configure使用了oslo，这个在后续的博文中应该会提到。初始化的构成主要包括将app_list里面的内容加入App_Manager的列表中，然后开启协程去协调这些APP完成工作。hub是from ryu.lib import hub的。继续查看ryu/lib/hub.py。最终找到许多关于eventlet的内容。在hub.py中定义了Event,StreamServer和WSGIServer等类，还有一些重要的重要函数如spawn()等。为了更好地学习RYU，学习coroutine和eventlet就非常有必要了。&lt;/p&gt;
&lt;h2&gt;&lt;a href="http://en.wikipedia.org/wiki/Coroutine#Implementations_for_Python"&gt;Coroutine&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;协程[coroutine]是一个程序组件。相比subroutine, coroutine更一般。coroutine相对与thread而言，又不一样。thread是资源抢占式的存在，而coroutine是通过yield来转移执行权，协程之间是平等的，没有等级关系。multi-thread一旦开始运行，就无法确定某一时刻到底是哪一个thread在占用cpu，临界资源也要加互斥锁。而coroutine则是需要程序员自己决定程序如何运行，同时也需要自己负责程序的风险。协程和线程一样，只共享堆，不共享栈。&lt;/p&gt;
&lt;h2&gt;&lt;a href="http://eventlet.net/"&gt;Eventlet&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;eventlet是一个可以提供高性能并发处理能力的python库。我们可以在/usr/lib/python2.7/dist-packages/eventlet中找到对应的文件。&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Examples&lt;/h3&gt;
&lt;p&gt;为了更好的理解eventlet的内容，我花了半天认真地抄了一遍&lt;a href="http://eventlet.net/doc/examples.html"&gt;官网&lt;/a&gt;的例子。具体实例举例如下。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GreenPile&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Spawn multiple workers and collect their results.&lt;/span&gt;

&lt;span class="s"&gt;Demonstrates how to use the eventlet.green.socket module.&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;green&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;


&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;geturl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;con&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;gethostbyname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;%s connected&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;GET /\r\n\r\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;www.muzixing.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;www.baidu.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;www.python.org&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;pile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GreenPile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls:&lt;/span&gt;
    &lt;span class="n"&gt;pile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geturl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pile&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;%s: %s&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上的代码对指定url发送了GET请求。重点在与eventlet.GreenPile()的使用。GreenPile类源码如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;GreenPile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size_or_pool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_or_pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GreenPool&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size_or_pool&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GreenPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_or_pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waiters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LightQueue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Runs *func* in its own green thread, with the result available by&lt;/span&gt;
&lt;span class="s"&gt;        iterating over the GreenPile object.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;True&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;try:&lt;/span&gt;
            &lt;span class="ow"&gt;gt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waiters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;except:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;raise&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Wait for the next result, suspending the current greenthread until it&lt;/span&gt;
&lt;span class="s"&gt;        is available.  Raises StopIteration when there are no more results.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;used:&lt;/span&gt;
            &lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;try:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waiters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;finally:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从__init__函数可以看出，GreenPile内部有一个GreenPool对象和一个Queue对象：waiters。GreenPool的作用相当与线程池的作用，这点后续会继续介绍。上述例子用到的spawn函数完成了协程（被称之为green thread）的启动。可以看出spawn函数的参数是（函数，参数），在上述例子中为： pile.spawn(geturl, x)。从spawn函数中，也可以看出spawn()方法的返回值被保存在waiters队列中。next()方法的实现使其具有迭代性质。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GreenPool&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;下面的例子使用到了GreenPool类，完成了一个非常暴力的迭代爬虫，理论上，如果你让他去爬取某一个网站，然后不去管它，它会从这个网站出发，找到所有的链接，然后跳到各自的链接，然后继续迭代，直到最后把整个互联网的网站都爬一遍。而且，它不尊重你网站的robot.txt，这意味这它什么都会爬取。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;with_statement&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;green&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib2&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;


&lt;span class="c1"&gt;# http://daringfireball.net/2009/11/liberal_regex_for_matching_urls&lt;/span&gt;
&lt;span class="n"&gt;url_regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;\b(([\w-]+://?|www[.])[^\s()&amp;lt;&amp;gt;]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;&amp;#39;&amp;#39;Fetch A url, stick any found urls into the seen set,&lt;/span&gt;
&lt;span class="s"&gt;    and dispatch any new  ones to te pool.&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;fetching&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url_match&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;url_regex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finditer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;new_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url_match&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# You can only send requests to muzixing.com so as not to destroy internet&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new_url&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen:&lt;/span&gt;  &lt;span class="c1"&gt;# and ’muzixing.com&amp;#39; in new_url:&lt;/span&gt;
            &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;# While this seems stack-recursive, it is actually not.&lt;/span&gt;
            &lt;span class="c1"&gt;# Spawned greenthreads start their own stacks&lt;/span&gt;
            &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;crawl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;&amp;#39;&amp;#39;Recrusively crawl starting from *start_url*.Return a set of&lt;/span&gt;
&lt;span class="s"&gt;    urls that were found.&lt;/span&gt;
&lt;span class="s"&gt;    &amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GreenPool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waitall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;

&lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;crawl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.muzixing.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;I saw there urls:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;
&lt;span class="c1"&gt;# print &amp;#39;\n&amp;#39;.join(seen)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;首先爬虫从&lt;a href="http://www.muzixing.com"&gt;http://www.muzixing.com&lt;/a&gt;网站开始搜索url。然后继续迭代寻找url，不断扩大查找范围。实验结果如下所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1en5uqubim7j20m10n1dn9.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;图1：迭代爬虫显示信息&lt;/p&gt;
&lt;p&gt;从上图可以看到爬虫抓取了&lt;a href="http://www.muzixing.com"&gt;www.muzixing.com&lt;/a&gt;的网页中存在的url如&lt;a href="http://ikimi.net"&gt;http://ikimi.net&lt;/a&gt;，然后我们可以看到爬虫又跳到了&lt;a href="http://ikimi.net"&gt;http://ikimi.net&lt;/a&gt;上爬取页面的其他url,如&lt;a href="http://www.ikimi.net/wp-includes"&gt;http://www.ikimi.net/wp-includes&lt;/a&gt;。如果将起始页面换成&lt;a href="bbs.byr.cn"&gt;bbs.byr.cn&lt;/a&gt;会发现爬虫会以更快的速度在整个互联网蔓延开来！&lt;/p&gt;
&lt;p&gt;上述例子中可以学习到GreenPool类的使用。GreenPool可以类比于线程池，这有利于理解。在GreenPool中的元素都是GreenThread。其中最重要的函数是spawn/spawn_n函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Run the *function* with its arguments in its own green thread.&lt;/span&gt;
&lt;span class="s"&gt;        Returns the :class:`GreenThread &amp;lt;eventlet.greenthread.GreenThread&amp;gt;`&lt;/span&gt;
&lt;span class="s"&gt;        object that is running the function, which can be used to retrieve the&lt;/span&gt;
&lt;span class="s"&gt;        results.&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;该函数启动了一个GreenThread，参数是需要执行的function和function对应的参数。返回值是执行该函数的GreenThread类。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;spawn_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Create a greenthread to run the *function*, the same as&lt;/span&gt;
&lt;span class="s"&gt;        :meth:`spawn`.  The difference is that :meth:`spawn_n` returns&lt;/span&gt;
&lt;span class="s"&gt;        None; the results of *function* are not retrievable.&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;spawn_n函数功能上差不多，只是返回的是None。其他的函数举例简单说明如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;waitall():等待所有greenthread执行完毕。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;running(): 返回目前正在执行的greenthread。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;imap():从迭代器中取出数据項作为func的参数去执行，并返回结果。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;starmap(): 和imap类似，但是取参数的方式有所差异。从&lt;a href="http://blog.csdn.net/hackerain/article/details/7836993"&gt;openstack nova 基础知识——eventlet&lt;/a&gt;中摘取举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;imap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;span class="n"&gt;starmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;free(): 返回当前可获取的greenthread的数目。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上代码上的with语句是python中的一个非常方便的关键字。使用with关键字可以让代码更严谨且简洁。其封装了__enter__()函数和__exit__()函数，用于执行信息和退出处理。其等价于以下代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;try:&lt;/span&gt;
    &lt;span class="err"&gt;__enter__()&lt;/span&gt;
&lt;span class="err"&gt;finally:&lt;/span&gt;
    &lt;span class="err"&gt;__exit__()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;上述是关于GreenPool类的使用案例，使用该类可以高效完成并发操作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Convenience&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;接下来再介绍一个更好玩的程序，多人群聊程序，可以让我们在学习eventlet的时候充满成就感。代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;green&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;

&lt;span class="n"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3001&lt;/span&gt;
&lt;span class="n"&gt;participants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;read_chat_forever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;line:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Chat:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;participants:&lt;/span&gt;
            &lt;span class="n"&gt;try:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;writer:&lt;/span&gt;  &lt;span class="c1"&gt;# Don&amp;#39;t echo&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;
                    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e:&lt;/span&gt;
                &lt;span class="c1"&gt;# ignore broken pipes, they just mean the participant&lt;/span&gt;
                &lt;span class="c1"&gt;# closed its connection already&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;raise&lt;/span&gt;
        &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;participants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;participant left chat&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;try:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ChatServer starting up on port %s&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;0.0.0.0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;True:&lt;/span&gt;
        &lt;span class="n"&gt;new_connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Participant joined chat.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;new_writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;makefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;participants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_writer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;eventlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;read_chat_forever&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;new_writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;new_connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;makefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ChatServer exiting&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;try语句块中完成了服务端socket的建立和监听。然后在while循环中完成了消息的处理。&lt;/p&gt;
&lt;p&gt;首先关注第一个函数：eventlet.listen((addr,port))。在eventlet文件夹中，打开__init__文件可以查看到一些为了方便而初始化的定义，举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;version_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;__version__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version_info&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;try:&lt;/span&gt;
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;greenthread&lt;/span&gt;
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;greenpool&lt;/span&gt;
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;patcher&lt;/span&gt;
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eventlet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;convenience&lt;/span&gt;
    &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;greenlet&lt;/span&gt;



    &lt;span class="n"&gt;GreenPool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;greenpool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GreenPool&lt;/span&gt;
    &lt;span class="n"&gt;GreenPile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;greenpool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GreenPile&lt;/span&gt;

    &lt;span class="n"&gt;Queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;

    &lt;span class="n"&gt;import_patched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;patcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;import_patched&lt;/span&gt;
    &lt;span class="n"&gt;monkey_patch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;patcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;monkey_patch&lt;/span&gt;

    &lt;span class="nb"&gt;connect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convenience&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;connect&lt;/span&gt;
    &lt;span class="nb"&gt;listen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convenience&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt;
    &lt;span class="n"&gt;serve&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convenience&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serve&lt;/span&gt;
    &lt;span class="n"&gt;StopServe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convenience&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StopServe&lt;/span&gt;
    &lt;span class="n"&gt;wrap_ssl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convenience&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrap_ssl&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;所以我们直接可以使用eventlet.listen调用convenience.listen函数。listen函数完成了一个server socket的绑定和监听。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backlog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;win&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOL_SOCKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SO_REUSEADDR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;backlog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;socket.accept()函数将返回一个（connection，address）元组。socket.makefile([mode[, bufsize]])返回一个文件对象用于读写缓存。&lt;/p&gt;
&lt;p&gt;eventlet.spawn_n函数将read_chat_forever函数及其三个参数作为参数，创建GreenThread去执行任务。eventlet主要完成的工作就是帮助你如何去协调你的任务，而不是去实现你的任务，这一点在这里得到体现。其实对比于线程池就容易理解读多了。&lt;/p&gt;
&lt;p&gt;试验结果截图如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1en5tcjidm2j20gt0crabx.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;图2：多人群聊server运行界面&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1en5tcj7dvej20ln0crwh8.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;图3：多人群聊client运行界面&lt;/p&gt;
&lt;p&gt;从client运行界面可以看出不同的用户发送的信息会以IP：message的形式展示出来，代码很简单，但是非常有趣。&lt;/p&gt;
&lt;p&gt;以上例子均可以在官网找到，读者可以到官网去查看更多案例。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Patcher&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Patch是eventlet中的一个重要模块。用于替换系统自带的模块。其中有import_patched和monkey_patch两个函数，后者可以提供运行时替换。具体例子可以查看&lt;a href="http://blog.csdn.net/hackerain/article/details/7836993"&gt;openstack nova 基础知识——eventlet&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;回到RYU&lt;/h2&gt;
&lt;p&gt;前两行代码调用了hub.patch()函数，查看hub.py中发现patch = eventlet.monkey_patch，实现了运行时替换模块。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;
&lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;接下来的CONF文件由于oslo的内容比较多，所以会在后续博文中详细介绍。首先关注main()函数的主要内容。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu-manager %s&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;default_config_files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/local/etc/ryu/ryu.conf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfigFilesNotFoundError:&lt;/span&gt;
        &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu-manager %s&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init_log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file:&lt;/span&gt;
        &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
        &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pid_file:&lt;/span&gt;
            &lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

    &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;CONF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
    &lt;span class="c1"&gt;# keep old behaivor, run ofp if no application is specified.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;app_lists:&lt;/span&gt;
        &lt;span class="n"&gt;app_lists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ryu.controller.ofp_handler&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;app_mgr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_lists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;contexts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_contexts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instantiate_apps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;webapp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;webapp:&lt;/span&gt;
        &lt;span class="n"&gt;thr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webapp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;finally:&lt;/span&gt;
        &lt;span class="n"&gt;app_mgr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从CONF文件中取出app信息，存在app_lists内，若没有启动其他app,则默认启动ofp_handler应用，用于处理基础的事件，如协议协商等。然后声明一个AppManager的类，用于初始化和管理APP。load_apps函数完成了APP的加载。最后try语句块中的joinall()使得进程需要等待所有的services完成之后才能退出。至此RYU初始运行学习完成，后续的博文将分别介绍：oslo, 事件处理机制，RYUAPP类以及RYU数据结构和API使用等内容。&lt;/p&gt;
&lt;h2&gt;后语&lt;/h2&gt;
&lt;p&gt;Evenlet是个不错的python库，简单却很高效。相比于thread,coroutine的行为是可控的，切换成本也要更小。在单核情况下，coroutine要比thread开销小，但是multithread可以在多CPU的情况下发挥更大的能力。RYU是使用Python编写的控制器，比同样使用Python编写的POX，无论从代码的规范，优雅度，还是从性能上，都有很大的优势，此外，这个纯SDN控制器对OpenFlow协议的支持可以说是最稳定，最全面的。虽然我还会继续研究ONOS，学习大型分布式框架。但是RYU会成为我开发Application的利器。相比之下，Java编写的ODL，过于复杂和不稳定。新生儿ONOS相比之下用户体验更好，且没有使用YANG，大大降低了学习难度。周一的时候，还在Docker中安装了ONOS，并使用Cbench测试对比了ONOS和RYU的吞吐量。同样环境下，单节点的ONOS性能几乎是RYU的两倍，这让我有些忧伤。也许匕首只适合敏捷作战，而大刀才是开疆扩土的利器吧。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 10 Dec 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-12-10:pages/2014/12/10/ryuxue-xi-eventlet.html</guid><category>ryu</category><category>eventlet</category></item><item><title>Docker部署SDN环境</title><link>http://www.muzixing.com/pages/2014/12/03/dockerbu-shu-sdnhuan-jing.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;5月份的时候，当我还是一个大学生的时候，有个网友问我，你有研究Docker吗？当时我连Docker是什么都不知道。谷歌之后，对Docker产生兴趣，但是一直没有时间去学习。这个周终于将这个学习计划列入了Todolist。所以我花了3天时间，认真地把这&lt;a href="http://dockerpool.com/static/books/docker_practice/index.html"&gt;《Docker 从入门到实践》&lt;/a&gt;看完并实践了一遍，收获颇丰。虽然我的导师以及我自己还是觉得我在瞎转，而且我觉得没有方向的日子很痛苦。所以只好自己做计划，学习点新知识，打打基础了。本篇内容主要介绍什么是Docker、Docker简单入门以及如何使用Docker部署SDN环境，以及docker的网络配置等内容。What is Docker和Why Docker部分摘自《Docker从入门到实践》。&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://www.docker.com/whatisdocker/"&gt;What is Docker&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Docker 是一个开源项目，诞生于 2013 年初，最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会，遵从了 Apache 2.0 协议，项目代码在 GitHub 上进行维护。Redhat 已经在其 RHEL6.5 中集中支持 Docker；Google 也在其 PaaS 产品中广泛应用。&lt;/p&gt;
&lt;p&gt;Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。Docker 的基础是 Linux 容器（LXC）等技术。(新版本已修改，并不使用LXC技术)&lt;/p&gt;
&lt;p&gt;下面的图片比较了 Docker 和传统虚拟化方式的不同之处，可见容器是在操作系统层面上实现虚拟化，直接复用本地主机的操作系统，而传统方式则是在硬件层面实现。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://dockerpool.com/static/books/docker_practice/_images/virtualization.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://dockerpool.com/static/books/docker_practice/_images/docker.png" /&gt;&lt;/p&gt;
&lt;p&gt;图1：Docker和虚拟机对比&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://dockerpool.com/static/books/docker_practice/introduction/why.html"&gt;Why Docker&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;首先，Docker 容器的启动可以在秒级实现，这相比传统的虚拟机方式要快得多。 其次，Docker 对系统资源的利用率很高，一台主机上可以同时运行数千个 Docker 容器。&lt;/p&gt;
&lt;p&gt;容器除了运行其中应用外，基本不消耗额外的系统资源，使得应用的性能很高，同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机，而Docker 只需要启动 10 个隔离的应用即可。&lt;/p&gt;
&lt;p&gt;具体说来，Docker 在如下几个方面具有较大的优势。&lt;/p&gt;
&lt;h4&gt;更快速的交付和部署&lt;/h4&gt;
&lt;p&gt;对开发和运维（devop）人员来说，最希望的就是一次创建或配置，可以在任意地方正常运行。&lt;/p&gt;
&lt;p&gt;开发者可以使用一个标准的镜像来构建一套开发容器，开发完成之后，运维人员可以直接使用这个容器来部署代码。 Docker 可以快速创建容器，快速迭代应用程序，并让整个过程全程可见，使团队中的其他成员更容易理解应用程序是如何创建和工作的。 Docker 容器很轻很快！容器的启动时间是秒级的，大量地节约开发、测试、部署的时间。&lt;/p&gt;
&lt;h4&gt;更高效的虚拟化&lt;/h4&gt;
&lt;p&gt;Docker 容器的运行不需要额外的 hypervisor 支持，它是内核级的虚拟化，因此可以实现更高的性能和效率。&lt;/p&gt;
&lt;h4&gt;更轻松的迁移和扩展&lt;/h4&gt;
&lt;p&gt;Docker 容器几乎可以在任意的平台上运行，包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。&lt;/p&gt;
&lt;h4&gt;更简单的管理&lt;/h4&gt;
&lt;p&gt;使用 Docker，只需要小小的修改，就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新，从而实现自动化并且高效的管理。&lt;/p&gt;
&lt;h3&gt;Docker简单入门&lt;/h3&gt;
&lt;p&gt;谷歌出来的教程实在太多了。所以我也不打算太多介绍，只讲一些我觉得对于网络研究人员而言比较有用的命令。&lt;/p&gt;
&lt;h4&gt;基本概念&lt;/h4&gt;
&lt;p&gt;镜像（Image）:镜像是一个只读模板。用户上传制作好的镜像供其他人下载使用。用户可以基于镜像去创建Container。
容器（Container）:容器可以理解为一个隔离起来的linux环境，用于运行应用，Namespace可以帮助你理解。
仓库（Repository）:如果你会使用Git/Github的话，不难理解，就是用于存放镜像的场所。&lt;/p&gt;
&lt;h4&gt;Docker安装&lt;/h4&gt;
&lt;p&gt;本文的实验环境是Ubuntu14.04-amd64。非常需要注意的一点是，目前&lt;strong&gt;Docker只支持64位机器&lt;/strong&gt;。Ubuntu14.04安装方式有两种：1）通过系统自带包安装和2）通过Docker源安装。推荐第二种方式，能安装比较新的版本。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;adv&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;keyserver&lt;/span&gt; &lt;span class="n"&gt;hkp:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;keyserver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com:80&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nb"&gt;recv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;keys&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="n"&gt;A1D7869245C8950F966E92D8576A8BA88D21E9&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;bash&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;echo deb https://get.docker.io/ubuntu docker main &amp;gt; /etc/apt/sources.list.d/docker.list&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;lxc&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;获取镜像&lt;/h3&gt;
&lt;p&gt;首先，推荐到&lt;a href="hubhub.docke.com"&gt;Docker&lt;/a&gt;注册帐号，这样可以向使用Git/Github那样使用Docker/Dockerhub。注册和登陆可通过如下命令完成：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;注册之后，可以通过如下命令进行搜索,如搜索ryu:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;可以从搜索结果中的Star来确定资源的好坏，从而找到合适的images,如muzixing/ryu。然后使用如下命令，将其拉到本地：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;pull&lt;/span&gt;  &lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;下载完成后，可以通过如下命令查看已存在的images&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1emxdzs4wf6j20qp04rdh0.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;图2：images&lt;/p&gt;
&lt;h3&gt;创建容器&lt;/h3&gt;
&lt;p&gt;创建容器使用示例如下，-t=tty,  -i=interactive,  -d=debug, -p=port, --name &lt;name&gt;可以用于命名container。 其他的命令可以通过--help来查看。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;name&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="sr"&gt;/ryu:SDN  /&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bash&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;如果你需要对端口映射，或者网络配置方面的设置，还需要仔细去查看手册。举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;  &lt;span class="sr"&gt;&amp;lt;ip&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;name&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="sr"&gt;/ryu:SDN  /&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bash&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上命令创建并运行了一个名字叫&lt;name&gt;的container，并且将容器内部的端口port映射到主机的某个port，完成了端口映射，允许外网访问容器。这是容器与外界通信的方式之一。如果希望永久绑定到某个固定的 IP 地址，可以在 Docker 配置文件 /etc/default/docker 中指定 DOCKER_OPTS="--ip=IP_ADDRESS"，之后重启 Docker 服务即可生效。设置网络访问的参数默认是 --icc=ture，如果--icc=false,则禁止网络访问。&lt;/p&gt;
&lt;p&gt;查看容器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;-a为全部容器。&lt;/p&gt;
&lt;p&gt;查看打印信息可以通过：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;dokcer&lt;/span&gt; &lt;span class="n"&gt;logs&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;暂停容器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;开启暂停的容器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;重启容器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;restart&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;有时候我们开启了容器，但是没有开窗口，在后台运行，可以通过一下命令进入容器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;attach&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;部署SDN控制器RYU&lt;/h3&gt;
&lt;p&gt;首先获取镜像：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;pull&lt;/span&gt;  &lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后创建容器，并将容器的6633端口绑定到主机的6633端口。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;  &lt;span class="mf"&gt;0.0.0.0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6633&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6633&lt;/span&gt;  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;ryu3&lt;/span&gt;&lt;span class="mf"&gt;.15&lt;/span&gt; &lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="sr"&gt;/ryu:SDN  /&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bash&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;进入容器之后，运行ryu.&lt;/p&gt;
&lt;p&gt;在另一个能ping通运行容器主机的机器上运行mininet.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341jw1emxf7rriqyj20k10cp75p.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;图3：mininet运行图&lt;/p&gt;
&lt;p&gt;从上图可以看出控制器IP是172.16.192.128。这个IP地址的主机网卡信息如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341jw1emxdzrwx4nj20k20jadkv.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;图4：Host地址信息&lt;/p&gt;
&lt;p&gt;从图上可以看出，与mininet通信的是主机（实际情况下会是某台服务器）eth0的地址。但是从下面的图中看出运行的RYU地址是172.17.0.5。为什么可以通信呢？&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1emxdzrkaswj20k50hqwjb.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;图5：容器信息&lt;/p&gt;
&lt;p&gt;因为做了端口映射，将主机的所有接口的6633端口的地址都转发到容器172.17.0.5的6633端口，从而完成数据通信。其实现的原理是：Docker在启动之后，会创建一个docker0的网桥,从图4可以看到。然后还会创建veth pair。其中一端挂载在网桥上，如图4的vethba5f9f3，另一端是容器的网卡eth0，此案例中是172.17.0.5的网卡。其实这相当与一个link。原理图如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341jw1emxfusmbzoj20l30dhmy1.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;图6：Docker网络通信原理&lt;/p&gt;
&lt;p&gt;在运行容器的主机上使用iptables命令查看nat规则：
&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1emxf7rim1mj20jj082dh5.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;图7：iptables查看NAT。&lt;/p&gt;
&lt;p&gt;同理mininet，或者其他的应用程序也可以使用容器部署，不再赘述，读者可自行尝试。&lt;/p&gt;
&lt;h3&gt;上传镜像&lt;/h3&gt;
&lt;p&gt;首先需要将部署了应用的容器导出为tar文件。可以使用docker export container &amp;gt; file 命令。举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="n"&gt;ryu3&lt;/span&gt;&lt;span class="mf"&gt;.15&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后使用docker import命令将其导入为镜像：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cat&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ryu:sdn&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上命令为读取ryu.tar 将其导入成muzixing/ryu:sdn的image。完成之后可通过docker images查看。&lt;/p&gt;
&lt;p&gt;确保无误之后，可将其推送到Dockerhub。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="n"&gt;muzixing&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;读者也可以尝试更好的自动创建方式。&lt;/p&gt;
&lt;h3&gt;网络配置&lt;/h3&gt;
&lt;p&gt;我们完全可以将Docker理解成一个独立的主机，可以对其网络进行配置，如配置DNS，iptables等。可以通过启动时配置，也可以通过修改文件的方式配置。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;BRIDGE&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;bridge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BRIDGE&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="err"&gt;指定容器挂载的网桥&lt;/span&gt;
&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;bip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CIDR&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="err"&gt;定制&lt;/span&gt; &lt;span class="n"&gt;docker0&lt;/span&gt; &lt;span class="err"&gt;的掩码&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="n"&gt;SOCKET&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SOCKET&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;Docker&lt;/span&gt; &lt;span class="err"&gt;服务端接收命令的通道&lt;/span&gt;
&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;icc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="err"&gt;是否支持容器之间进行通信&lt;/span&gt;
&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="err"&gt;请看下文容器之间的通信&lt;/span&gt;
&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;iptables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="err"&gt;禁止&lt;/span&gt; &lt;span class="n"&gt;Docker&lt;/span&gt; &lt;span class="err"&gt;添加&lt;/span&gt; &lt;span class="n"&gt;iptables&lt;/span&gt; &lt;span class="err"&gt;规则&lt;/span&gt;
&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;mtu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BYTES&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="err"&gt;容器网络中的&lt;/span&gt; &lt;span class="n"&gt;MTU&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;文件配置则如同正常的主机配置，进入到/etc/目录下，修改制定文件即可。同样的，Dokcer可以配置网络链接的网桥，可以不选择docker0网桥，而选择其他网桥，如使用brctl创建的网桥，或者使用OpenvSwitch创建的网桥，具体操作不再赘述。&lt;/p&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;工欲善其事，必先利其器。Docker可以允许我们更灵活地使用资源，并且可以很方便地迁移环境。比如以后需要安装RYU的同学就不需要再去关注，为什么six版本不够？为什么gcc报错这些问题了。只需要有一台64位的机器，然后安装docker,理论上是不会有错的。然后将镜像下载下来，创建并运行容易，就可以得到ryu控制器运行的环境。同理Nginx，Tornado和MySQL等软件也可以直接获取，而不需要自己安装配置环境。这大大加快了生产环境的部署，也显著提高了资源的利用率，个人认为将在未来对虚拟机产生强烈的冲击。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 03 Dec 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-12-03:pages/2014/12/03/dockerbu-shu-sdnhuan-jing.html</guid><category>Docker</category><category>sdn</category><category>RYU</category></item><item><title>ONOS论文解析</title><link>http://www.muzixing.com/pages/2014/11/26/onoslun-wen-jie-xi.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;不久之前，onlab的那群人，发布了ONOS。同时也在SIGCOMM上发表了一篇论文&lt;a href="http://onos.wpengine.com/wp-content/uploads/2014/11/HotSDN-paper-2014-ONOS-Towards-an-Open-Distributed-SDN-OS.pdf"&gt;ONOS: Towards an Open, Distributed SDN OS&lt;/a&gt;,这引起了很多人的关注。博主刚好得知这个消息，阅读了一遍ONOS的论文，总（翻）结（译）了一下论文的内容，作为自己的论文笔记（好长的笔记）。但是越来越感觉读论文，然后写一些读书或者读论文笔记没有意思。因为写着写着，写成了翻译，完全没有自己的观点。还不如去做些实验，写点教程来得实在。读研究生的生活也感觉有些无所事事了，我想我应该做点有意义的事情，比如学一下Docker, OpenStack之类的。搞学术，学术不让啊！&lt;/p&gt;
&lt;h2&gt;ABSTRACT&lt;/h2&gt;
&lt;p&gt;ONOS(Open Networking Operating System)是一个分布式的SDN控制平台。ONOS满足了大规模网络操作系统对性能，拓展性等需求。在论文中，他们提出了来那个个ONOS的模型。第一个模型实现了核心的特性，完成了一个分布式的网络操作系统模型，但是性能不够好。第二个模型则在第一个模型的基础之上，大大提高了ONOS的性能。&lt;/p&gt;
&lt;h2&gt;INTRODUCTION&lt;/h2&gt;
&lt;p&gt;为了支持大规模网络的需求，ONOS可能需要满足一下极具挑战性的需求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;High Throughput: up to 1M requests/second&lt;/li&gt;
&lt;li&gt;Low Latency: 10 - 100 ms event processing&lt;/li&gt;
&lt;li&gt;Global Network State Size: up to 1TB of data&lt;/li&gt;
&lt;li&gt;High Availability: 99.99% service availability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341jw1emom6fdh4rj20ir0b4gmw.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;PROTOTYPE 1: NETWORK VIEW, SCALE-OUT, FAULT TOLERANCE&lt;/h2&gt;
&lt;p&gt;ONOS的第一个模型使用了若干的开源软件来构建整个系统。比如使用FloodLight的一些现有模块，如switch manger、I/O loop、link discovery、module management、以及REST API。也使用到了Zookeeper, Titan, Cassandra以及Blueprints等开源软件。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1emoijpm69xj20g50c2dha.jpg" /&gt;&lt;/p&gt;
&lt;h4&gt;Global Network View&lt;/h4&gt;
&lt;p&gt;ONOS维持了一个全网拓扑视图，从而允许一个ONOS集群内的实例能相互之间分享和管理网路信息。其全网拓扑信息包括switch、port、link和host等信息。ONOS使用&lt;a href="http://thinkaurelius.github.io/titan/"&gt;Titan&lt;/a&gt; graph database来存储，并使用Cassandra 来保障分布式和可持续性。由于Cassandra具有一致性存储的特性，所以保障了网络视图的最终一致性。&lt;/p&gt;
&lt;h4&gt;Scale-out.&lt;/h4&gt;
&lt;p&gt;ONOS的一个关键特性就是拓展性。ONOS分布式运行在多个服务器上，每一个实例是其管理的网络子集中的交换机的控制器。一个独立的ONOS实例将独立地完成网络的控制，并始终保持与全网视图的一致，即网络中发生状态变化，如添加交换机等时间，都应该由ONOS实例负责将这个事件传播到全局网络视图（Global Network View）。&lt;/p&gt;
&lt;h4&gt;Fault tolerance&lt;/h4&gt;
&lt;p&gt;分布式的ONOS允许即使某一个组件甚至某一个ONOS实例Down掉也不会影响整个系统的运行。ONOS允许component作为一个单独的实例去运作，不过也提供了多冗余容灾的能力。多实例的情况下，需要选择出leader，这个在分布式系统中是分厂必要的行为。在OpenFlow1.3版本中，有多控制器的定义。ONOS可以允许交换机连接到多控制器，但是对于交换机而言只有一个控制器是master，其他的是slaver。当某一个ONOS发生故障Down掉之后，他所管理的交换机将由别的ONOS实例接管。ONOS使用&lt;a href="http://zookeeper.apache.org/"&gt;Zookeeper&lt;/a&gt;来存储交换机和控制器之间的关系数据。每一个ONOS实例都需要连接Zookeeper。&lt;a href="https://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/"&gt;Zookeeper&lt;/a&gt;曾经是&lt;a href="http://hadoop.apache.org/"&gt;Hadoop&lt;/a&gt;的一个子项目。现在已经好似一个顶级项目。它主要是用来解决分布式应用中经常遇到的一些数据管理问题，如：统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。&lt;/p&gt;
&lt;h3&gt;Evaluation&lt;/h3&gt;
&lt;p&gt;ONOS的第一个模型花了4个月的时间（好快！）。但是，这个Prototype的性能表现并不好。论文中举例分析如下：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consistency and Integrity&lt;/strong&gt;:  这一部分论文写得比较模糊，没有看懂，所以不发表评论。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Low Performance and Visibility&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;模型一的性能并不好，特别是延迟比预期的要差许多，比如30s才可以获取到网络拓扑状态变化情况。主要原因在与使用了开源软件，虽然很快可以完成开发，但是这些开源软件之间的协调，并不容易。而且ONOS的开发者并不是特别熟悉这些开源代码，导致性能并不高。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data Model Issues&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于使用Titan存储，所以所有数据如Port,flow entries等都需要以Vertices存储。而且需要构建一个索引来查询数据如交换机数据。当大量节点加入网络时，并发的数据量就会很大，所以索引构建就会成为瓶颈。即使一个很小的改动，也会引起许多许多数据库更新的操作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Excessive Data Store Operations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于使用了Cassandra和Titan,完成这两者之间的数据转换则产生过多的数据存储操作。每一个简单的网络操作都会由于过多的数据读取和写入操作而延迟。原因如下：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Polling&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于时间紧张，第一个模型，并没有实现订阅分发，而是通过周期同步数据，显然这样增加了CPU的使用率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lessons Learned&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第一个模型的测试能学到一些教训，比如设计更高效的数据模型，减少多余的数据操作，以及更简化的API等等。&lt;/p&gt;
&lt;h2&gt;PROTOTYPE 2: IMPROVING PERFORMANCE&lt;/h2&gt;
&lt;p&gt;第二个模型关注于提升性能。所以第二个模型改变了network view architecture,还增加了一个事件通知框架。在第一个模型中，远程操作是造成性能瓶颈的重要原因之一，所以在模型二中，通过减少远程操作的数量和加快远程操作的速度来解决这个问题。改变之后的模型二如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1emqixkwgv8j20jw0f5762.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RAMCloud Data Store&lt;/strong&gt;: &lt;a href="https://ramcloud.atlassian.net/wiki/display/RAM/RAMCloud"&gt;RAMCloud&lt;/a&gt;中文名字应该叫“内存云”，顾名思义，使用内存来代替普通硬盘来存储，从而大大提高存储速度。
&lt;strong&gt;Optimized Data Model&lt;/strong&gt;： 优化向来都是一个复杂的事情。他们新设计了一个data model（中文怎么称呼都不舒服），也不追求数据完整性了，许多更新都是相对独立的，从而大大减少了数据的读写操作，优化了性能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Topology Cache&lt;/strong&gt;： 读取拓扑是一个非常耗时的操作，所以新的ONOS将拓扑信息存在高速缓存中，从而提高了读取拓扑的速度。除此之外，他们还构建了一个索引用于更快速地查找数据。构建索引的过程可以在任何时刻由全部的数据生成，但是一般情况下，只有新的ONOS节点接入时，才会读取全部数据，所以从全局来看，这并不会消耗太多时间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Event Notification&lt;/strong&gt;： 前面已经提到由于周期获取数据而引起的性能问题，所以一个事件通知机制非常必要。模型二创建了一个实例内部的发布-订阅的事件机制，然后将这个通信系统部署在了&lt;a href="http://hazelcast.com/"&gt;Hazelcast&lt;/a&gt;上（又一个牛逼的开源软件。）发布订阅模式无需赘述。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Network View API&lt;/strong&gt;： 关于API的改动，ONOS用自己设计的API取代了生成的Blueprints graph API。Figure4展示了网络视图所包含的内容。ONOS的API主要由以下三个主要部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对底层设施拓扑的抽象描述的接口;&lt;/li&gt;
&lt;li&gt;处理网络或系统Events（事件）的接口;&lt;/li&gt;
&lt;li&gt;提供安装流表等信息的接口。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1emqk7nvjdwj20m10e175m.jpg" /&gt;&lt;/p&gt;
&lt;h3&gt;Evaluation&lt;/h3&gt;
&lt;p&gt;对于模型二的性能主要分为一下三个方面进行测试和评价：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对基础网络状态改变的反应&lt;/li&gt;
&lt;li&gt;对网络事件的反应&lt;/li&gt;
&lt;li&gt;下发流表路径部署&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Basic Network State Changes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;网络中状态的改变会阻塞ONOS的操作，直到数据更新完成。所以这一点对整个ONOS的性能影响巨大。&lt;/p&gt;
&lt;p&gt;测试案例中使用了三个节点的ONOS集群，连接了81个OpenFlow交换机，组成了一个典型的WAN拓扑，每一个交换机上都有四个活跃的端口。&lt;/p&gt;
&lt;p&gt;为测试这个性能，ONOS采用了对比的方式。Table 1中展示了添加一个交换机这个动作所需要的latency。从表中可以看出，使用通用的API，速度最慢。使用自定义的API速度快了很多。因为使用新的Data model仅仅需要一个操作可以完成添加交换机的操作，所以时间从22.2ms下降到了1.19ms。在序列化方面还尝试了&lt;a href="http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/"&gt;Google Protocol Buffers&lt;/a&gt;，这个尝试可以将latency下降了0.244ms。最后他们还尝试了使用&lt;a href="http://en.wikipedia.org/wiki/InfiniBand"&gt;Infiniband&lt;/a&gt;的I/O架构，从而得到了更好的数据。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1emql9ck45tj20gk05tgma.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reaction to Network Events&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这项测试组要用于评价ONOS对网络事件的反应速度等性能。如网路中某一个link down掉之后，ONOS对流量重新路由的过程需要多长时间。这个性能直接关系到SLA（Service-Level Agreement）的性能。&lt;/p&gt;
&lt;p&gt;这个实验使用了6个节点的ONOS的集群，数据层面使用mininet模拟了206个软件交换机和416个link。他们将16000条flows添加到网络中，然后关掉网络中的某一个交换端口，则足以导致1000多条flow发生改变，从而重新路由这些flow。其中每一条流有六跳，当某个端口down掉之后，他们都变成7跳的流。&lt;/p&gt;
&lt;p&gt;Table 2展示了重新路由进度进行到一半和99%的数据。其中包括从网络时间被捕捉到到下发第一条flow_mod的过程。以及全部Flow_mod都下发。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1emqrajqucxj20em03ywer.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Path Installation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第三个性能指标测试了ONOS系统的吞吐量。这次测试使用了与第二项性能指标一样的拓扑。但是预下发了15000条静态流表。他们添加了1000条6hops的flow。Table 3展示的测试结果。吞吐量和延时成反比，所以在进程进行到一半的时候吞吐量为18832paths/sec。（好像性能不够好！）&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1emqrthq20mj20ex03w0sy.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;在Prototype2中，ONOS对网络事件的延迟上达到了预期的要求，但是在吞吐量上还没有达到1M path/sec的标准。不过作者们将这个原因归咎与仅仅使用一个ONOS节点来计算路径。如果分布式计算路径效果肯定会更好一些吧。&lt;/p&gt;
&lt;h3&gt;Demonstration on Internet2&lt;/h3&gt;
&lt;p&gt;论文作者们将ONOS部署在Internet2上，运行正常。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww3.sinaimg.cn/mw690/7f593341jw1emqsv4wsd3j20f80b20uy.jpg" /&gt;
&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1emqsv58p7yj20fg0bd40z.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;DISCUSSION: TOWARDS AN OPEN, DISTRIBUTED NETWORK OS&lt;/h2&gt;
&lt;h3&gt;Use Cases&lt;/h3&gt;
&lt;p&gt;ONOS可以提供的使用案例如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1emqt0ik8xej20up0li0v1.jpg" /&gt;&lt;/p&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;ONOS看起来应该是个不错的产品，希望性能和稳定度上能达到不错的水平。在读ONOS论文的过程中，学习到了许多关于分布式计算的知识，也看到了使用开源软件快速开发的模式。我想这些都是我们应该学习的。目前已经有太多优秀的开源软件，合理使用开源软件能够避免重新造轮子的过程。不过我们也从ONOS的例子中看到，并不是使用开源软件叠加就能出来一个非常好的产品，关键的数据模型等方面还是需要研发人员用心设计才能达到一个非常好的效果。希望ONOS能给SDN带来更多市场吧。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 26 Nov 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-11-26:pages/2014/11/26/onoslun-wen-jie-xi.html</guid><category>ONOS</category><category>controller</category></item><item><title>sFlow入门初涉</title><link>http://www.muzixing.com/pages/2014/11/21/sflowru-men-chu-she.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://www.sflow.org/sFlowOverview.pdf"&gt;sFlow&lt;/a&gt;是一个应用在高速交换网络中的监控软件。sFlow需要交换机支持才能使用，万幸OpenvSwitch支持这个功能。netflow同样也是类似功能的软件，可惜没有接触过，也只是听过名字而已。第一次接触到sFlow之后，就觉得很感兴趣，跟着&lt;a href="http://www.sdnlab.com/3760"&gt;SDNLAB&lt;/a&gt;的教程做了一遍之后，记录下自己的学习过程。&lt;/p&gt;
&lt;h3&gt;安装sFlow&lt;/h3&gt;
&lt;p&gt;下载sFlow代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;pan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baidu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/s/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;mgmOVck&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;解压缩，安装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;tar&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;zxvf&lt;/span&gt; &lt;span class="n"&gt;sflow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gz&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;sflow&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sflow&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rt&lt;/span&gt;
&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;此时通过浏览器127:0.0.1:8008可以查看到生成的页面。&lt;/p&gt;
&lt;h3&gt;实验步骤&lt;/h3&gt;
&lt;p&gt;本实验步骤将介绍如何在一台机器上完成sflow流量监控实验。实验需要运行一个控制器，可以使用mininet自带的控制器，也可以使用RYU等控制器。然后运行mininet，设置OVS的sFlow功能，从而从8008端口上查看到相应的数据。&lt;/p&gt;
&lt;h3&gt;启动mininet&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;mn&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;或者&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;mn&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;controllerip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;开启OVS的sFlow功能&lt;/h4&gt;
&lt;p&gt;为了让mininet中创建的OVS和本地网卡相连，从而使得8008端口可以通过网卡获取到mininet中流量数据，我们需要将某个网卡加入到OVS生成的bridge上。选择最简单的eth0即可，不过如果eth0是连接外网的网卡的话，很可能添加到bridge之后，就无法上网了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="n"&gt;eth0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;设置s1的IP，使得交换机可以作为sFlow agent与sFlow Collector通信。例如，给s1使用eth的IP：10.108.144.45，此举确保IP是可用的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="n"&gt;ifconfig&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="mf"&gt;10.108.144.45&lt;/span&gt; &lt;span class="n"&gt;netmask&lt;/span&gt; &lt;span class="mf"&gt;255.255.255.248&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;配置之后，查看配置是否生效：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ifconfig&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;开启OVS的sFlow功能：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@sflow_id&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;sFlow&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=\&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;127.0.0.1:6343\&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt; &lt;span class="n"&gt;sampling&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt; &lt;span class="n"&gt;polling&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;bridge&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="n"&gt;sflow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@sflow_id&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其中agent指的是需要作为sFlow agent的网卡，target是目标的sFlow Collector。&lt;/p&gt;
&lt;p&gt;查看配置是否生效：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;sflow&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;查看结果如下图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww1.sinaimg.cn/mw690/7f593341jw1emisnsk7gmj20fb06emxu.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;list功能可以查看很多内容，如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;
&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;
&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;qos&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;监控网络流量&lt;/h3&gt;
&lt;p&gt;打开127.0.0.1：8008，点击agent等栏目能看到对应的信息。在mininet中使用pingall，iperf iperfudp等命令产生流量，并查看统计情况。实例如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/7f593341jw1emismf2z9nj21da0dz0wn.jpg" /&gt;&lt;/p&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;在网络中，如果能实时监控到网络的流量，那么就可以根据网络流量数据做出许多Traffic Engineering的操作。所以对于一个网络而言，实时的网络流量数据至关重要。本篇教程是在阅读了SDNLAB网站的教程之后，自己总结的单机版sFlow部署。更多详细的内容，大家可以到&lt;a href="http://www.sdnlab.com"&gt;SDNLAB&lt;/a&gt;去查看。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 21 Nov 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-11-21:pages/2014/11/21/sflowru-men-chu-she.html</guid><category>Moniter</category><category>sflow</category><category>mininet</category></item><item><title>Load balance(Multipath) Application on RYU</title><link>http://www.muzixing.com/pages/2014/11/07/load-balancemultipath-application-on-ryu.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;本篇博文介绍的是如何在RYU上通过使用select group 来实现multipath，从而实现流量的调度，完成简单的负载均衡Demo。OpenFlow13中有group table,可用于实现组播和冗余容灾等功能。实验中还是用了queue,完成了链路带宽的保障。&lt;/p&gt;
&lt;h2&gt;相关工作&lt;/h2&gt;
&lt;p&gt;要完成多径传输，那么网络拓扑必然有loop，所以首先要解决由于loop而可能产生的storm。解决方案在之前一个&lt;a href="http://www.muzixing.com/pages/2014/10/19/ji-yu-sdnde-ryuying-yong-arp_proxy.html"&gt;博文&lt;/a&gt;中已经提出。本应用就是利用了这个思想，实现了环路风暴的解除（可能有的情况下不成功，原因未知）&lt;/p&gt;
&lt;h3&gt;网络拓扑&lt;/h3&gt;
&lt;p&gt;网络拓扑文件内容如下所示，也可以到github上下载，详情查看文章结尾。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Custom loop topo example&lt;/span&gt;

&lt;span class="s"&gt;   There are two paths between host1 and host2.&lt;/span&gt;

&lt;span class="s"&gt;                |--------switch2 --------|&lt;/span&gt;
&lt;span class="s"&gt;   host1 --- switch1        |            switch4 ----host2&lt;/span&gt;
&lt;span class="s"&gt;                |           |            |  |______host3&lt;/span&gt;
&lt;span class="s"&gt;                -------- switch3 ---------&lt;/span&gt;
&lt;span class="s"&gt;                            |&lt;/span&gt;
&lt;span class="s"&gt;                          host4&lt;/span&gt;

&lt;span class="s"&gt;Adding the &amp;#39;topos&amp;#39; dict with a key/value pair to generate our newly defined&lt;/span&gt;
&lt;span class="s"&gt;topology enables one to pass in &amp;#39;--topo=mytopo&amp;#39; from the command line.&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;topo&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Topo&lt;/span&gt;


&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;MyTopo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Topo&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;Simple loop topology example.&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;Create custom loop topo.&amp;quot;&lt;/span&gt;

        &lt;span class="c1"&gt;# Initialize topology&lt;/span&gt;
        &lt;span class="n"&gt;Topo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Add hosts and switches&lt;/span&gt;
        &lt;span class="n"&gt;host1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;h1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;host2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;h2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;host3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;h3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;host4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;h4&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;host5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;h5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;host6&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;h6&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;switch1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;switch2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;switch3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;switch4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;switch5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Add links&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;topos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mytopo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lambda:&lt;/span&gt; &lt;span class="n"&gt;MyTopo&lt;/span&gt;&lt;span class="p"&gt;())}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Multipath&lt;/h2&gt;
&lt;p&gt;解决网络可能形成风暴的问题之后，可以使用select类型的group_table来实现多径功能。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;send_group_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ofp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;
    &lt;span class="n"&gt;ofp_parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;

    &lt;span class="n"&gt;port_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;actions_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

    &lt;span class="n"&gt;port_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;actions_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

    &lt;span class="n"&gt;weight_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
    &lt;span class="n"&gt;weight_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;

    &lt;span class="n"&gt;watch_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_ANY&lt;/span&gt;
    &lt;span class="n"&gt;watch_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPQ_ALL&lt;/span&gt;

    &lt;span class="n"&gt;buckets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPBucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weight_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watch_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watch_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions_1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPBucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weight_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watch_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watch_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions_2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

    &lt;span class="n"&gt;group_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPGroupMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPFC_ADD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ofp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPGT_SELECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;不知道现在OVS的select的key是否已经改变，原先的key为dl_dst。匹配成功的flow，在执行select时，是以dl_dst为key,进行判断，从而从buckets中选择一个action_list。&lt;/p&gt;
&lt;p&gt;查看组表信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ofctl&lt;/span&gt; &lt;span class="nb"&gt;dump&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt; &lt;span class="n"&gt;OpenFlow13&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;查看流表信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ofctl&lt;/span&gt; &lt;span class="nb"&gt;dump&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;flows&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt; &lt;span class="n"&gt;OpenFlow13&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;QoS&lt;/h2&gt;
&lt;p&gt;首先我们知道OpenFlow无法创建队列。所以我们可以通过&lt;a href="http://osrg.github.io/ryu-book/ja/html/rest_qos.html"&gt;ovsdb来配置队列&lt;/a&gt;，也可以直接使用ovs命令配置:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;Port&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;eth2&lt;/span&gt; &lt;span class="n"&gt;qos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@newqos&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
     &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@newqos&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;QoS&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;htb&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;config:max&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;250000000&lt;/span&gt; &lt;span class="n"&gt;queues&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@q0&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
     &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@q0&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;config:min&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8000000&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;config:max&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;150000000&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;

&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;Port&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;eth3&lt;/span&gt; &lt;span class="n"&gt;qos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@defaultqos&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@defaultqos&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;QoS&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;htb&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;config:max&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300000000&lt;/span&gt; &lt;span class="n"&gt;queues&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@q1&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
     &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;@q1&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;config:min&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5000000&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;config:max&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200000000&lt;/span&gt;

&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上代码在s1-eth2上创建了queue 0,在s1-eth3上创建了queue 0和queue 1。并配置了max_rate和min_rate。&lt;/p&gt;
&lt;p&gt;查看queue的信息可以使用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ofctl&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt; &lt;span class="n"&gt;OpenFlow13&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;列举port查看qos：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;列举queue：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;删除QOS:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;destroy&lt;/span&gt; &lt;span class="n"&gt;qos&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;destroy&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;区别于OpenFlow1.0, OpenFlow1.3中的入队操作只有一个queue_id,需要额外指定port。即指定数据如某一个队列的话需要如下的actions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;actions_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionSetQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;所以使用group的情况下，完成QoS功能函数如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;send_group_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ofp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;
        &lt;span class="n"&gt;ofp_parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;

        &lt;span class="n"&gt;port_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
        &lt;span class="n"&gt;queue_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionSetQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;actions_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;queue_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

        &lt;span class="n"&gt;port_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;queue_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionSetQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;actions_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;queue_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

        &lt;span class="n"&gt;weight_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
        &lt;span class="n"&gt;weight_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;

        &lt;span class="n"&gt;watch_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_ANY&lt;/span&gt;
        &lt;span class="n"&gt;watch_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPQ_ALL&lt;/span&gt;

        &lt;span class="n"&gt;buckets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPBucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weight_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watch_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watch_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions_1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPBucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weight_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watch_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watch_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions_2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

        &lt;span class="n"&gt;group_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPGroupMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPFC_ADD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ofp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPGT_SELECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Load balancing&lt;/h2&gt;
&lt;p&gt;&lt;img alt="mininet" src="http://ww1.sinaimg.cn/mw690/7f593341jw1em5uu5i76qj20k40cr0v8.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;从图中我们可以看到，pingall连通性没有问题。第一个iperf是在没有设置队列的情况下，由于找不到队列，所以不如队，只转发，此时带宽为26.4Gbits/sec。之后的测试数据为设置队列之后的数据。可以看出h1到h2之间的带宽是300Mbits/sec，而h1到h3的带宽是150Mbits/sec。 &lt;/p&gt;
&lt;p&gt;原因在于我们将h1到h2的数据流在组表中选择了s1-eth3的queue 0，而该队列的最大带宽是300M。&lt;/p&gt;
&lt;p&gt;同时另一个从h1到h3的数据流，在hash过程中，选择了s1-eth2端口的queue 0，该队列的最大速度为150M。&lt;/p&gt;
&lt;p&gt;下图为queue information：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341jw1em5uu6ecr8j20k30cuq63.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;可以看到，port 2 queue 0和port 3 queue 0有数据，而port 3 queue 1没有数据。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ww2.sinaimg.cn/mw690/7f593341jw1em5uu5dgjfj20k80cu0xb.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;上图为s1和s4的组表和流表信息，从s4的流表信息（后部分流表）可知，同样是s1到s4的数据，dl_dst为h2的数据从port 2进入，而dl_dst为h3的数据从port 1进入，验证了数据传输过程使用了多径传输，合理利用了带宽空间。多径传输可以充分利用链路带宽，提高链路利用率。同时这个实验简单粗暴地完成了两条链路的负载均衡（将不同的数据流平均地分摊到了两条path上，由于对不同Path限制了不同的带宽，所以，流量并不是平均的）。根据拓扑及流量情况，添加算法计算合理流量路径，可以完成更灵活有效的负载均衡功能。&lt;/p&gt;
&lt;h2&gt;后语&lt;/h2&gt;
&lt;p&gt;这其实是简单的实验，但是由于在安装OVS的过程中遇到了很多的问题，所以过程比较痛苦，写下来，以备不时之需，也有可能帮助到别人吧。提供一个纯从&lt;a href="http://hwchiu.logdown.com/posts/207387-multipath-routing-with-group-table-at-mininet"&gt;OVS上配置的方案&lt;/a&gt;，相比之下比开发控制要简单一些。之前的博文的名字是：Multipath and QoS Application on RYU,但是后来导师提醒Multipath 和QoS不是一个层面的，才发现自己学识粗浅。需要努力的地方还太多。所以本篇博文被我生生改成Load balance的题目，虽然很牵强，但是相比之下，犯的错误更少一些。&lt;/p&gt;
&lt;p&gt;全部代码文件在github的&lt;a href="https://github.com/muzixing/ryu/tree/master/ryu/app/multipath"&gt;multipath&lt;/a&gt;,请读者到github查看具体的实验步骤。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 07 Nov 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-11-07:pages/2014/11/07/load-balancemultipath-application-on-ryu.html</guid><category>multipath</category><category>qos</category><category>queue</category><category>SDN</category><category>RYU</category><category>load balance</category></item><item><title>OpenvSwitch2.3.0 and Mininet install</title><link>http://www.muzixing.com/pages/2014/11/02/openvswitch230-and-mininet-install.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;折腾了我两个周的事情是一定要写出来的，后来人就不用继续掉坑里了。在此感谢@南京-小L的帮助。&lt;/p&gt;
&lt;h3&gt;安装OpenvSwitch2.3.0&lt;/h3&gt;
&lt;p&gt;不需要安装。但是友情提供一键安装脚本：&lt;/p&gt;
&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Make sure only root can run our script&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(id -u)&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;   &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;You need to be &amp;#39;root&amp;#39; dude.&amp;quot;&lt;/span&gt; 1&amp;gt;&amp;amp;2
   &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;#install&lt;/span&gt;
&lt;span class="c"&gt;#apt-get update&lt;/span&gt;
&lt;span class="c"&gt;#apt-get install -y build-essential&lt;/span&gt;


&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;====================INSTALL OpenvSwitch-2.3.0====================&amp;quot;&lt;/span&gt;
&lt;span class="c"&gt;#apt-get install -y   uml-utilities libtool python-qt4 python-twisted-conch debhelper python-all&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;  -f openvswitch-2.3.0.tar.gz &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then &lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;openvswitch-2.3.0.tar.gz has exist&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;wget http://openvswitch.org/releases/openvswitch-2.3.0.tar.gz
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;  -d openvswitch-2.3.0 &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;   &lt;/span&gt;rm -r openvswitch-2.3.0
&lt;span class="k"&gt;fi&lt;/span&gt;
tar -xzf openvswitch-2.3.0.tar.gz

&lt;span class="c"&gt;# Install openvswitch&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;openvswitch-2.3.0
make clean
./configure --with-linux&lt;span class="o"&gt;=&lt;/span&gt;/lib/modules/&lt;span class="sb"&gt;`&lt;/span&gt;uname -r&lt;span class="sb"&gt;`&lt;/span&gt;/build 2&amp;gt;/dev/null
make &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make install

&lt;span class="c"&gt;# install Open vSwitch kernel module&lt;/span&gt;
insmod datapath/linux/openvswitch.ko
make modules_install


mkdir -p /usr/local/etc/openvswitch
ovsdb-tool create /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema  2&amp;gt;/dev/null

&lt;span class="c"&gt;# start ovs server&lt;/span&gt;
sh /usr/local/share/openvswitch/scripts/ovs-ctl restart

&lt;span class="c"&gt;# Also, you can start ovs server by below commands.&lt;/span&gt;
&lt;span class="c"&gt;#ovsdb-server -v --remote=punix:/usr/local/var/run/openvswitch/db.sock \&lt;/span&gt;
&lt;span class="c"&gt;#             --remote=db:Open_vSwitch,Open_vSwitch,manager_options \&lt;/span&gt;
&lt;span class="c"&gt;#             --private-key=db:Open_vSwitch,SSL,private_key \&lt;/span&gt;
&lt;span class="c"&gt;#             --certificate=db:Open_vSwitch,SSL,certificate \&lt;/span&gt;
&lt;span class="c"&gt;#             --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \&lt;/span&gt;
&lt;span class="c"&gt;#             --pidfile --detach&lt;/span&gt;

&lt;span class="c"&gt;#ovs-vsctl --no-wait init&lt;/span&gt;
&lt;span class="c"&gt;#ovs-vswitchd --pidfile --detach&lt;/span&gt;
ovs-vsctl show
depmod -A openvswitch
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;h3&gt;Mininet安装&lt;/h3&gt;
&lt;p&gt;如果以前有安装mininet，那么你需要先卸载mininet&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;rm&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rf&lt;/span&gt; &lt;span class="sr"&gt;/usr/&lt;/span&gt;&lt;span class="nb"&gt;local&lt;/span&gt;&lt;span class="sr"&gt;/bin/m&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="sr"&gt;/usr/&lt;/span&gt;&lt;span class="nb"&gt;local&lt;/span&gt;&lt;span class="sr"&gt;/bin/m&lt;/span&gt;&lt;span class="n"&gt;nexec&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
        &lt;span class="sr"&gt;/usr/&lt;/span&gt;&lt;span class="nb"&gt;local&lt;/span&gt;&lt;span class="sr"&gt;/lib/&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="sr"&gt;/*/&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
        &lt;span class="sr"&gt;/usr/&lt;/span&gt;&lt;span class="nb"&gt;local&lt;/span&gt;&lt;span class="sr"&gt;/bin/o&lt;/span&gt;&lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="o"&gt;-*&lt;/span&gt; &lt;span class="sr"&gt;/usr/&lt;/span&gt;&lt;span class="nb"&gt;local&lt;/span&gt;&lt;span class="sr"&gt;/sbin/o&lt;/span&gt;&lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="o"&gt;-*&lt;/span&gt;

&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;下载最新版本的mininet&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;git:&lt;/span&gt;&lt;span class="sr"&gt;//gi&lt;/span&gt;&lt;span class="n"&gt;thub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/mininet/mi&lt;/span&gt;&lt;span class="n"&gt;ninet&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后运行install.sh -options&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="sr"&gt;/util/&lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;安装的关键在options。查看详细的内容可以通过查看：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;而我们需要安装的是OpenFlow13和OpenvSwitch2.3.0,所以命令如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n3V&lt;/span&gt; &lt;span class="mf"&gt;2.3.0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;执行，安装成功！&lt;/p&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;再次感谢sdnap群@南京-小L的信息。不然我还要折腾一阵子。然后感兴趣的朋友可以去仔细看看./install.sh -h里面的内容，-y可以装ryu!!-x可以装nox！还是非常有用的！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 02 Nov 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-11-02:pages/2014/11/02/openvswitch230-and-mininet-install.html</guid><category>OVS</category><category>mininet</category></item><item><title>OpenVirteX：Operation and Subsystems</title><link>http://www.muzixing.com/pages/2014/10/28/openvirtexoperation-and-subsystems.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;继上篇&lt;a href="http://www.muzixing.com/pages/2014/10/23/openvirtexwen-dang-xiang-jie-overview-and-components.html"&gt;《OpenVirteX文档概述（一）：Overview and Components》&lt;/a&gt;之后，本篇将继续介绍OVX的Operation and Subsystems部分。主要讲述OVX内部的运作原理，本文属于个人简介，有误之处敬请指出，希望对读者有所帮助。本篇的顺序依然是按照官网文档的顺序介绍。&lt;/p&gt;
&lt;h2&gt;简介&lt;/h2&gt;
&lt;p&gt;本部分将介绍OVX内部的工作原理，如哪些内部子系统实现了哪一些功能，从而使得OVX能支持OpenFlow网络的虚拟化。以下的内容将分为如下的小点介绍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;System Overview&lt;/li&gt;
&lt;li&gt;Startup and Shutdown&lt;/li&gt;
&lt;li&gt;The Event Loops&lt;/li&gt;
&lt;li&gt;Network Discovery and Presentation&lt;/li&gt;
&lt;li&gt;Virtualization and De-virtualization&lt;/li&gt;
&lt;li&gt;State Synchronization&lt;/li&gt;
&lt;li&gt;Reslience&lt;/li&gt;
&lt;li&gt;persistence&lt;/li&gt;
&lt;li&gt;The JSONRPC API&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;System Overveiw&lt;/h2&gt;
&lt;p&gt;OVX分为以下几个主要的部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一半是面向南向物理基础设施的部分 ，管理了datapath到OVX之间的OpenFlow通道，并建立和维持了一系列数据结构，用于描述物理基础网络。&lt;/li&gt;
&lt;li&gt;另一半是面向北向租户控制器的部分，向租户控制器提供由OVXSwicth等组成的虚拟网络，并维护好OVX到各个租户控制器的OpenFlow通道。&lt;/li&gt;
&lt;li&gt;Global maps则保存了物理设施到OVXNetwork的component之间的映射关系，完成PhysicalNetwork到OVXNetwork之间的桥接路由（其实就是映射）。&lt;/li&gt;
&lt;li&gt;JSON的API用于配置和获取系统的信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Global mapping是在OVXNetwork被创建的时候完成的，两段channel的管理也在不同的IO Loop中完成配置，使得从datapath到tenant controller的两段OpenFlow channel 能够正确对接成一条完整的controller channel。每一个需要被路由到OVXNetwork，或者需要横跨南北两部分的数据包都要在loop中调用virtualize()或者devirtualize()函数以完成消息的转换。由于global map的存在，使得底层物理网络和租户的虚拟网络之间的状态可以解耦，从而使得OVXNetwork可以在运行状态下动态地改变网络，也让OVX可以在没有任何租户网络的情况下控制底层网络。&lt;/p&gt;
&lt;h2&gt;Startup and Shutdown&lt;/h2&gt;
&lt;p&gt;这部分将要介绍的是OVX启动和关闭时OVX内部的程序运作流程。分为以下4个小节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Main process startup&lt;/li&gt;
&lt;li&gt;PhysicalNetwork / Southbound channel initialization&lt;/li&gt;
&lt;li&gt;Tenant Network (OVXNetwork) / Northbound channel initialization&lt;/li&gt;
&lt;li&gt;System shutdown&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Main process startup&lt;/h3&gt;
&lt;p&gt;OVX的入口方法在&lt;strong&gt;OpenVirteX.java[package net.onrc.openvirtex.core]&lt;/strong&gt;文件,通过解析命令行的输入参数来启动OpenVirteXController,OpenVirteXController完成了OVX核心的启动，也完成了环境变量，OVX参数等系统配置和初始化。启动的内容包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初始化单一的PhysicalNetwork实例，用于描述底层物理网络。&lt;/li&gt;
&lt;li&gt;尝试连接数据库，恢复数据库中先前存在虚网。&lt;/li&gt;
&lt;li&gt;启动API服务，接受API调用。&lt;/li&gt;
&lt;li&gt;初始化南向的通道处理函数，监听网络事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第三步的时候，OVX监听API调用，第四步时，监听来自datapaths的连接。&lt;/p&gt;
&lt;h3&gt;PhysicalNetwork population / Southbound channel initialization&lt;/h3&gt;
&lt;p&gt;交换机连接到OVX以及链路发现的数据都记录到了PhysicalNetwork中。OVX为每一个交换机创建了一个PhysicalSwitch和SwitchDiscoveryManger的对象，用户描述交换机。此时OVX对于交换机而言，就是一个控制器。以下的图形象地描述了OVX在处理datapath连接时的状态变化。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/ClientFSM.png" /&gt;&lt;/p&gt;
&lt;p&gt;Fig.1:OVX的南向与datapath握手的状态机示意图&lt;/p&gt;
&lt;p&gt;如果对这个经典的OpenFlow协议的状态机不熟悉，可以参考&lt;a href="http://www.muzixing.com/pages/2013/12/12/yuan-chuang-openflowtong-xin-liu-cheng-jie-du.html"&gt;《OpenFlow通信流程解读》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SwitchChannelHandler [net.onrc.openvirtex.core.io]&lt;/strong&gt;将这个状态机设置成枚举类型的ChannelState,每一个状态都有对应的方法去处理当前状态下的事件和消息。&lt;/p&gt;
&lt;p&gt;当datapath达到WAIT_DESCRIPTION_STAT_REPLY之后，OVX才能将datapath映射成一个PhysicalSwitch。利用datapath提供的信息，OVX可以对datapath对应的PhysicaiSwitch进行配置，并将其加入到PhysicalNetwork中。当SwitchDiscoveryManager找到datapath的PhysicalNetwork，并且PhysicalSwitch的statisticsManager开启之后，datapath进入ACTIVE状态。当datapath进入ACTIVE状态时，datapath将参与到网络发现和OVX的事件循环当中，此时的datapath是一个正常运行状态的交换网桥。&lt;/p&gt;
&lt;h3&gt;Tenant network (OVXNetwork) / Northbound channel initialization&lt;/h3&gt;
&lt;p&gt;一个租户的网络的创建、配置和初始化都通过API的调用，其中步骤包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Declare an OVXNetwork, the Address block used, and tenant controller(s) to  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;connect the OVXNetwork to&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create OVXSwitches from available PhysicalSwitches&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add OVXPorts to the OVXSwitches&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add OVXLinks, Hosts, and for BVSes, SwitchRoutes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If manual, specify paths for OVXLinks and SwitchRoutes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Optionally, add backup paths for OVXLinks and SwitchRoutes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Initialize the OVXNetwork&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上的步骤完成之后，OVX需要将其components初始化，并将virtual components映射到PhysicalNetwork components，并记录在global map中。然后将虚拟的components状态置为ACTIVE,在这种非常具有强制依赖性的顺序之下，最终完成OVXNetwork的初始化。具体的API都写在了&lt;strong&gt;API server [net.onrc.openvirtex.api.server]&lt;/strong&gt;中，他们在&lt;strong&gt;tenant handlers [api.server.handlers.tenant]&lt;/strong&gt;中被调用。具体的接口函数此处不加赘述，读者可到官网查看，也可以直接查看源码。下图描述了OVX中tenant Network的创建过程：
&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/VnetInit.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;每一个Component都包含有register()和boot()的接口函数用于注册和初始化component。容易意识到的一点是，这些Component的启动肯定是有顺序的，或者说他们之间的以来关系肯定是固定的。如端口必然以来于交换机，没有交换机类，就不会有端口类。下图介绍了Components之间的包含和映射关系。其中实线为包含关系，虚线为映射关系。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/dependencies.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ControllerChannelHandler [net.onrc.openvirtex.core.io]&lt;/strong&gt;  负责OVXSwitch实例到tenant controller的连接，并维持一个状态机如下图所示。当且仅当一个OVXNetwork完成了所有OVXSwitch和控制器的连接时，才能进入ACTIVE状态。此时的OVX对于tenant Controller而言是一个datapath。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/ServerFSM.png" /&gt;&lt;/p&gt;
&lt;h3&gt;System shutdown&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;OpenVirtexShutdownHook [net.onrc.openvirtex.core.io]&lt;/strong&gt;调用 OpenVirteXController.terminate()方法完成系统的关闭。这个方法关闭了面向租户和面向datapath两端的channel，也注销了PhysicalNetwork。&lt;/p&gt;
&lt;h2&gt;The Event Loops&lt;/h2&gt;
&lt;p&gt;这部分将介绍OVX的I/O loop。&lt;/p&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;OVX event loop主要用于处理OpenFlow messages。主要完成如下三个功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;负责OVX与datapath、OVX和tenant controller的OpenFlow协议通信。&lt;/li&gt;
&lt;li&gt;完成OpenFlow messages的virtualize()和devirtualize():主要是将来自datapath的OpenFlow消息重写，路由到对应的租户控制器以及反向的消息转换。&lt;/li&gt;
&lt;li&gt;保持OVX和datapath、OVX和tenant controller的连接。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Message handling and (de)virtualization&lt;/h3&gt;
&lt;p&gt;OVXMessages部署了以下的两个接口中任意一个或者全部：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Virtualizable&lt;/strong&gt;: virtualize(PhysicalSwitch sw) : controller-bound messages&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Devirtualizable&lt;/strong&gt; : devirtualize(OVXSwitch sw) : network-bound messages&lt;/p&gt;
&lt;p&gt;这两个接口函数的参数都是switch类的子类。对于那些没有必要跨越virtual-physical gap的消息，就没有这些方法，如keep alive的消息（echo-request and echo-reply）。而那些需要从datapath一直交付到tenan controller的消息就必须要这写方法了，如flow_mod。&lt;/p&gt;
&lt;p&gt;这些方法在handleIO()调用。handleIO()是PhysicalSwitch和OVXSwitch类中abstract method。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;@Override&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;handleIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFMessage&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handleIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;当交换机处于ACTIVE状态时，才会被调用。&lt;/p&gt;
&lt;p&gt;PhysicalPhysicalSwitch.Switchstate.ACTIVE满足时，handleIO允许被调用。函数代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;handleIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PhysicalSwitch&lt;/span&gt; &lt;span class="n"&gt;psw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;OFMessage&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;Virtualizable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;virtualize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;ClassCastException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;psw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Received illegal message : &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;OVXSwitch.Switchstate.ACTIVE满足时，函数代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;handleIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OVXSwitch&lt;/span&gt; &lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;OFMessage&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;/*&lt;/span&gt;
     &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Save&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;came&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;
     &lt;span class="o"&gt;*/&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setXid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;channelMux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getXid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;/*&lt;/span&gt;
         &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Check&lt;/span&gt; &lt;span class="n"&gt;whether&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;permitted&lt;/span&gt;
         &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nb"&gt;send&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;dataplane&lt;/span&gt;
         &lt;span class="o"&gt;*/&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;roleMan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canSend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;Devirtualizable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;devirtualize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;denyAccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;roleMan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;ClassCastException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;OVXSwitch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Received illegal message : &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其整个event loop（事件循环）示意图如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/07/io_main-622x1024.png" /&gt;&lt;/p&gt;
&lt;p&gt;从上图中我们可以看到一些细节部分，比如来自租户的LLDP数据包是不会发送到datapath的。直接在OVX查询topology的数据结构就可以模拟出LLDP的效果了。同样OVX不断的在发送LLDP数据包，而packet_in数据类型而LLDP时，不会交给租户的控制器，而是由OVX的拓扑发现模块去处理，事实上，OVX就是一个控制器！只不过，它比控制器多出来虚拟化的功能，从而将网络的管理权，交给了各个租户的控制器而已。蓝色部分是面向租户的，橙色部分是面向datapath的，而中间的淡绿色部分是global部分。通过调用virtualize()和devirtualize()函数和使用global map数据完成消息的转换。&lt;/p&gt;
&lt;h3&gt;Network Discovery and Presentation&lt;/h3&gt;
&lt;p&gt;为了保证虚拟化的准确性，OVX必须保证获取到实时的网络试图，这就需要做以下的事情：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;探测拓扑和流表的变化&lt;/li&gt;
&lt;li&gt;将拓扑变化对应地修改到PhysicalNetwork和PhysicalSwitch数据结构中。&lt;/li&gt;
&lt;li&gt;检测拓扑变化是否对租户的虚网有影响，有则更新租户虚网拓扑信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这一部分需要注意的一个重点是，OVX对网络拓扑，特别是对虚网拓扑的处理。按常规思路，直接下发转发tenan controller的LLDP数据包，和上传LLDP的packet_in是最简单的。但是代价就是会增加OVX的IO压力，给网络增加过多的流量。优化方法就是由OVX代理获取物理拓扑，而对于租户的拓扑探测请求则直接通过查询OVX的拓扑信息返回，这样就可以使得来自租户控制器的大量LLDP数据包在OVX上就得到回复，从而模拟了拓扑发现过程。&lt;/p&gt;
&lt;h4&gt;Topology discovery/LLDP handling&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Physical LLDP handling&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;每一个PhysicalNetwork的SwitchDiscoveryManager负责处理LLDP消息。其处理流程如下图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/SDMgr-loop-1024x807.png" /&gt;&lt;/p&gt;
&lt;p&gt;根据每一个端口的探测计数器结果（默认为3），可以将端口分为fast和slow端口。其中fast端口为内部端口，即端口对端也是一个交换机端口，能回复LLDP数据包。否则就是slow端口，理论上slow端口为连接主机的端口。每一次发送一个探测包，探测计数器就加1，收到回复则减1，当计数器大于3时，可将端口定义为slow port，这些数据都存储在Map&lt;Short, AtomicInteger&gt; portProbeCount。&lt;/p&gt;
&lt;h4&gt;PhysicalSwitch Statistics Collection&lt;/h4&gt;
&lt;p&gt;在OVX中统计信息存储在如下的数据结构中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;AtomicReference&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Short&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OVXPortStatisticsReply&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;portStats&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;AtomicReference&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;flowStats&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;OVX通过&lt;strong&gt;StatisticsManager[net.onrc.openvirtex.elements.datapath.statistics]&lt;/strong&gt;来获取统计信息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Physical flow table synchronization&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OVX通过周期地发送statisticsRequest来收集网络的统计信息，并存储在PhysicalSwitch.flowStats之中。具体的实现可以查看&lt;strong&gt;StatisticsManager[net.onrc.openvirtex.elements.datapath.statistics]&lt;/strong&gt;等模块。&lt;/p&gt;
&lt;h3&gt;OVXNetwork Presentation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Virtual topology presentation&lt;/strong&gt;OVX通过查找OVX拓扑数据，来回复租户的拓扑发现请求，从而显著减少了LLDP消息在物理网络中的传播。其中步骤为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查找neighborPortMap表中destination port的数据&lt;/li&gt;
&lt;li&gt;将结果封装成LLDP报文的packet_in并发送给租户控制器。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下图介绍了这个处理流程。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/topology-resolution-1024x616.png" /&gt;&lt;/p&gt;
&lt;p&gt;OVX目前还没有做关于租户多控制器的实现。&lt;/p&gt;
&lt;h2&gt;Network Virtualization&lt;/h2&gt;
&lt;p&gt;本部分将介绍OVX的核心模块，网络虚拟化模块，主要完成virtual&amp;lt;---&amp;gt;physical之间的映射转换。主要完成源目地址的修改，接入端口的翻译，OF消息的翻译等内容。具体的实现将分为以下几部分介绍。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Switch Representation Translation&lt;/li&gt;
&lt;li&gt;OpenFlow field translation – Cookies, Buffer IDs, XIDs&lt;/li&gt;
&lt;li&gt;Address virtualization&lt;/li&gt;
&lt;li&gt;Link and Route virtualization&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Switch Representation Translation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OVXSwitch -&amp;gt; PhysicalSwitch (Southbound)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过拦截从tenant controller发向datapath的消息，以in_port为键值查找对应的PhysicalPort,从而找到对应的物理交换机，也可以通过tenant ID的方式查找OVXMap。具体实现，读者需要自行查看源码。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PhysicalSwitch -&amp;gt; OVXSwitch (Northbound)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;上行数据的查找可以直接通过MAC地址来查找，因为主机的MAC地址是唯一属于一个虚网的，所以可以作为key，用于查找tenantID，从而实现转换。也可以通过OpenFlow协议的消息字段，如xid，来找到某一个controller channel，而一个controller channel将对应一个租户的控制器。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;OpenFlow field translation – Cookies, Buffer IDs, XIDs&lt;/h3&gt;
&lt;p&gt;那些需要从datapath到租户控制器的OpenFlow消息都需要就行翻译。需要翻译的OpenFlow消息的字段包括cookies,buffer_id,xid等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;XIDTranslator.XID&lt;/strong&gt;需要在datapath上唯一，这个是OpenFlow协议的规定。而OVX在翻译消息的构成中，需要将来自datapath的xid以及生成的xid的键值对存储下来，以便在反向通信时，还原成原来的数据，保证通信的正确性。这个工作由XidTranslator.translate()完成，其中包括以下几个步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;generates a new XID&lt;/li&gt;
&lt;li&gt;creates an XidPair to store the original XID and source OVXSwitch&lt;/li&gt;
&lt;li&gt;stores the XidPair in xidMap, using the new XID as the key&lt;/li&gt;
&lt;li&gt;returns the new XID value to the caller&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;反向的处理则由XidTranslator.untranslate()负责。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OVXFlowTable&lt;/strong&gt;是以cookie为键值存储在OVX上的。而这个cookie的产生由generateCookie() 函数负责。每一个cookie的编码都有tenantID参与，保证在OVX上cookie的唯一性以及导向性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;long&lt;/span&gt; &lt;span class="n"&gt;generateCookie&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookieCounter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getAndIncrement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vswitch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTenantId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ow"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ow"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;bufferMap&lt;/strong&gt;在packet_in/packet_out数据中，他们共用一个buffer_id。在消息的转换过程中，需要将来自packet_in的buffer_id和生成的buffer_id存起来，当packet_out数据下发时，则需要查找，并转换。&lt;/p&gt;
&lt;h3&gt;Address virtualization&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;地址虚拟化是OVX中非常关键的部分&lt;/strong&gt;。为了允许用户使用任意的IP，OVX定义了OVXIPAddress用于描述用户定义的IP，这个IP地址在虚网内是唯一的。OVX还定义了PhysicalIPAddress,用于描述底层物理的IP地址，这个地址在物理网络中是唯一的。在数据层面的通信中，OVX需要将边源端口的入口流量重写IP地址成PhysicalIPAddress,还需要重写边源端口的出流量数据的IP，转换成OVXIPAddress,从而向租户展现一个使用了租户定义地址的通信流程。而中间的转发过程，也即在core datapath的转发过程中，一直都是使用PhysicalIPAddress的，且其转发等行为也由OVX直接完成了。&lt;/p&gt;
&lt;p&gt;为了完成这个工作，OVX将datapath分为两种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;core datapath:仅和datapath相连的内部datapath,没有host挂载。&lt;/li&gt;
&lt;li&gt;edge datapath:连接有host的datapath。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于edge datapath而言，OVX需要作如下两件事情：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于来自网络侧的流量，查询映射表，将PhysicalIPAddress重写成OVXIPAddress.&lt;/li&gt;
&lt;li&gt;对于来自主机测的流量，查询映射表，将OVXIPAddress重写成PhysicalIPAddress.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下图举例介绍了一个简单的通信流程：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/07/addr_virt.png" /&gt;&lt;/p&gt;
&lt;p&gt;图中蓝色部分为使用OVXIPAddress通信的部分，橙色部分为使用PhysicalIPAddress通信的部分。其中:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a为packet_in过程，直接发送给tenant controller;&lt;/li&gt;
&lt;li&gt;b是packet_out过程，b过程需要将OVXIPAddress重写成PhysicalIPAddress;&lt;/li&gt;
&lt;li&gt;c过程是core datapath的控制过程，直接由OVX完成，不需要上传给tenant controller，如果在虚妄中并没有这个交换机的存在的话。&lt;/li&gt;
&lt;li&gt;d过程是对端edge datapath的packet_in过程，上传到OVX上时，需要转换成OVXIPAddress,进行虚拟化转换，才能转发给tenant controller。&lt;/li&gt;
&lt;li&gt;e过程为packet_out过程，OVX需要将PhysicalIPAddress重写成OVXIPAddress。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Implementations&lt;/h4&gt;
&lt;p&gt;以下介绍哪一些消息需要转换。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PhysicalIPAddress -&amp;gt; OVXIPAddress:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OVXPacketIn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;OVXIPAddress -&amp;gt; PhysicalIPAddress:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OVXPacketOut&lt;/li&gt;
&lt;li&gt;OVXFlowMod&lt;/li&gt;
&lt;li&gt;OVXActionNetworkLayerSource/Destination&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下图片举例介绍了virtualize和devirtualize的流程：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/PacketIn.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PacketIn virtualization&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/PacketOut-1024x682.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PacketOut devirtualization&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/FlowMod-1024x863.png" /&gt;
&lt;strong&gt;FlowMod devirtualization&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Link and Route virtualization&lt;/h3&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2&gt;State Synchronization&lt;/h2&gt;
&lt;h3&gt;Error Escalation&lt;/h3&gt;
&lt;p&gt;OVX通过获取到网络的错误来同步PhysicalNetwork，如某一个port Down掉了，那么在PhysicalNetwork就应该更新其状态，并把与之对应的link down掉。这些状态变化依赖于PortStatus消息，这些消息的处理由&lt;strong&gt;OVXPortStatus [net.onrc.openvirtex.messages]&lt;/strong&gt;负责。&lt;/p&gt;
&lt;p&gt;OVX拥有错误消除的能力，能在一定范围内，隐藏底层网络中发生的错误事件，及时调整策略，保障租户的虚网正常运行。如一个BVS（Big Virtual Switch）中有一条链路发生故障，OVX可以重新映射一条没有人使用的备用链路，从而向租户隐藏错误。而对于普通的链路，OVX也可以将故障的OVXLink重新映射到冗余的链路上，保障网络的连通性。以下举例说明：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/err_ignore.png" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;左边的图中，b,c两点并没有映射到租户的虚网中，所以OVX完全向租户控制器隐藏了这些错误，当然租户的控制器才不关心这些不属于他的交换机到底什么状态。&lt;/li&gt;
&lt;li&gt;中间的图，a,d两点之间有多条path,当且仅当，所有的path都down掉，OVX才会通知租户控制器这一事件。&lt;/li&gt;
&lt;li&gt;右边的图中，当a到b的SwitchRoute都down掉时，才会向租户上报错误。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Flow Table State Synchronization&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;OVXFlowTable Synchronization&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;来自tenant controller的flow_mod在进行devirtualize()转换之前，需要存储在OVX上。tenant controller查看流表信息时，直接查看的就是存储在OVX上的流表信息。OVX始终为通过&lt;strong&gt;OVXFlowMods [net.onrc.openvirtex.messages]&lt;/strong&gt;来为OVXSwitch保存着一个实时更新的flow table。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;/* Within class OVXFlowMod */&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;devirtualize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;OVXSwitch&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;FlowTable&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getFlowTable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;long&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;OVXFlowTable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getCookie&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;Store&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;virtual&lt;/span&gt; &lt;span class="n"&gt;flowMod&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;obtain&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt;
    &lt;span class="n"&gt;ovxMatch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="sr"&gt;/* update sw&amp;#39;s OVXFlowTable */&lt;/span&gt;
    &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;pflag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handleFlowMods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;OVXFlowTable.handleFlowMods()&lt;/strong&gt;根据flow_mod的command类型来修改对应的流表项。&lt;/p&gt;
&lt;p&gt;在虚拟的流表被更新之后，OVX将把这个更新下发到datapath，实时修改datapath的流表。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Physical flow table synchronization&lt;/strong&gt; 
datapath的flow table信息被记录在PhysicalSwitch.flowStats数据结构中。每一个PhysicalSwitch实例中的&lt;strong&gt;StatisticsManager [net.onrc.openvirtex.elements.datapath.statistics]&lt;/strong&gt;负责周期地发送 OFFlowStatisticsRequests来获取统计数据，普遍的可以设置为30秒为刷新周期。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Synchronization between flow tables&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;physical flow table和virtual flow table的同步通过virtualize()函数和devirtualize()函数实现。具体代码实现如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;virtualize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;PhysicalSwitch&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sr"&gt;/* determine tenant from cookie */&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ow"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ow"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sr"&gt;/* find which OVXSwitch&amp;#39;s flowtable is affected */&lt;/span&gt;
        &lt;span class="n"&gt;OVXSwitch&lt;/span&gt; &lt;span class="n"&gt;vsw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getVirtualSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getFlowTable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasFlowMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;OVXFlowMod&lt;/span&gt; &lt;span class="n"&gt;fm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getFlowMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleteFlowMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="sr"&gt;/* send north ONLY if tenant controller wanted a FlowRemoved for the FlowMod*/&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFFlowMod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPFF_SEND_FLOW_REM&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;writeFields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;vsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendMsg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Resilience&lt;/h2&gt;
&lt;p&gt;网络中的网元肯定是会有down掉的时候的。为了减少这些底层设施的failures影响到租户的网络，OVX采用了冗余映射的方式，解决这一问题，主要包括以下的方面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;OVXLinks : multiple paths&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SwitchRoute : multiple paths&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OVXBigSwitch : multiple SwitchRoutes, sets of PhysicalSwitches, or SwitchRoutes with multiple paths&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当某一个冗余映射的component发生故障时，他就可以通过调用&lt;strong&gt;Resilient[net.onrc.openvirtex.elements]&lt;/strong&gt;接口完成故障恢复。这个接口提供了以下连个方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;public boolean tryRecovery(Component c) : Given the failure of c, attempt to switch over to any backup mappings, if possible&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;public boolean tryRevert(Component c) : Given the resumed function of c, attempt to switch back to the original (favored) mapping&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下将两个过程介绍了link故障和linkh恢复的过程。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/tryRecovery.png" /&gt;&lt;/p&gt;
&lt;p&gt;从上图可以看出，当physical link failed时,OVX将在查找他的备份链路，试图重新映射，并把以前的流表导入到新的link相关的switch中，同时还需要将failed的link加入到broken set，将重新映射的link从backup list中删除。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/tryRevert.png" /&gt;&lt;/p&gt;
&lt;p&gt;上图介绍了链路恢复的过程。当之前failed的link重新恢复之后，OVX将自动尝试将映射恢复到原来的链路上，这包括流表的倒换等操作。这时需要注意的是链路的优先级问题，假设原先的链路具有最高优先级，这能让问题变得简单一些。&lt;/p&gt;
&lt;h2&gt;Persistence&lt;/h2&gt;
&lt;p&gt;本部分将介绍OVX中关于配置持续性的描述。OVX使用数据库存储用户的配置信息，并实时更新信息。当OVX重启时，能通过读取用户信息，迅速恢复租户的虚网。不仅仅包括虚网的拓扑，还包括所有的ID(tenantID, DPID等等)&lt;/p&gt;
&lt;h3&gt;Configuration Parameters&lt;/h3&gt;
&lt;table class="table-bordered table-striped table-condensed"&gt;
&lt;tr&gt;
    &lt;td&gt;&lt;b&gt;Option&lt;/b&gt;&lt;/td&gt;
    &lt;td&gt;&lt;b&gt;Argument&lt;/b&gt;&lt;/td&gt;
    &lt;td&gt;&lt;b&gt;Comments&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;-dh or –db-host&lt;/td&gt;
    &lt;td&gt;hostname&lt;/td&gt;
    &lt;td&gt;default: "127.0.0.1"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;-dp or –db-port&lt;/td&gt;
    &lt;td&gt;port&lt;/td&gt;
    &lt;td&gt;default:27017&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;值得注意的是，当虚网没有提前进行配置时，会出现以下的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If OVX can’t connect to the database: Currently, this generates error messages in the log. These messages won’t interfere with the regular operation of OVX.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using the option “–db-clear”: All persistence data is deleted from storage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Related Packages and Classes&lt;/h3&gt;
&lt;p&gt;由于笔者对数据库不了解，所以这部分不做详细介绍，详情读者可以到官网查看文档。&lt;/p&gt;
&lt;h4&gt;class DBManager&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Fields&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;static&lt;/span&gt; &lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;DB_CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;CONFIG&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;static&lt;/span&gt; &lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;DB_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;USER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;static&lt;/span&gt; &lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;DB_VNET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;VNET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;DBConnection&lt;/span&gt; &lt;span class="n"&gt;dbConnection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DBCollection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt; &lt;span class="n"&gt;between&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;dpids&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;vnet&lt;/span&gt; &lt;span class="n"&gt;managers&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;OVXNetworkManager&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dpidToMngr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt; &lt;span class="n"&gt;between&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;vnet&lt;/span&gt; &lt;span class="n"&gt;managers&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DPIDandPortPair&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;OVXNetworkManager&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;linkToMngr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt; &lt;span class="n"&gt;between&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;ports&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;vnet&lt;/span&gt; &lt;span class="n"&gt;managers&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DPIDandPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;OVXNetworkManager&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;portToMngr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Methods&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Initialize&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Create&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;persistable&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;createDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Persistable&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Remove&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;removeDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Persistable&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Save&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;specified&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Persistable&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Remove&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;specified&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Persistable&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Reads&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;virtual&lt;/span&gt; &lt;span class="n"&gt;networks&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;spawn&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;OVXNetworkManager&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;each&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;readOVXNetworks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Reads&lt;/span&gt; &lt;span class="n"&gt;virtual&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;maps&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;registers&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;their&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;readOVXSwitches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;switches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;OVXNetworkManager&lt;/span&gt; &lt;span class="n"&gt;mngr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;readOVXLinks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;OVXNetworkManager&lt;/span&gt; &lt;span class="n"&gt;mngr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;readOVXPorts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;OVXNetworkManager&lt;/span&gt; &lt;span class="n"&gt;mngr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;readOVXRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;OVXNetworkManager&lt;/span&gt; &lt;span class="n"&gt;mngr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;class OVXNetworkManager&lt;/h4&gt;
&lt;p&gt;OVXNetworkManager负责从数据库中恢复租户的虚网。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Field&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;virtual&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vnet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;offline&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;online&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;switches&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;Long&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;offlineSwitches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;Long&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;onlineSwitches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;offline&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;online&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="n"&gt;identified&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;DPIDandPortPair&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;offlineLinks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;DPIDandPortPair&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;onlineLinks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;offline&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;online&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;ports&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;DPIDandPort&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;offlinePorts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;DPIDandPort&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;onlinePorts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;bootState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Methods&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Register&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;offline&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;registerSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;registerLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DPIDandPortPair&lt;/span&gt; &lt;span class="n"&gt;dpp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;registerPort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DPIDandPort&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Delete&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;offline&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;online&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;physical&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;online&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;virtual&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;synchronized&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;setSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;synchronized&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;unsetSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;synchronized&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;setLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DPIDandPortPair&lt;/span&gt; &lt;span class="n"&gt;dpp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Storing Configurations&lt;/h4&gt;
&lt;p&gt;当虚网的component初始化之后，他们的信息将以文档的形式存入数据库。目前需要存在数据库中的component的如下所示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OVXNetwork&lt;/li&gt;
&lt;li&gt;OVXSingleSwitch&lt;/li&gt;
&lt;li&gt;OVXBigSwitch&lt;/li&gt;
&lt;li&gt;OVXPort&lt;/li&gt;
&lt;li&gt;OVXLink&lt;/li&gt;
&lt;li&gt;SwitchRoute&lt;/li&gt;
&lt;li&gt;Host&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Mechanism&lt;/h4&gt;
&lt;p&gt;当component初始化时，需要调用register()方法。在这个方法中，会调用DBManager.save()方法，用于将信息存储到数据库，其中包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gets target collection by getDBName() e.g. “VNET”&lt;/li&gt;
&lt;li&gt;Gets query index by getDBIndex() e.g. { “tenantId”:1 }&lt;/li&gt;
&lt;li&gt;Gets key by getDBKey() and value by getDBObject() e.g. key is “switches”, value is { “dpids”:[4], “vdpid”:400 }&lt;/li&gt;
&lt;li&gt;Adds (updates) this value into the list of this key by using MongoDB’s $addToSet operator. If the initial set is {“switches”:[{“dpids”:[1], “vdpid”:100}]}, this becomes {“switches”:[{“dpids”:[1], “vdpid”:100}, {“dpids”:[4], “vdpid”:400}]}&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Persistible Components&lt;/h4&gt;
&lt;p&gt;OVXSwitch subclasses (OVXSingleSwitch, OVXBigSwitch), OVXLink, SwitchRoute, OVXPort and Host等class都具有persistible属性，都会将信息存储在数据库中。&lt;/p&gt;
&lt;h4&gt;Updating (Deleting) Configurations&lt;/h4&gt;
&lt;p&gt;当component发生更新时，OVX会创建新对象去描述这个新的component，同时也要把这些新数据存到数据库中。但是这个过程对于全部的component来说并不是统一的，分为以下两种情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OVXNetworks&lt;/strong&gt; : DBManager.removeDoc() deletes a document of the specified virtual network. This method is called by OVXNetwork.unregister().&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Other Elements&lt;/strong&gt; : DBManager.remove() deletes an element in the list of the value for specified key by the $pull operation of MongoDB. This method is called by component inactivation methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;unregisterDP() – OVXSwitch&lt;/li&gt;
&lt;li&gt;unregister() – OVXPort, OVXLink, SwitchRoute, OVXHost&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Restoring Configurations&lt;/h4&gt;
&lt;p&gt;当boot完成的时候，physical component是处于在offline状态的。OVX将去查询在offline list中的component是否还是offline，当OVX发现某一个physical element(物理网元)处于活跃状态时，将为其创建对应的physical component。当全部的physical element都处于active时，OVX将试图从数据库中恢复OVXNetwork&lt;/p&gt;
&lt;h2&gt;后语&lt;/h2&gt;
&lt;p&gt;原本我想写的是OVX的文档详解，但是目前看来好像写成了文档翻译。因为确实我对于OVX只是通过文档了解到了一些皮毛，没有更深的理解，写出来的文章缺乏主观的观点。这种问题在很久以前我已经意识到。我自己目前陷入一种非常尴尬的状态，对新知识渴望，但是却了解甚少。所以以后的时间可能需要专心读书，沉下心来好好学术。博客已经开了快一年了，但是一直以来写的都是偏工程的教程和代码详解等文章，其学术意义不大。现在也成为一个研究生了，还没有找到一个合适的节奏，希望在以下的学习生活中，能脚踏实地，加强点核心竞争力吧。谢谢浏览本博客的所有人！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 28 Oct 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-10-28:pages/2014/10/28/openvirtexoperation-and-subsystems.html</guid><category>network virtualization</category></item><item><title>OpenVirteX文档详解（一）——Overview and Components</title><link>http://www.muzixing.com/pages/2014/10/23/openvirtexwen-dang-xiang-jie-overview-and-components.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;本篇博文将按照OpenVirteX Documentation的顺序详细介绍OpenVirteX的相关内容。完整翻译版，请查看@北邮-张歌 翻译的文章。转载请声明出处。&lt;/p&gt;
&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;OpenVirteX(以下简称OVX)是onlab开发的一个网络虚拟化平台，可以实现多租户的网络虚拟化。对于租户而言，需要在OVX上注册，申请资源，配置自己的网络，指定自己的控制器。剩下的工作就由OVX完成了。OVX可以根据租户的需求，将租户的网络拓扑映射到具体的物理拓扑上，完成网络的联通。对于租户而言，看到的是一个虚拟的网络，无法看到真实的物理拓扑，也不需要关心，即租户“认为”得到了一个属于自己的真实网络。而OVX的位置相当于一个介于租户控制器和交换机之间的转换平台。面对租户，OVX就是一个物理的网络，而面对交换机，OVX就是控制器。（这种转换平台的角色可以实现很多功能，不仅仅是网络虚拟化，还可以模拟许多信息，比如在某个项目中我们将OVS模拟成一个OTN的交换机，验证了一些想法）&lt;/p&gt;
&lt;h3&gt;网络虚拟化&lt;/h3&gt;
&lt;p&gt;网络虚拟化允许多租户占用同一个网络基础设施，同时允许租户对其网络的控制能力，对于租户而言，感觉上是自己控制了整个网络。OVX通过使租户能够获取到自己的虚拟拓扑和全网的地址空间来实现网络虚拟化。前者可以允许租户自定义网络拓扑，后者则是用于隔离不同租户的流量，防止冲突。&lt;/p&gt;
&lt;p&gt;与flowspace的切分slice，使租户使用网络的一部分不一样的是，OVX通过同一个header space来区分所有租户的数据。举个例子就是：两个用户可以设置同样的IP，子网掩码，相同的TCP/UDP端口号，而不会引起冲突，这在flowspace理论下是不能成立的。其根本的区别在于OVX做了地址虚拟化，即面向用户的地址是OVXIPAddress，而真正在core datapath中使用的地址其实还是PhysicalIPAddress，只是在edge port的地方，OVX需要做一个translation，把地址把OVXIPAddress的地址映射成唯一的PhysicalIPAddress,而在core datapath的数据转发过程中，其实数据一直是有OVX来处理，而不需要转发到tenant的controller，从而实现了地址虚拟化。这一部分是OVX最重要最核心的部分，我将在后续的部分中详细介绍。&lt;/p&gt;
&lt;p&gt;与切分slice原理不一样的另一点是，以前切分的slice限制在底层网络的同构子图中，即用户的虚拟拓扑实际上是物理真实拓扑的一个同构子图，也就是说，租户是可以看到真实的网络拓扑的。而在OVX中不一样的是，用户不需要关心底层的拓扑，而可以任意的定义自己的虚网拓扑，OVX会完成虚网拓扑到物理网络拓扑的映射，这是OVX区别于FlowVisor的重要特性。&lt;/p&gt;
&lt;p&gt;OVX作为一个翻译者（代理），存在于租户的控制器和底层网络之间。对于租户而言，OVX通过修改、重写OpenFlow报文来实现租户控制器与租户租用的物理网元之间的通信。这种方法使得OVX具有以下两种能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;提供支持OpenFlow的可编程虚拟网络，从而使得租户可以指定自己的控制器来控制器网络。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OVX是透明的，对于租户而言，OVX是一个底层网络，而对于底层网络而言，OVX是一个控制器。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;值得注意的一点是，整个OVX的虚拟化过程中都是基于主机只属于一个虚网的假设的。主机地址的虚拟化是整个网络虚拟化的核心，同时主机的硬件地址是用来区分租户的流量的关键。下图说明了基于OVX的网络虚拟化。&lt;/p&gt;
&lt;p&gt;&lt;img alt="OVX" src="http://ovx.onlab.us/wp-content/uploads/2014/04/Figure1-1.png" /&gt;&lt;/p&gt;
&lt;h3&gt;OpenVirteX:更高级的网络视图&lt;/h3&gt;
&lt;p&gt;OVX不仅拥有底层物理网络拓扑，而且还有每个租户的虚拟网络拓扑。底层的物理网络拓扑是通过OVX下发LLDP报文获取到的，而上层的虚拟网络拓扑则是由OVX生成的。即租户的控制器下发的LLDP报文不会直接送到底层物理网络，而是在OVX上通过查询底层物理拓扑，从而模拟了LLDP的过程，向上提供网络拓扑。&lt;/p&gt;
&lt;p&gt;OVX通过映射算法，解耦了底层网络和租户网络。即南向上，OVX作为控制器，接收底层物理设备的信息，并下发流表等报文到底层设备。北向上，OVX作为交换机集合，向租户的控制器发送OF报文。从而将一条完整的控制通路，变成了两段相互独立的控制通路。而这两者之间的映射关系，保存在Global Map中。在下图中，蓝色部分是面向租户的，而橙色部分是面向交换机的。两者之间互不可见，即租户看不到物理的交换机数据。而绿色部分是两者结合的纽带，保存了网络映射的数据。在数据上行、下行的过程中通过查表修改的方式，翻译成正确的数据。如下图右侧所示，上行数据需要调用virtualize()函数，而下行数据需要调用devirtualize()函数。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/Figure1-2.png" /&gt;&lt;/p&gt;
&lt;h2&gt;Components&lt;/h2&gt;
&lt;p&gt;接下来的部分将分成以下的小节分析，顺序和官网的文档一样。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Overview&lt;/li&gt;
&lt;li&gt;Component State Machines&lt;/li&gt;
&lt;li&gt;Component Persistence&lt;/li&gt;
&lt;li&gt;Switches&lt;/li&gt;
&lt;li&gt;Ports&lt;/li&gt;
&lt;li&gt;Links and Routes&lt;/li&gt;
&lt;li&gt;Addresses&lt;/li&gt;
&lt;li&gt;Hosts&lt;/li&gt;
&lt;li&gt;Network Topologies&lt;/li&gt;
&lt;li&gt;Shared Global Mappings&lt;/li&gt;
&lt;li&gt;Messages&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;在OVX中，无论物理的还是虚拟的网络，都是由交换机，端口，链路等基础的对象组成的。对于租户而言，他们面对的虚拟的交换机，本质上和真实的交换机没有差别。全局映射表（Global map）描述了虚拟交换机和物理交换机之间的n:1的映射关系，在这里的映射实现上是OVXSwitch和PhysicalSwitch之间的映射，本质上是租户测看到的虚拟交换机和真实物理交换机之间的映射。n:1映射给交换机复用提供了条件，从而使得不同的租户的交换机可以映射到同一台真实的物理交换机。&lt;/p&gt;
&lt;p&gt;以下是OVX中的一些主要的Class的说明。&lt;/p&gt;
&lt;table class="table-bordered table-striped table-condensed"&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;Base Class&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Representation&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Network&lt;/td&gt;
        &lt;td&gt;The full topology &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Switch&lt;/td&gt;
        &lt;td&gt;A switch &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Port&lt;/td&gt;
        &lt;td&gt;A port on switch&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Link&lt;/td&gt;
        &lt;td&gt;A connection between two ports&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Host&lt;/td&gt;
        &lt;td&gt;A network host&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;IPAddress&lt;/td&gt;
        &lt;td&gt;An IP Address &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;接下来是继承这些类的子类的一些情况介绍。&lt;/p&gt;
&lt;table class="table-bordered table-striped table-condensed"&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;Base Class&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Physical Component Class&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Virtual Component Class(es)&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Network&lt;/td&gt;
        &lt;td&gt;PhysicalNetwork&lt;/td&gt;
        &lt;td&gt;OVXNetwork&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Switch&lt;/td&gt;
        &lt;td&gt;PhysicalSwitch&lt;/td&gt;
        &lt;td&gt;OVXSwitch&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Port&lt;/td&gt;
        &lt;td&gt;PhysicalPort&lt;/td&gt;
        &lt;td&gt;OVXPort&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Link&lt;/td&gt;
        &lt;td&gt;PhysicalLink&lt;/td&gt;
        &lt;td&gt;OVXLink, SwitchRoute&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Host&lt;/td&gt;
        &lt;td&gt;--&lt;/td&gt;
        &lt;td&gt;Host&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;IPAddress&lt;/td&gt;
        &lt;td&gt;PhysicalIPAddress&lt;/td&gt;
        &lt;td&gt;OVXIPAddress&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;举例说明，PhysicalSwicth是底层交换机对应的对象，而租户中的交换机则对应的是OVXSwitch。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;特别需要注意的是Host只有在租户中才有定义。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OVX通过对这些类进行实例化的方式去创建一个网络。可以有实例化交换机或者端口等类的过程去触发PhysicalNetwork的实例化，因为任何一个交换机或者交换机上的端口都应该属于某一个网络。即这些类的以来关系是Link依赖Port，Port依赖Switch,Switch依赖Network,显而易见的，这是真实网络中的依赖关系。&lt;/p&gt;
&lt;h3&gt;Component State Machines&lt;/h3&gt;
&lt;p&gt;容易想象，每一个交换机，端口等都应该有某些状态，如端口的Down，Up等等。而且不同的网元之间的状态是有一定关系的。比如交换机down掉之后，它的所有端口以及连接到它上面的link都会Down掉，这一点非常容易理解。&lt;/p&gt;
&lt;p&gt;为了让OVX能够跟踪和描述不同网元的状态变化的相互关系，我们定义了一个有限状态机（Finite State Machines）来描述这些状态逻辑。&lt;/p&gt;
&lt;h4&gt;基本的状态&lt;/h4&gt;
&lt;p&gt;除去Address和OVXSingleSwitch和OVXBigSwitch以外，其他的component（switch，port，link e.g.）都有如下几个简单的状态：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;INIT:只是创建了一个实例的时候，仅仅是实例化了一个Object&lt;/li&gt;
&lt;li&gt;INACTIVE：将实例通过映射算法，存储到数据库中。实现初步的初始化状态，等待握手。&lt;/li&gt;
&lt;li&gt;ACTIVE：正常的运行状态&lt;/li&gt;
&lt;li&gt;STOPPED：销毁了Object。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Component FSM Interface&lt;/h4&gt;
&lt;p&gt;FSM的转换需要一些接口函数来触发，具体如下图所示,函数的功能介绍也很简单，我直接把官网的原文摘抄了过来。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/Figure2-1.png" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;register() [INIT -&amp;gt; INACTIVE] : add component to mappings and storage, checking that dependencies are met (Example: A new port may not be created if a switch doesn’t exist)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;boot() [INACTIVE -&amp;gt; ACTIVE] : open control channels, activate dependent components (Example: bring a link up if the ports on both end are boot()ed)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;teardown() [ACTIVE -&amp;gt; INACTIVE] : close control channels, deactivate dependent components (Example: If a port is torn down, links to/from it are also torn down)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;unregister() [INACTIVE -&amp;gt; STOPPED] : remove from mappings and storage, deactivating or unregistering dependent components as necessary (Example: A link will no longer exist, so must be unregister()ed if either one or both ports it connects is unregister()ed)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从图中我们也可以看出，在这个FSM中，并不是所有的状态都可以相互转换的。比如只有在INACTIVE状态才能通过调用boot()函数来将状态转换成ACTIVE,而不能直接从INIT状态转换成ACTIVE，显然这是非常合理的。&lt;/p&gt;
&lt;h3&gt;Component Persistence&lt;/h3&gt;
&lt;p&gt;租户希望即使OVX重启或者升级之类的，租户的信息以及网络的状态都可以恢复，保持。在OVX中确实也有这方面的功能:OVX通过存储用户的配置信息来完成租户网络的重建。这样就可以保证即使OVX down掉，也没有关系，只要数据库没有损坏就可以恢复了。具体的接口这里不在赘述，详情可以直接查看官网：http://ovx.onlab.us/documentation/architecture/components/&lt;/p&gt;
&lt;h3&gt;Switches&lt;/h3&gt;
&lt;p&gt;一个Switch类是一个datapath的描述，包含了端口的信息和它的DPID，以及他的features，正如features_reply中的信息一样，当然还有某些其他成员，如isConnected,具体的Switch类的成员变量如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;isConnected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt; &lt;span class="n"&gt;liveness&lt;/span&gt; &lt;span class="n"&gt;indication&lt;/span&gt;
&lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;OVXDescriptionStatistics&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Switch&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Short&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;portMap&lt;/span&gt;             &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;ports&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keyed&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
&lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;OFFeaturesReply&lt;/span&gt; &lt;span class="n"&gt;featuresReply&lt;/span&gt;         &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;Features&lt;/span&gt; &lt;span class="n"&gt;Reply&lt;/span&gt;
&lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;switchId&lt;/span&gt;                         &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;DPID&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;switch&lt;/span&gt;
&lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;                       &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;control&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;继承了Switch基类的子类PhysicalSwitch和OVXSwitch在整个OpenFlow Channel中扮演非常重要的重要。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PhysicalSwitch类是用于描述物理交换机的类。&lt;/li&gt;
&lt;li&gt;OVXSwitch是描述了面向租户的交换机实体。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PhysicalSwitch作为南向控制通道的终点，用户保存物理交换机的信息；OVXSwitch作为北向控制通路的起点，向租户控制器发送数据，进行通信。其两者的映射关系，以及消息的转发规则都记录在Global Map中。&lt;/p&gt;
&lt;p&gt;而OVXSwitch作为基类，还派生了两个子类:OVXSingleSwitch和OVXBigSwitch&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OVXSingleSwitch: map to a single switch&lt;/li&gt;
&lt;li&gt;OVXBigSwitch: map to multiple swtiches&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OVXBigSwitch(BVS)映射成多个交换机，同时这些交换机之间的连接，可以等同于一个大交换机内部的交换网络，所以BVS需要保存这些内部交换网络的流表，也即需要保存多个交换机内部连接的流表，详情如下图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/Figure2-2.png" /&gt;&lt;/p&gt;
&lt;h3&gt;Ports&lt;/h3&gt;
&lt;p&gt;Port基类存储于交换机的PortMap表中。和网络中真实网络一致，OVX定义的Port以is_edge位标示端口是否属于边源端口。&lt;/p&gt;
&lt;p&gt;Ports基类同样也派生了两个子类:PhysicalPort和OVXPort&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PyhsicalPort:描述了底层物理交换机的端口，拥有ovxPortMap表，在up stream的转化过程中需通过此表来找到对应的OVXPort.&lt;/li&gt;
&lt;li&gt;OVXPort:描述了OVXSwitch的端口，包含有重要的tenantId字段和对应的物理Port记录。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Links and Routes&lt;/h3&gt;
&lt;p&gt;同样的Link基类也派生两个子类：PhysicalLink和OVXLink。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PhysicalLink：1:1记录了底层网络的信息。包含了linkId等关键字段。&lt;/li&gt;
&lt;li&gt;OVXLink: 是面向租户的数据结构，描述了租户网络中的Link。拥有tenantId等关键字段。&lt;/li&gt;
&lt;li&gt;SwitchRoute：当映射的两个交换机之间的物理链路不止一段时，OVX需要将中间节点的流表等信息保存起来，在保证物理网络连通的情况下，向用户展现只有一跳的链路。另一方面，多个交换机组成一个大的交换机的情况也是如此。举例请看下图。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/Figure2-3.png" /&gt;&lt;/p&gt;
&lt;p&gt;(摘自官网原文)&lt;/p&gt;
&lt;p&gt;Top) Two PhysicalLinks connecting PhysicalPorts (white circles) on three PhysicalSwitches (ps1, ps2, and ps3). Middle) An OVXLink connects two OVXSwitches (vs1, vs2) by their OVXPorts (black circles). vs1 and vs2 map to ps1 and ps3, respectively. The OVXLink maps over two PhysicalLinks, but appears as a single hop to a tenant, to which ps2 is invisible. Bottom) A SwitchRoute internally connects two OVXPorts on the same BVS. A SwitchRoute has an external (OVXPort) and internal (PhysicalPort) endpoints.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ovx.onlab.us/wp-content/uploads/2014/04/Figure2-4.png" /&gt;&lt;/p&gt;
&lt;p&gt;（摘自官网原文）&lt;/p&gt;
&lt;p&gt;various Links with respect to the network mappings. On the top are two tenants, and bottom, OVX’s network view (PhysicalNetwork). Note, there is only one PhysicalNetwork instance but we show two for clarity. Right) Tenant 1 has two OVXLinks, vlink1 and vlink2. Vlink1 corresponds to the path ps1-ps3-ps2 across PhysicalLinks l2 and l3, whereas vlink2 is a 1:1 mapping onto l5. Left) Tenant 2 contains both OVXLinks (red) and a SwitchRoute joining the ports in the OVXBigSwitch vs2, the latter mapped to l3 (blue).&lt;/p&gt;
&lt;h3&gt;Address&lt;/h3&gt;
&lt;p&gt;与其他部分一样，同样分为PhysicalIPAddress和OVXIPAddress两个子类。但是OVX最核心的部分也是最复杂的部分就是地址的虚拟化！将在后续章节进行详细描述。&lt;/p&gt;
&lt;h3&gt;Hosts&lt;/h3&gt;
&lt;p&gt;Host类相对其他类要特殊一些，因为他只有并没有派生成其他子类。因为OVX并没有对Host进行虚拟化，而且也没有必要对Host进行虚拟化。Host类中的Mac地址是区分不同租户的关键标识。通过不同的Host硬件地址，判断属于不同的虚网，且必须遵循每一个Host只属于一个虚网的假设，否则在添加tenantId时会产生冲突，从而无法产生唯一对应的tenantId，影响到流量隔离的功能。所以整个OVX的虚拟化的根基都是基于物理地址全网唯一，而对不同的Host打tenanId来实现虚网隔离，或者流量隔离的。&lt;/p&gt;
&lt;p&gt;租户可以任意设置Host的IP，但是OVX必须将这些可能和其他租户地址冲突的虚拟IP地址转化成底层物理网络中唯一的IP地址，然后流量在core datapath中将使用PhysicalIPAddress进行交换与路由，其处理逻辑都由OVX完成，而不需要上交tenant的控制器。只有在边缘端口处才会通过重写IP的方式，将数据的IP换成租户定义的IP，从而实现网络的通信。这一点应该得到重视，这是OVX虚拟化的核心部分。&lt;/p&gt;
&lt;h3&gt;Networks&lt;/h3&gt;
&lt;p&gt;Network基类，包含了switchSet，linkSet等成员，储存了整个网络的信息。同时和其他的基类一样，也会派生两个子类：PhysicalNetwork和OVXNetwork&lt;/p&gt;
&lt;p&gt;PhysicalNetwork是1:1与底层基础设施对应的，并保存了真实的网络数据，包括交换机，端口，链路和网元状态等。&lt;/p&gt;
&lt;p&gt;OVXNetwork面向租户描述了网络的状况。OVX为每一个租户维持了一个OVXNetwork的类，并通过唯一的tenantId来映射到底层的网络设施。同时这个唯一的tenantId将出现在OVXNetwork中所有的交换机，端口以及链路等数据结构中，从而使得OVX能够根据这个ID来识别OpenFlow消息的正确翻译和转发。&lt;/p&gt;
&lt;h3&gt;Shared Global Mappings&lt;/h3&gt;
&lt;p&gt;OVX保存着物理网络和租户网络之间的映射关系表，其存储在全局共享的OVXMap的结构中。其包含的Map表如下所示：&lt;/p&gt;
&lt;table class="table-bordered table-striped table-condensed"&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;HashMap&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Key&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Values&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;virtualSwitchMap&lt;/td&gt;
        &lt;td&gt;OVXSwitch&lt;/td&gt;
        &lt;td&gt;PhysicalSwitches&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;physicalSwitchMap&lt;/td&gt;
        &lt;td&gt;PhysicalSwitch&lt;/td&gt;
        &lt;td&gt;Map(TenantID,OVXSwitch)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;virtualLinkMap&lt;/td&gt;
        &lt;td&gt;PhysicalLink&lt;/td&gt;
        &lt;td&gt;Map(TenantID,OVXLink)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;routetoLinkMap&lt;/td&gt;
        &lt;td&gt;SwitchRoute&lt;/td&gt;
        &lt;td&gt;PhysicalLinks&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;phyLinktoRouteMap&lt;/td&gt;
        &lt;td&gt;PhysicalLink&lt;/td&gt;
        &lt;td&gt;SwitchRoutes using PhysicalLink, keyed on TenantID&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;networkMap&lt;/td&gt;
        &lt;td&gt;TenantID&lt;/td&gt;
        &lt;td&gt;OVXNetwork&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;physicalIPMap&lt;/td&gt;
        &lt;td&gt;PhysicalIPAddress (as String)&lt;/td&gt;
        &lt;td&gt;OVXIPAddress&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;virtualIPMap&lt;/td&gt;
        &lt;td&gt;OVXIPAddress&lt;/td&gt;
        &lt;td&gt;PhysicalIPAddress&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;macMap&lt;/td&gt;
        &lt;td&gt;MACAddress (as String)&lt;/td&gt;
        &lt;td&gt;Tenant ID as integral value&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;h3&gt;Messages&lt;/h3&gt;
&lt;p&gt;面向租户的的数据流量需要隔离，同样的，交换机到租户控制器的OpenFlow消息也需要隔离。在这个过程中，OVX扮演着中继或者代理角色。接收交换机的消息，并保存到对应的OF的数据结构中，然后将对应字段做映射，如xid,保证上行的OF消息能准确地送到正确的租户控制器，也需要保证接受到的多个租户控制器的消息能够反向翻译成下行正确的数据，发送给对应的交换机。从而实现OF信道的完整性和隔离性。转换之后的消息保存在OVX开头的数据结构中，与OF开头的消息数据结构相对应。在这个转换的过程中使用到了两个接口函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Virtualizable(): 处理来自底层datapath到tenant controller的消息，判定消息发送到哪一个租户控制器等功能。&lt;/li&gt;
&lt;li&gt;Devirtualizable()： 处理从租户控制器下发到底层datapath的消息，并将由OVXSwitch里的消息正确映射到PhysicalSwitch,从而完成下行信令的发送。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;以上部分是我对OVX的理解，当然逻辑顺序是按照官网的内容顺序写下来的。如有错误指出，希望您能给我宝贵意见！后续的还有一片专门讲内部如何实现的，对应官网文档第三部分。另外，我的小伙伴@北邮-张歌完成了这些官网文档的翻译，阅读可到：www.sdnlab.com&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 23 Oct 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-10-23:pages/2014/10/23/openvirtexwen-dang-xiang-jie-overview-and-components.html</guid><category>Network Virtualization</category></item><item><title>基于SDN的RYU应用——ARP_PROXY</title><link>http://www.muzixing.com/pages/2014/10/19/ji-yu-sdnde-ryuying-yong-arp_proxy.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;在传统网络中，存在着一定的广播流量，占据了一部分的网络带宽。同时，在有环的拓扑中，如果不运行某些协议，广播数据还会引起网络风暴，使网络瘫痪。传统的解决方案是运行STP（生成树协议），来解决环路带来的风暴隐患。但是这样的难题在SDN之后，解决起来似乎变得要简单一些。本文将介绍如何在控制器RYU上开发ARP代理模块，用于代理回复ARP请求，以及解决环状拓扑风暴的问题。&lt;/p&gt;
&lt;h3&gt;算法逻辑&lt;/h3&gt;
&lt;p&gt;具体的算法流程图如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;packet_in
    &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;
  ARP learning
  MAC_to_Port learning
    &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;               No  
Multicast? &lt;span class="o"&gt;--------------------------------------------&amp;gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                                                   &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; Yes                                               &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                                                   &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                                                   &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;      No                                           &lt;span class="o"&gt;|&lt;/span&gt;
   loop? &lt;span class="o"&gt;-----&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;dpid&lt;span class="p"&gt;,&lt;/span&gt;eth_src&lt;span class="p"&gt;,&lt;/span&gt;dst_ip&lt;span class="p"&gt;)&lt;/span&gt;learning            &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                   &lt;span class="o"&gt;|&lt;/span&gt;                               &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                   &lt;span class="o"&gt;|&lt;/span&gt;                               &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                   &lt;span class="o"&gt;|&lt;/span&gt;               No              &lt;span class="o"&gt;|&lt;/span&gt;         No
    &lt;span class="o"&gt;|&lt;/span&gt;Yes        dst_ip in arp_table? &lt;span class="o"&gt;-------&amp;gt;&lt;/span&gt;dst in mac_to_port? &lt;span class="o"&gt;----&amp;gt;&lt;/span&gt;Flood
    &lt;span class="o"&gt;|&lt;/span&gt;                   &lt;span class="o"&gt;|&lt;/span&gt;                               &lt;span class="o"&gt;|&lt;/span&gt;               &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                   &lt;span class="o"&gt;|&lt;/span&gt;Yes                            &lt;span class="o"&gt;|&lt;/span&gt;Yes            &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                   &lt;span class="o"&gt;|&lt;/span&gt;                               &lt;span class="o"&gt;|&lt;/span&gt;               &lt;span class="o"&gt;|&lt;/span&gt;
   drop             ARP_REPLY                       flow_mod            &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                   &lt;span class="o"&gt;|&lt;/span&gt;                               &lt;span class="o"&gt;|&lt;/span&gt;               &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;                   &lt;span class="o"&gt;|&lt;/span&gt;                               &lt;span class="o"&gt;|&lt;/span&gt;               &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;lt;------------------|&amp;lt;------------------------------|&amp;lt;--------------|&lt;/span&gt;               
    &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;
    end
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;解决环路风暴&lt;/h3&gt;
&lt;p&gt;在回复ARP请求之前，必须要解决的是网络环路问题。我们的解决方案是：以（dpid, eth_src,arp_dst_ip）为key，记录第一个数据包的in_port，并将从网络中返回的数据包丢弃，保证同一个交换机中的某一个广播数据包只能有一个入口，从而防止成环。在此应用中默认网络中发起通信的第一个数据包都是ARP数据包。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;代码如下：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eth_dst&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ETHERNET_MULTICAST&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;ARP&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;header_list:&lt;/span&gt;
    &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst_ip&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw:&lt;/span&gt;  &lt;span class="c1"&gt;# Break the loop&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;in_port:&lt;/span&gt;
            &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPacketOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_NO_BUFFER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;ARP回复&lt;/h3&gt;
&lt;p&gt;解决完环路拓扑中存在的广播风暴问题之后，我们还需要利用SDN控制器可获取网络全局的信息的能力，去代理回复ARP请求，从而减少网络中泛洪的ARP请求数据。这个逻辑非常简单，和二层学习原理基本一样，也是通过自学习主机ARP记录，再通过查询记录并回复。具体代码实现如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ARP&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;header_list:&lt;/span&gt;
    &lt;span class="n"&gt;hwtype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hwtype&lt;/span&gt;
    &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proto&lt;/span&gt;
    &lt;span class="n"&gt;hlen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hlen&lt;/span&gt;
    &lt;span class="n"&gt;plen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plen&lt;/span&gt;
    &lt;span class="n"&gt;opcode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opcode&lt;/span&gt;

    &lt;span class="n"&gt;arp_src_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src_ip&lt;/span&gt;
    &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst_ip&lt;/span&gt;

    &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;opcode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ARP_REQUEST:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp_table:&lt;/span&gt;  &lt;span class="c1"&gt;# arp reply&lt;/span&gt;
            &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;ARP_Reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;ARP_Reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_protocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;ethertype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ETHERNET&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethertype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
            &lt;span class="n"&gt;ARP_Reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_protocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;opcode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ARP_REPLY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;src_mac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;src_ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;dst_mac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;dst_ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;arp_src_ip&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

            &lt;span class="n"&gt;ARP_Reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPacketOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_NO_BUFFER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_CONTROLLER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ARP_Reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;在环状拓扑中解决广播风暴问题基本都是使用STP协议，而SDN的网络架构，给我们提供了一个更高效的解决方案。不仅如此，我们还可以在解决风暴之后，进一步完成ARP代理应用。然而这个简单的APP，并没有很好地解决ARP的问题，因为ARP也有生存时间。而过时的数据会影响网络的正常运行，所以，进一步的优化将是设置ARP记录的刷新时间。以及sw{dpid, eth_src,arp_dst_ip}的刷新时间。以保证数据的有效性。&lt;/p&gt;
&lt;p&gt;推而广之，我们可以按照这样的模式去处理其他的广播数据，如DHCP。更多的功能数据包或者信令数据包的代理，都可以模仿本篇的流程实现。文章的最后，附上完整的代码实现。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# Author:muzixing&lt;/span&gt;
&lt;span class="c1"&gt;# Time:2014/10/19&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;

&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app_manager&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ofp_event&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CONFIG_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;set_ev_cls&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ethernet&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;arp&lt;/span&gt;

&lt;span class="n"&gt;ETHERNET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;
&lt;span class="n"&gt;ETHERNET_MULTICAST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;ff:ff:ff:ff:ff:ff&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;ARP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;


&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ARP_PROXY_13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;OFP_VERSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ARP_PROXY_13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nv"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPSwitchFeatures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CONFIG_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;switch_features_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;
        &lt;span class="n"&gt;ofproto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;
        &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;

        &lt;span class="c1"&gt;# install table-miss flow entry&lt;/span&gt;
        &lt;span class="c1"&gt;#&lt;/span&gt;
        &lt;span class="c1"&gt;# We specify NO BUFFER to max_len of the output action due to&lt;/span&gt;
        &lt;span class="c1"&gt;# OVS bug. At this moment, if we specify a lesser number, e.g.,&lt;/span&gt;
        &lt;span class="c1"&gt;# 128, OVS will send Packet-In with invalid buffer_id and&lt;/span&gt;
        &lt;span class="c1"&gt;# truncated packet data. In that case, we cannot output packets&lt;/span&gt;
        &lt;span class="c1"&gt;# correctly.&lt;/span&gt;

        &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPMatch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_CONTROLLER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                          &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPCML_NO_BUFFER&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;add_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ofproto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;
        &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;

        &lt;span class="n"&gt;inst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPInstructionActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPIT_APPLY_ACTIONS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                             &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

        &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPFlowMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;idle_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hard_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nv"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPPacketIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_packet_in_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;
        &lt;span class="n"&gt;ofproto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;
        &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;
        &lt;span class="n"&gt;in_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;in_port&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="n"&gt;pkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;eth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_protocols&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;
        &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;
        &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

        &lt;span class="n"&gt;header_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;protocol_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;protocols&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ARP&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;header_list:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src_ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;  &lt;span class="c1"&gt;# ARP learning&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;packet in %s %s %s %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# learn a mac address to avoid FLOOD next time.&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="c1"&gt;# 1:reply or drop;  0: flood&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;ARP_PROXY_13&amp;quot;&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_FLOOD&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;OFPP_FLOOD&amp;#39;&lt;/span&gt;

        &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

        &lt;span class="c1"&gt;# install a flow to avoid packet_in next time&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_FLOOD:&lt;/span&gt;
            &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_NO_BUFFER:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPacketOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;arp_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_buffer_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;header_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;
        &lt;span class="n"&gt;in_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ETHERNET&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;header_list:&lt;/span&gt;
            &lt;span class="n"&gt;eth_dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ETHERNET&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;
            &lt;span class="n"&gt;eth_src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ETHERNET&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eth_dst&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ETHERNET_MULTICAST&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;ARP&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;header_list:&lt;/span&gt;
            &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst_ip&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw:&lt;/span&gt;  &lt;span class="c1"&gt;# Break the loop&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;in_port:&lt;/span&gt;
                    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPacketOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_NO_BUFFER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ARP&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;header_list:&lt;/span&gt;
            &lt;span class="n"&gt;hwtype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hwtype&lt;/span&gt;
            &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proto&lt;/span&gt;
            &lt;span class="n"&gt;hlen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hlen&lt;/span&gt;
            &lt;span class="n"&gt;plen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plen&lt;/span&gt;
            &lt;span class="n"&gt;opcode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opcode&lt;/span&gt;

            &lt;span class="n"&gt;arp_src_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src_ip&lt;/span&gt;
            &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst_ip&lt;/span&gt;

            &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;opcode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ARP_REQUEST:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arp_dst_ip&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp_table:&lt;/span&gt;  &lt;span class="c1"&gt;# arp reply&lt;/span&gt;
                    &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="n"&gt;ARP_Reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="n"&gt;ARP_Reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_protocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;ethertype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;header_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ETHERNET&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethertype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
                    &lt;span class="n"&gt;ARP_Reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_protocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;opcode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ARP_REPLY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;src_mac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arp_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="n"&gt;src_ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;arp_dst_ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;dst_mac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;eth_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;dst_ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;arp_src_ip&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

                    &lt;span class="n"&gt;ARP_Reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

                    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPacketOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_NO_BUFFER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_CONTROLLER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ARP_Reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 19 Oct 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-10-19:pages/2014/10/19/ji-yu-sdnde-ryuying-yong-arp_proxy.html</guid><category>SDN</category><category>ARP_PROXY</category><category>RYU</category></item><item><title>RYU入门教程</title><link>http://www.muzixing.com/pages/2014/09/20/ryuru-men-jiao-cheng.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;辗转了POX,NOX,OpenDaylight等多个控制器之后，我终于意识到我只喜欢python语言的控制器。但是我依然记得OpenDaylight的Nullpointer的Exception,还记得YANG文件的深奥，但是OpenDaylight让我对控制器开发的兴趣减少了，这不是我想要的事情。最后，我下决定转向RYU。我突然发现，生活突然变得很美好。我用着我熟悉的，喜欢的，优美的python，写着充满美感的语句，犹如写诗一般的惬意。&lt;/p&gt;
&lt;p&gt;本篇主要介绍如何安装RYU，和如何在RYU上开发APP。&lt;/p&gt;
&lt;h3&gt;RYU的安装&lt;/h3&gt;
&lt;p&gt;安装RYU，需要安装一些python的套件,具体的安装方法可以谷歌，但推荐通过pip install安装，详情查看源码安装部分。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;python-eventlet&lt;/li&gt;
&lt;li&gt;python-routes&lt;/li&gt;
&lt;li&gt;python-webob&lt;/li&gt;
&lt;li&gt;python-paramiko&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;安装RYU主要有两种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;pip安装&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;下载源文件安装&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;git:&lt;/span&gt;&lt;span class="sr"&gt;//gi&lt;/span&gt;&lt;span class="n"&gt;thub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/osrg/&lt;/span&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;requires&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;依赖软件已经在源码的tools/pip-requires文件中，通过pip install来批量安装依赖文件。这种安装方式相比逐个安装依赖要方便，且所需的所有的依赖由官方提供，全面而准确，所以推荐读者通过这种方式安装依赖。&lt;/p&gt;
&lt;p&gt;安装之后，如果遇到lxml的问题，可以通过安装lxml来解决。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;libxml2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt; &lt;span class="n"&gt;libxslt1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;
&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;lxml&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;若遇到six版本不够的问题，则：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;uninstall&lt;/span&gt; &lt;span class="n"&gt;six&lt;/span&gt; 
&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;six&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;来安装高版本的six.&lt;/p&gt;
&lt;p&gt;若还有更多问题，可参考&lt;a href="http://linton.tw/2014/02/15/note-install-ryu-36-sdn-framework/"&gt;@linton小伙伴的博客&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;RYU使用&lt;/h3&gt;
&lt;p&gt;安装RYU之后，进入ryu目录，输入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="n"&gt;yourapp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;运行对应的APP，如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="n"&gt;simple_switch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;RYU源码分析&lt;/h3&gt;
&lt;p&gt;当我安装好了RYU之后，第一件事就是迫不及待地去看它的源码，其可读性之高，超出我的想象。&lt;/p&gt;
&lt;p&gt;下面介绍ryu/ryu目录下的主要目录内容。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;base&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;base中有一个非常重要的文件：app_manager.py.其作用是RYU 应用的管理中心。用于加载RYU应用程序，接受从APP发送过来的信息，同时也完成消息的路由。&lt;/p&gt;
&lt;p&gt;其主要的函数有app注册、注销、查找、并定义了RYUAPP基类，定义了RYUAPP的基本属性。包含name,threads,events、event_handlers和observers等成员，以及对应的许多基本函数。如：start(),stop()等。&lt;/p&gt;
&lt;p&gt;这个文件中还定义了AppManager基类,用于管理APP。定义了加载APP等函数。不过如果仅仅是开发APP的话，这个类可以不必关心。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;controller&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;controller文件夹中许多非常重要的文件，如events.py,ofp_handler.py,controller.py等。其中controller.py中定义了OpenFlowController基类。用于定义OpenFlow的控制器，用于处理交换机和控制器的连接等事件，同时还可以产生事件和路由事件。其事件系统的定义，可以查看events.py和ofp_events.py。&lt;/p&gt;
&lt;p&gt;在ofp_handler.py中定义了基本的handler(应该怎么称呼呢？句柄？处理函数？)，完成了基本的如：握手，错误信息处理和keep alive 等功能。更多的如packet_in_handler应该在app中定义。&lt;/p&gt;
&lt;p&gt;在dpset.py文件中，定义了交换机端的一些消息，如端口状态信息等，用于描述和操作交换机。如添加端口，删除端口等操作。&lt;/p&gt;
&lt;p&gt;其他的文件不再赘述。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;lib&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;lib中定义了我们需要使用到的基本的数据结构，如dpid,mac和ip等数据结构。在lib/packet目录下，还定义了许多网络协议，如ICMP,DHCP，MPLS和IGMP等协议内容。而每一个数据包的类中都有parser和serialize两个函数。用于解析和序列化数据包。&lt;/p&gt;
&lt;p&gt;lib目录下，还有ovs,netconf目录，对应的目录下有一些定义好的数据类型，不再赘述。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ofproto&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在这个目录下，基本分为两类文件，一类是协议的数据结构定义，另一类是协议解析，也即数据包处理函数文件。如ofproto_v1_0.py是1.0版本的OpenFlow协议数据结构的定义，而ofproto_v1_0_parser.py则定义了1.0版本的协议编码和解码。具体内容不赘述，实现功能与协议相同。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;topology&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;包含了switches.py等文件，基本定义了一套交换机的数据结构。event.py定义了交换上的事件。dumper.py定义了获取网络拓扑的内容。最后api.py向上提供了一套调用topology目录中定义函数的接口。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;contrib&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个文件夹主要存放的是开源社区贡献者的代码。我没看过。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;cmd&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;定义了RYU的命令系统，具体不赘述。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;services&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;完成了BGP和vrrp的实现。具体我还没有使用这个模块。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;tests&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;tests目录下存放了单元测试以及整合测试的代码，有兴趣的读者可以自行研究。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;开发你自己的RYU应用程序&lt;/h3&gt;
&lt;p&gt;大概浏览了一下RYU的源代码，相信看过OpenDaylight的同学会发现，太轻松了！哈哈，我想我真的不喜欢maven,osgi,xml，yang以及java，但是不能不承认OpenDaylight还是很牛逼的，在学习的读者要坚持啊！&lt;/p&gt;
&lt;p&gt;开发RYU的APP，真的再简单不过了。&lt;/p&gt;
&lt;p&gt;先来最简单的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app_manager&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;L2Switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L2Switch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;如果你觉得非常熟悉，不要怀疑，我确实是在拿官网的例子再讲。&lt;/p&gt;
&lt;p&gt;首先，我们从ryu.base import app_manager，在前面我们也提到过这个文件中定义了RyuApp基类。我们在开发APP的时候只需要继承这个基类，就获得你想要的一个APP的一切了。于是，我们就不用去注册了？！是的，不需要了！&lt;/p&gt;
&lt;p&gt;保存文件，可以取一个名字为L2Switch.py。&lt;/p&gt;
&lt;p&gt;现在你可以运行你的APP了。快得有点不敢相信吧！但是目前什么都没有，运行之后，马上就会结束，但起码我们的代码没有报错。&lt;/p&gt;
&lt;p&gt;运行:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="n"&gt;L2Switch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;继续往里面添加内容：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app_manager&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ofp_event&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;set_ev_cls&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;L2Switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L2Switch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nv"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPPacketIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;packet_in_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;
        &lt;span class="n"&gt;ofp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;
        &lt;span class="n"&gt;ofp_parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;

        &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_FLOOD&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPacketOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其中ofp_event完成了事件的定义，从而我们可以在函数中注册handler，监听事件，并作出回应。&lt;/p&gt;
&lt;p&gt;packet_in_handler方法用于处理packet_in事件。@set_ev_cls修饰符用于告知RYU，被修饰的函数应该被调用。（翻译得有点烂这句）&lt;/p&gt;
&lt;p&gt;set_ev_cls第一个参数表示事件发生时应该调用的函数，第二个参数告诉交换机只有在交换机握手完成之后，才可以被调用。&lt;/p&gt;
&lt;p&gt;下面分析具体的数据操作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ev.msg：每一个事件类ev中都有msg成员，用于携带触发事件的数据包。&lt;/li&gt;
&lt;li&gt;msg.datapath:已经格式化的msg其实就是一个packet_in报文，msg.datapath直接可以获得packet_in报文的datapath结构。datapath用于描述一个交换网桥。也是和控制器通信的实体单元。datapath.send_msg()函数用于发送数据到指定datapath。通过datapath.id可获得dpid数据，在后续的教程中会有使用。&lt;/li&gt;
&lt;li&gt;datapath.ofproto对象是一个OpenFlow协议数据结构的对象，成员包含OpenFlow协议的数据结构，如动作类型OFPP_FLOOD。&lt;/li&gt;
&lt;li&gt;datapath.ofp_parser则是一个按照OpenFlow解析的数据结构。&lt;/li&gt;
&lt;li&gt;actions是一个列表，用于存放action list，可在其中添加动作。&lt;/li&gt;
&lt;li&gt;通过ofp_parser类，可以构造构造packet_out数据结构。括弧中填写对应字段的赋值即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果datapath.send_msg()函数发送的是一个OpenFlow的数据结构，RYU将把这个数据发送到对应的datapath。&lt;/p&gt;
&lt;p&gt;至此，一个简单的HUB已经完成。&lt;/p&gt;
&lt;h3&gt;RYU进阶——二层交换机&lt;/h3&gt;
&lt;p&gt;在以上的基础之上，继续修改就可以完成二层交换机的功能。具体代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app_manager&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mac_to_port&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ofp_event&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;set_ev_cls&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ofproto_v1_0&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;haddr_to_bin&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ethernet&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;L2Switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RyuApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;OFP_VERSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofproto_v1_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_VERSION&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="c1"&gt;#define the version of OpenFlow&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L2Switch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;add_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ofproto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;

        &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;in_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dl_dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;haddr_to_bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPFlowMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPFC_ADD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idle_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hard_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFP_DEFAULT_PRIORITY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPFF_SEND_FLOW_REM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nv"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPPacketIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;packet_in_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;
        &lt;span class="n"&gt;ofproto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;

        &lt;span class="n"&gt;pkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;eth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_protocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ethernet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;
        &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;

        &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;    &lt;span class="c1"&gt;#get the dpid&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;packet in %s %s %s %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;#To learn a mac address to avoid FLOOD next time.&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;


        &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_FLOOD&lt;/span&gt;

        &lt;span class="c1"&gt;#Look up the out_port &lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mac_to_port&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="n"&gt;ofp_parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto_parser&lt;/span&gt;

        &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPActionOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPP_FLOOD:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


        &lt;span class="c1"&gt;#We always send the packet_out to handle the first packet.&lt;/span&gt;
        &lt;span class="n"&gt;packet_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPacketOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;in_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet_out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;#To show the message of ports&amp;#39; status.&lt;/span&gt;
    &lt;span class="nv"&gt;@set_ev_cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ofp_event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventOFPPortStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAIN_DISPATCHER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_port_status_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;
        &lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;
        &lt;span class="n"&gt;port_no&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt;

        &lt;span class="n"&gt;ofproto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofproto&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPR_ADD:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;port added %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPR_DELETE:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;port deleted %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ofproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OFPPR_MODIFY:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;port modified %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Illeagal port state %s %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;相信代码中的注释已经足以让读者理解这个程序。完成之后，运行:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ryu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="n"&gt;L2Switch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后可以使用mininet进行pingall测试，成功！&lt;/p&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;习惯性还是写一写总结。RYU的方便简洁大大超出我的预料，比我使用过的任何一个控制器都要易于使用和开发。 这些是我学RYU一两天的收获，希望在后续的学习中还能有所收获，写出更好的博文。如果你有什么意见或建议可以评论，相互学习，共同进步。&lt;/p&gt;
&lt;p&gt;最后提供一些有用的链接：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;http://osrg.github.io/ryu/resources.html&lt;/p&gt;
&lt;p&gt;我比较喜欢里里面的   http://ryu.readthedocs.org/en/latest/&lt;/p&gt;
&lt;p&gt;当然里面的电子书也是相当好的：http://osrg.github.io/ryu-book/en/html/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;推荐一个小伙伴的博客：linton.tw &lt;/p&gt;
&lt;p&gt;他在RYU上有更多的学习和研究。欢迎访问！&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sat, 20 Sep 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-09-20:pages/2014/09/20/ryuru-men-jiao-cheng.html</guid></item><item><title>QEMU+virt-manager+phoronix-test-suite服务器测试</title><link>http://www.muzixing.com/pages/2014/09/17/qemuvirt-managerphoronix-test-suitefu-wu-qi-ce-shi.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;这是研究生开学的第一个任务，学习测试服务器性能。首先我们需要在一台新服务器上面安装ubuntu12.04，这个步骤很简单。安装完之后，可以使用top命令查看系统的cpu,mem等性能指标。然后我们就需要安装phoronix-test-suite，用于测试服务器的某些性能。接下来，使用qemu安装虚拟机，在虚拟机有负载的情况下，继续测量服务器的性能。&lt;/p&gt;
&lt;h3&gt;PHORONIX-TEST-SUITE&lt;/h3&gt;
&lt;p&gt;这是一个相当牛逼的服务器测试工具：[phoronix-test-suite]:http://www.phoronix-test-suite.com/&lt;/p&gt;
&lt;p&gt;下载安装：http://get.ubuntusoft.com/app/phoronix-test-suite&lt;/p&gt;
&lt;p&gt;先将安装包下载到本地，然后解压。进入phoronix-test-suite目录，运行install_sh进行安装。&lt;/p&gt;
&lt;p&gt;安装之后可以通过&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;phoronix&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;suite&lt;/span&gt;  &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;查看可使用的测试列表。&lt;/p&gt;
&lt;p&gt;选择某一个测试项进行测试&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;phoronix&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;suite&lt;/span&gt;  &lt;span class="n"&gt;benchmark&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;phoronix&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;suite&lt;/span&gt;  &lt;span class="n"&gt;benchmark&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;接下来只需要按照步骤将测试结果提交给网站，你就可以通过网站查看到测试结果。若想保存测试结果页面，在chrome浏览器中打开，选择打印页面-&amp;gt;保存页面为pdf,则可以将网页保存为pdf文件。&lt;/p&gt;
&lt;p&gt;更多的测试工具如IOZONE等，可自行google.&lt;/p&gt;
&lt;h3&gt;QEMU&lt;/h3&gt;
&lt;p&gt;QEMU is a generic and open source machine emulator and virtualizer.&lt;/p&gt;
&lt;p&gt;When used as a machine emulator, QEMU can run OSes and programs made for one machine (e.g. an ARM board) on a different machine (e.g. your own PC). By using dynamic translation, it achieves very good performance.&lt;/p&gt;
&lt;p&gt;When used as a virtualizer, QEMU achieves near native performances by executing the guest code directly on the host CPU. QEMU supports virtualization when executing under the Xen hypervisor or using the KVM kernel module in Linux. When using KVM, QEMU can virtualize x86, server and embedded PowerPC, and S390 guests.&lt;/p&gt;
&lt;p&gt;QEMU是一套由Fabrice Bellard所编写的模拟处理器的自由软件。它与Bochs，PearPC近似，但其具有某些后两者所不具备的特性，如高速度及跨平台的特性。经由kqemu这个开源的加速器，QEMU能模拟至接近真实电脑的速度。&lt;/p&gt;
&lt;p&gt;简单的说就是一个开源的虚拟化软件，可通过qemu创建虚拟机。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;安装&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;qemu&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;按照提示将依赖全部安装好即可。若不成功，可自行google.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;创建虚拟磁盘&lt;/p&gt;
&lt;p&gt;qemu-img create -f qcow2 ubuntu.img 10G&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;创建一个10G大小的格式为qcow2的虚拟磁盘ubuntu.img，磁盘名字用户自定。 -f为format参数，格式fmt=qcow2,是qemu中最常见的格式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安装虚拟机&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;创建完虚拟磁盘之后，需要将系统安装到这个磁盘上。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;qemu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x86_64&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;hda&lt;/span&gt; &lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cdrom&lt;/span&gt; &lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iso&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;localtime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;smp&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;参数介绍：-hda指定虚拟磁盘位置，如我们创建的ubuntu.img，-cdrom，指定光驱位置，可以是光驱，也可以是iso文件。 -localtime是本地时间。-m 指定内存， -smp指定cpu个数。&lt;/p&gt;
&lt;p&gt;进入虚拟机有一些简单的快捷键可以进行窗口的切换。如 ctrl+alt+f 切换全屏等。&lt;/p&gt;
&lt;p&gt;当然这是在有图形化界面的情况下。若没有图形化界面就会报错：could not initialize SDL.&lt;/p&gt;
&lt;p&gt;这个时候我们就需要在另一台有图形化界面的linux上ssh远程登录，进行后续操作。&lt;/p&gt;
&lt;h3&gt;SSH登录&lt;/h3&gt;
&lt;p&gt;在另一台有图形化界面的linux系统上远程登录服务器。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ssh&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="nv"&gt;@IP&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;输入对应密码进入系统。然后在服务器上安装libvirt和virt-manager。&lt;/p&gt;
&lt;h3&gt;Libvirt和Virt-manager&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;libvirt&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;libvirt is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A toolkit to interact with the virtualization capabilities of recent versions of Linux (and other OSes), see our project goals for details.&lt;/li&gt;
&lt;li&gt;Free software available under the GNU Lesser General Public License.&lt;/li&gt;
&lt;li&gt;A long term stable C API&lt;/li&gt;
&lt;li&gt;A set of bindings for common languages&lt;/li&gt;
&lt;li&gt;A CIM provider for the DMTF virtualization schema&lt;/li&gt;
&lt;li&gt;A QMF agent for the AMQP/QPid messaging system&lt;/li&gt;
&lt;li&gt;A technical meritocracy, in which participants gain influence over a project through recognition of their contributions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;more:http://libvirt.org/&lt;/p&gt;
&lt;p&gt;我们所需要使用的virt-manager是通过libvirt来远程管理虚拟机的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;安装&lt;/p&gt;
&lt;p&gt;sudo apt-get install libvirt&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;virt-manager&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The virt-manager application is a desktop user interface for managing virtual machines through libvirt. It primarily targets KVM VMs, but also manages Xen and LXC (linux containers). It presents a summary view of running domains, their live performance &amp;amp; resource utilization statistics. Wizards enable the creation of new domains, and configuration &amp;amp; adjustment of a domain’s resource allocation &amp;amp; virtual hardware. An embedded VNC and SPICE client viewer presents a full graphical console to the guest domain.&lt;/p&gt;
&lt;p&gt;virt-manager是一个有可视化窗口的，通过libvirt管理虚拟机的管理平台。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;安装&lt;/p&gt;
&lt;p&gt;sudo apt-get install virt-manager&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;按照提示安装完所有的依赖。&lt;/p&gt;
&lt;h3&gt;Virt-manager管理虚拟机&lt;/h3&gt;
&lt;p&gt;virt-manager是一个远程虚拟机管理软件，可以提供可视化的操作界面来创建虚拟机和管理虚拟机。&lt;/p&gt;
&lt;p&gt;远程登录到服务器安装完virt-manager之后，运行virt-manager&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;virt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;如果之前的ssh没有加-X参数的话，这个命令不会任何反应。加了-X参数之后，virt-manager会弹出一个运行窗口。&lt;/p&gt;
&lt;p&gt;点击左上角的创建虚拟机，在指定步骤选择由qemu创建好的img文件和以下载的iso文件。点击确定进行安装。这一步相信不难。接下来就是普通的安装系统，这里不再赘述。&lt;/p&gt;
&lt;h3&gt;Libvirt管理虚拟机&lt;/h3&gt;
&lt;p&gt;通过libvirt可以在不需要图形化界面的情况下管理虚拟机。这将使用到virsh。virsh是libvirt的一套shell指令。&lt;/p&gt;
&lt;p&gt;我们通过virsh可以创建和管理虚拟机。&lt;/p&gt;
&lt;p&gt;help:           显示该命令的说明&lt;/p&gt;
&lt;p&gt;quit:           结束 virsh，回到 Shell&lt;/p&gt;
&lt;p&gt;connect:            连接到指定的虚拟机服务器&lt;/p&gt;
&lt;p&gt;create:        启动一个新的虚拟机&lt;/p&gt;
&lt;p&gt;destroy:            删除一个虚拟机&lt;/p&gt;
&lt;p&gt;start:        开启（已定义的）非启动的虚拟机&lt;/p&gt;
&lt;p&gt;define:         从 XML 定义一个虚拟机&lt;/p&gt;
&lt;p&gt;undefine:        取消定义的虚拟机&lt;/p&gt;
&lt;p&gt;dumpxml:            转储虚拟机的设置值&lt;/p&gt;
&lt;p&gt;list:           列出虚拟机&lt;/p&gt;
&lt;p&gt;reboot:         重新启动虚拟机&lt;/p&gt;
&lt;p&gt;save:           存储虚拟机的状态&lt;/p&gt;
&lt;p&gt;restore:            回复虚拟机的状态&lt;/p&gt;
&lt;p&gt;suspend:            暂停虚拟机的执行&lt;/p&gt;
&lt;p&gt;resume:         继续执行该虚拟机&lt;/p&gt;
&lt;p&gt;dump:           将虚拟机的内核转储到指定的文件，以便进行分析与排错&lt;/p&gt;
&lt;p&gt;shutdown:        关闭虚拟机&lt;/p&gt;
&lt;p&gt;setmem:         修改内存的大小&lt;/p&gt;
&lt;p&gt;setmaxmem:       设置内存的最大值&lt;/p&gt;
&lt;p&gt;setvcpus:        修改虚拟处理器的数量&lt;/p&gt;
&lt;p&gt;如关闭一个正在运行的名称为ubuntu的虚拟机：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;virsh&lt;/span&gt; &lt;span class="nb"&gt;shutdown&lt;/span&gt; &lt;span class="n"&gt;ubuntu&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;克隆虚拟机&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在创建虚拟机之后，我们还可以通过克隆虚拟机来快速创建虚拟机。实例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;virt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nb"&gt;connect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;qemu:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其中template替换成被克隆虚拟机名称，clone替换成克隆输出的虚拟机名称，clone.img是格式化好的虚拟磁盘，可使用qemu制作。&lt;/p&gt;
&lt;h3&gt;测试&lt;/h3&gt;
&lt;p&gt;目前位置我们已尽完成了服务器性能测试和虚拟机创建和管理，只需要重复以上工作即可完成指定要求的服务器性能测试。&lt;/p&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;至此为止我们完成了服务器测试的准备工作。在搭建环境的过程中学习到了许多有用的知识，如虚拟化技，ssh登录等等。感觉非常好玩。通过scp去拖拽文件，让我感觉网络的神奇，我在不知不觉中就被小伙伴修改了许多文件。感觉被偷了还不知道。囧囧的。scp例子如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;scp&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="nv"&gt;@10&lt;/span&gt;&lt;span class="mf"&gt;.108.144.100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;/home/&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="sr"&gt;/music.mp3 /&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="sr"&gt;/music/m&lt;/span&gt;&lt;span class="n"&gt;usic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mp3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;将10.108.144.100root用户的/home/root/music.mp3 复制到本机的home/music，命名为music.mp3。传文件的远端类似，将参数位置调换即可。&lt;/p&gt;
&lt;p&gt;在如今云计算的时代，虚拟化技术已经是最基本的技术，有时间学一学还是很好玩的。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 17 Sep 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-09-17:pages/2014/09/17/qemuvirt-managerphoronix-test-suitefu-wu-qi-ce-shi.html</guid></item><item><title>OpenDayLight中MD-SAL学习笔记</title><link>http://www.muzixing.com/pages/2014/08/13/opendaylightzhong-md-salxue-xi-bi-ji.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;在学习opendaylight的过程中，总是遇到AD-SAL( API-Driven SAL)和MD-SAL（Model-Driven SAL）等概念。在努力查找资料学习之后，有了一点学习笔记，写出来加深印象。同时也给同样迷惑的同学一点帮助。&lt;/p&gt;
&lt;p&gt;转载请声明：北邮-李呈：www.muzixing.com&lt;/p&gt;
&lt;h2&gt;About MD-SAL&lt;/h2&gt;
&lt;p&gt;MD-SAL使得在SDN控制器那些丰富的服务和模块可以使用统一的数据结构和南向和北向的API。&lt;/p&gt;
&lt;p&gt;&lt;img alt="sal-comparison" src="https://wiki.opendaylight.org/images/4/4d/SAL-Comparison.png" /&gt;&lt;/p&gt;
&lt;p&gt;上图引用地址：https://wiki.opendaylight.org/images/4/4d/SAL-Comparison.png&lt;/p&gt;
&lt;p&gt;MD-SAL提供请求路由（request routing）和基础设施去支持服务的适配，但它不提供服务的适应本身;业务适配是由插件提供。MD-SAL认为适配插件是一个普通的插件：它向SAL提供数据，并通过模型生产的API来读取消费数据。&lt;/p&gt;
&lt;h3&gt;Request outing&lt;/h3&gt;
&lt;p&gt;为SAL中，request routing可用于消费者的请求路由，从而寻找到对应的生产者。当一个plugin注册之后，就会在routing table中有对应记录，consumer向SAL发起RPC应用申请的时候，会由request routing查找routing table，找到对应的plugin。&lt;/p&gt;
&lt;p&gt;在md-sal/sal-binding-api/...、binding/api/rpc目录下可以找到RpcRouter.java等文件，都与RPC routing有关。当然request routing还有notification的routing,并不仅仅只是rpc。&lt;/p&gt;
&lt;h2&gt;Bundle register&lt;/h2&gt;
&lt;h3&gt;AbstractBrokerAwareActivator&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;在一个具体的plugin实现中会继承AbstractBindingAwareProvider类,而AbstractBindingAwareProvider继承了AbstractBrokerAwareActivator类。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当一个bundle启动时就会调用AbstractBrokerAwareActivator。这个类实现了org.osgi.framework.BundleActivator接口。BunbleActivator中的start（BundleContext context）和stop(BundleContext context)方法用于开启bundle和关闭bundle.在AbstractBrokerAwareActivator中，实现了start和stop两个方法，分别调用了startImpl和stopImpl两个具体的方法。startImpl是在bundle开始的时候，用于初始化，资源申请等。同理，stopImpl是bundle关闭时，资源的释放。&lt;/p&gt;
&lt;p&gt;同理，消费者类似。&lt;/p&gt;
&lt;h3&gt;onSessionInitialized&lt;/h3&gt;
&lt;p&gt;每一个消费者或生产者和SAL之间的通信都可以具体称之为Session(会话)。上一小节提到的BundleActivator接口中有两个方法start和stop的参数都是BundleConetxt.在BundleContext接口中定义了许多方法，如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;registerService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Class&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;S\&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;java.lang.String,?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;可实现bundle的注册。具体链接：http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/BundleContext.html&lt;/p&gt;
&lt;p&gt;在onSessionInitialized方法中，通常会调用session.addRpcImplementation(Class&lt;T&gt; Serviceinterface,T implementation)。其方法定义在RpcProvider.java中，用于指明bunlde初始化时的接口和实现等运行实体。&lt;/p&gt;
&lt;h2&gt;Register to MD-SAL&lt;/h2&gt;
&lt;h3&gt;BindingAwareBroker&lt;/h3&gt;
&lt;p&gt;BindingAwareProvider和BindingAwareConsumer都实现了BindingAwareBroker interface,用
于实现生产者和消费者的在MD-SAL注册。此接口可以消除生产者和消费者之间的直接关系。&lt;/p&gt;
&lt;p&gt;其他文件的功能根据文件名称基本可以了解。博主也没有太多深究。&lt;/p&gt;
&lt;h3&gt;RPC register&lt;/h3&gt;
&lt;p&gt;调用&lt;strong&gt;addRpcImplementation(class &amp;lt;T&gt; serviceInterface, T implementation)&lt;/strong&gt;方法将RPC注册到MD-SAL,具体可查看RpcProviderRegister.java。举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;providerContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addRpcImplementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ShapeService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;具体链接：http://sdntutorials.com/how-to-register-a-service-to-md-sal/&lt;/p&gt;
&lt;p&gt;消费者可以通过&lt;strong&gt;getRpcService(class &lt;T/&gt; serviceInterface)&lt;/strong&gt;调用对应的RPC。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRpcService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ShapeService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Plugin development process&lt;/h2&gt;
&lt;p&gt;&lt;img alt="plugin_development_process" src="https://wiki.opendaylight.org/images/3/39/Plugin_design_process.png" /&gt;&lt;/p&gt;
&lt;p&gt;上图引用地址：https://wiki.opendaylight.org/images/3/39/Plugin_design_process.png&lt;/p&gt;
&lt;p&gt;在ODL中开发一个plugin的流程如上所示。以&lt;a href="http://www.muzixing.com/pages/2014/08/06/opendaylightzhong-kai-fa-mo-kuai-ping.html"&gt;Ping&lt;/a&gt;为例，首先需要使用YANG定义一个model,即model-ping。使用maven编译的时候，会调用YANG Tools自动生成对应的API.然后生成API OSGI Bundle。&lt;/p&gt;
&lt;p&gt;接着我们需要对接口进行实现，也即plugin source code.在ping例子中ping-plugin就是plugin source code。通过maven编译生成plugin OSGI Bundle.最后都部署到OSGI上。将对应的jar包放到controller对应目录中，运行controller时就会和控制器一起运行。但是在全局编译的时候还需要再对应的pom.xml中对其进行描述，从而使得在编译时将对应的bundle编译并生成对应的jar，从而成功在controller中添加功能。&lt;/p&gt;
&lt;h3&gt;Example&lt;/h3&gt;
&lt;p&gt;借用&lt;a href="https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:FAQ"&gt;官网&lt;/a&gt;的一张图，解（翻）释（译）一下添加新流表时，ODL内部运行的场景。&lt;/p&gt;
&lt;p&gt;&lt;img alt="add_flow_case" src="https://wiki.opendaylight.org/images/1/17/Add_Flow_use_case.png" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当plugin/app启动时，对应的bundle已经完成了注册。a）流编程服务(还是flow programmer service舒服)在md-sal注册，提供流数据配置通知服务。b）OF 插件和其他的插件在SAL上注册AddFlow RPF实现。注意RPC在plugin model中定义，而API是在编译过程中生成的。&lt;/li&gt;
&lt;li&gt;一个客户app通过控制器提供的REST API请求add flow。客户端app需要提供这个REST调用的全部参数。&lt;/li&gt;
&lt;li&gt;从“add flow”来的数据发序列化，然后一个新流就在flow service 配置数据树上创建了。若成功REST调用马上回回复调用者成功信息。&lt;/li&gt;
&lt;li&gt;由于flow programmer service已经注册去接收在flow service data tree上的数据变化消息的通知。MD-SAL产生一个data changed的通知并发给Flow programmer service.&lt;/li&gt;
&lt;li&gt;flow programmer service 读取该消息，并产生添加动作。&lt;/li&gt;
&lt;li&gt;在这个过程中还其他的操作中，flow programmer service 需要告诉OF plugin在适当的交换机上添加flow。Flow programmer service 使用OF plugin生成的API去创建"AddFlow"RPC所需要的输入参数DTO(data transfer obiect).&lt;/li&gt;
&lt;li&gt;Flow programmer service 获取到服务的实例，然后引用服务中的“AddFlow”RPC。MD-SAL将会将请求路由到适当的OF plugin。&lt;/li&gt;
&lt;li&gt;"AddFlow"RPC 请求被路由到OF plugin，然后“AddFlow”RPC的实现方法被引用。&lt;/li&gt;
&lt;li&gt;“AddFlow”RPC实现通过OF plugin API去读取RPC 输入参数的DTO.&lt;/li&gt;
&lt;li&gt;"AddFlow"RPC 被远程运行，相应的flow_mod被下发到相应的交换机。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;后语&lt;/h2&gt;
&lt;p&gt;对于MD-SAL，我只是有一个概念，离真正了解还有很多距离。文中若有错误指出，敬请指出，共同进步！&lt;/p&gt;
&lt;p&gt;其实官网上已经有很多资料，在学习的过程中，OpenDaylight SDN研究群（194240432）的共享资料帮助了我很多。接下来我将学习官网教程toaster,希望能在那个例子中得到实践经验，为以后的工程开发打下基础。以目前的状况来看，我还需要花很多时间来学习ODL，之后才是真正的SDN应用开发。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 13 Aug 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-08-13:pages/2014/08/13/opendaylightzhong-md-salxue-xi-bi-ji.html</guid><category>opendaylight</category><category>md-sal</category></item><item><title>OpenFlow1.3学习笔记</title><link>http://www.muzixing.com/pages/2014/08/10/openflow13xue-xi-bi-ji.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;OpenFlow1.3比1.0版本复杂太多了。由于交换机和控制器没有太多支持，所以关于OpenFlow的应用大多是基于1.0版本的，但是1.3版本相当经典，其中许多内容都是值得学习的。今天翻看了一下1.3版本的OF协议，觉得收获颇多，将学习笔记写下来加深印象，也给后人学习提供一点帮助吧。笔记不是协议翻译，只总结一些疑难点。&lt;/p&gt;
&lt;h2&gt;OpenFlow端口&lt;/h2&gt;
&lt;p&gt;OF端口是OF处理流程和网络其他部分进行转发数据包的网络接口。
OF交换机通过OF接口和其他交换机建立逻辑连接。OF交换机必须支持的端口类型为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;物理端口&lt;/li&gt;
&lt;li&gt;逻辑端口&lt;/li&gt;
&lt;li&gt;保留端口&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;逻辑端口和物理端口的不同在于，逻辑端口比物理端口更高一级，是对物理端口的虚拟化，提高可复用性，逻辑端口的数据包需要有tunnel_id，而物理端口没有。    &lt;/p&gt;
&lt;p&gt;保留端口中又分为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ALL&lt;/li&gt;
&lt;li&gt;CONTROLLER&lt;/li&gt;
&lt;li&gt;TABLE&lt;/li&gt;
&lt;li&gt;IN_PORT&lt;/li&gt;
&lt;li&gt;ANY&lt;/li&gt;
&lt;li&gt;LOCAL&lt;/li&gt;
&lt;li&gt;NORMAL&lt;/li&gt;
&lt;li&gt;FLOOD&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中所有OF交换机都要支持ALL,CONTROLLER,TABLE,IN_PORT,ANY类型端口，OF_ONLY不要求支持LOCAL,NORMAL,FLOOD端口。&lt;/p&gt;
&lt;h2&gt;OpenFlow Table&lt;/h2&gt;
&lt;p&gt;OpenFlow Table分为255级，最低级为0.&lt;/p&gt;
&lt;p&gt;一条flow entry的结构为：&lt;/p&gt;
&lt;table class="table-bordered table-striped table-condensed"&gt;
    &lt;tr&gt;
        &lt;td&gt;Match Fields&lt;/td&gt;
        &lt;td&gt;Priority&lt;/td&gt;
        &lt;td&gt;Counters&lt;/td&gt;
        &lt;td&gt;Instructions&lt;/td&gt;
        &lt;td&gt;Timeouts&lt;/td&gt;
        &lt;td&gt;Cookie&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;此处有一个区别于1.0版本的instruction,  用于修改动作及或者处理流程，作用于各级流表之间。匹配过程可查看协议。&lt;/p&gt;
&lt;h3&gt;Miss_table&lt;/h3&gt;
&lt;p&gt;每一个flow_table都需要支持table_miss，table_miss明确了如何处理未匹配的流，动作可能是DROP,也有可能是其他。&lt;/p&gt;
&lt;p&gt;table_miss flow entry 并不是缺省存在与流表中的。我们可通过控制器随时进行添加或删除。&lt;/p&gt;
&lt;h2&gt;Group Table&lt;/h2&gt;
&lt;p&gt;Group Table不是一个Flow Table。他是一个动作组的集合。一个动作组称之为group entry。它的结构如下：&lt;/p&gt;
&lt;table class="table-bordered table-striped table-condensed"&gt;
    &lt;tr&gt;
        &lt;td&gt;Group Identifier&lt;/td&gt;
        &lt;td&gt;Group Type&lt;/td&gt;
        &lt;td&gt;Counters&lt;/td&gt;
        &lt;td&gt;Action Buckets&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;当flow entry中有ofp_action_group时，将指明该flow entry选择执行的group table的ID。结构为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;/* Action structure for OFPAT_GROUP. */&lt;/span&gt;
&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ofp_action_group&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;/* OFPAT_GROUP. */&lt;/span&gt;
    &lt;span class="n"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;/* Length is 8. */&lt;/span&gt;
    &lt;span class="n"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;group_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;/* Group identifier. */&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Group Type&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;all:执行action buckets中所有的动作。适用于multicast or broadcast forwarding。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;select:选择其中若干组执行，适用于Load balancing。可以简单轮询，也可以根据权重执行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;indirect：只执行group中的一个bucket,这个组只支持一个bucket,允许多流表和组表指到这个组。可用于链路聚合（link aggregation)，支持快速的，高效的收敛。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fast failover：选择第一个活跃的bucket执行。可以在不询问控制器的情况下改变转发决策。但是要使用这个，还需要制定一个bucket的生存机制。可用于动态的负载均衡。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Instructions和Action的区别&lt;/h2&gt;
&lt;p&gt;1.0版本中没有instruction。而在1.3中，instruction又和action有一些相似之处。仔细阅读之后发现两者是不一样的。instructions作用于流表之间，用于控制processing和修改action set。可以说是action的生产指令。而action则是对数据包修改的动作。&lt;/p&gt;
&lt;h3&gt;Instruction&lt;/h3&gt;
&lt;p&gt;instructions的类型有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;(Optional)Meter meter_id:将数据包直接交给某一个meter.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(Optional)Apply-Actions actions(s):在不修改action set的情况下立即应用actions中的action。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(Optional)Clear-Actions:立即清除action set中的所有action&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(Required)Write-Actions actions(s):立即向action set中添加action，若已存在，覆盖，否则添加。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(Optional)Write-Metadata metadata/mask:添加metadata&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;（Required）Goto-table next_tale_id:跳转到下一个table,跳转对象id必须大于当前的，也就是说不可以跳回来。最后一个table必然不存在这个指令。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(Optional)Experimenter:用于试验 &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Action&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Action set &lt;/p&gt;
&lt;p&gt;每一个数据包都有一个action set,用于记录action。在processing中，action set在流表之间传递。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Action list&lt;/p&gt;
&lt;p&gt;集合和列表的区别显而易见。Apply-action和Packet_out消息包含action_list。因为这两者执行的动作是可重复的。如多个action_output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Actions&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Required &lt;strong&gt;Out_put&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Optional &lt;strong&gt;Set_queue&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Reqiured &lt;strong&gt;Drop&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Reqiured &lt;strong&gt;Group&lt;/strong&gt;指明动作类型为group.从而流表选择group中的action bucket。&lt;/li&gt;
&lt;li&gt;Optional &lt;strong&gt;Push_Tag/Pop_Tag&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Optional &lt;strong&gt;Set_Field&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Optional &lt;strong&gt;Change_TTL&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体细节可查看协议，不再赘述。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Multicle Controller&lt;/h2&gt;
&lt;p&gt;在1.3版本的OF中支持多控制器。但是这个多控制器只是相对于交换机而已。因为OF协议只是定义了交换机和控制器之间的通信过程。具体的控制器协同工作内容不是OF的范围。也许我可以开发一个这样的协议哦！&lt;/p&gt;
&lt;p&gt;在多控制器内容中，相对于交换机而言，控制器可以有3中身份：equal,master和slave。控制器可以在任何时候改变角色。&lt;/p&gt;
&lt;h3&gt;Equal&lt;/h3&gt;
&lt;p&gt;Equal表明这个控制器并没有什么特殊之处，他和其他同样为equal的控制器是同等级的。比如一个交换机连接了3个控制器，且这三个控制器都是equal属性，那么这三个控制器对于交换机而言是等价的。equal类型控制器相当于一个独立的，具有完全权限的控制器。&lt;/p&gt;
&lt;h3&gt;Master and Slave&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Master&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Master角色具有和Equal一样的完全权限。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当多控制器中某一个控制器申请成为Master时，其他控制器将成为Slave角色。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Slave&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作为Slave角色的控制器对交换机仅有可读权限,不能接受异步消息&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;（除去port_status以外的其他异步等消息）&lt;/p&gt;
&lt;p&gt;不能向交换机发送写消息（ofp_flow_mod等），若交换机收到slave控制器发送的写消息，将产生ERROR。 &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Mininet启动1.3版本OF&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;mn&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;topo&lt;/span&gt; &lt;span class="n"&gt;single&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="n"&gt;remote&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;ovsk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;protocols&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OpenFlow13&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从以上可知，启动1.3版本的命令是protocols=OpenFlow13,但是这只是启动了mininet的1.3版本，还需要对交换机进行配置。命令如下： &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vsctl&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;bridge&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="n"&gt;protocols&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OpenFlow13&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;查看1.3版本的流表命令为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;ovs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ofctl&lt;/span&gt; &lt;span class="nb"&gt;dump&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;flows&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt; &lt;span class="n"&gt;OpenFlow13&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;OpenFlow教程&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;archive&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openflow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="sr"&gt;/wk/i&lt;/span&gt;&lt;span class="n"&gt;ndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;OpenFlow_Tutorial&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;后语&lt;/h2&gt;
&lt;p&gt;OF1.3内容实在太多，目前博主还未使用1.3版本进行实验，所以了解不多，若文中出现不正确的地方，欢迎在评论中指出。希望我能给你一些帮助。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 10 Aug 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-08-10:pages/2014/08/10/openflow13xue-xi-bi-ji.html</guid><category>openflow</category></item><item><title>Opendaylight中开发模块Ping</title><link>http://www.muzixing.com/pages/2014/08/06/opendaylightzhong-kai-fa-mo-kuai-ping.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;在安装和运行opendaylight之后，我们需要了解opendaylight各个目录的作用，运行机制。在此基础之上，我们需要动手进行第一个ODL模块的开发，在开发中找到ODL的重要所在。接下来的教程是在完成官网的一篇教程的基础上的总结和介绍，希望读者能有所收获。&lt;/p&gt;
&lt;h3&gt;摘要&lt;/h3&gt;
&lt;p&gt;本篇教程主要介绍如何在ODL上使用MD-SAL开发一个简单的TCP ping插件。这个插件实现了向指定地址发送ICMP，探测IP地址可达性的功能。首先我们需要使用YANG定义一个ping model,然后我们需要实现一个ping plugin,实现ping功能，再然后创建ping service 用于提供ping服务，最后我们通过REST API来实现北向接口使用ping service。&lt;/p&gt;
&lt;p&gt;其中每一个功能，我们将其创建为maven工程，并作为osgi的bundle。所以我们总共需要创建4个OSGI 的bundle：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Northbound API / Implementation [ping-northbound]&lt;/p&gt;
&lt;p&gt;The northbound API defines the interface for interacting with the given service. For example, a REST, or JSON interface for invoking the ping service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Service Bundle [ping-service]&lt;/p&gt;
&lt;p&gt;The service bundle links the northbound implementation with the south bound (MD-SAL) definitions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;South Bound API (MD-SAL definition) [model-ping]&lt;/p&gt;
&lt;p&gt;This bundle defines a simple yang file which results in auto-generated data-models ( i.e. auto generated java interfaces)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Specific Implementation of South Bound Interface&lt;/p&gt;
&lt;p&gt;Defines the specific of the south bound interface, generally protocol specific etc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第一步：下载控制器源码，编译&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;使用一下的命令下载controller的最新代码，注意，若使用以前旧版本的控制器，在教程中会遇到一些问题，所以推荐重新下载新文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;https:&lt;/span&gt;&lt;span class="sr"&gt;//gi&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="sr"&gt;/gerrit/&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;检查YANG tools的版本&amp;gt;=0.5.8-SNAPSHOT即可。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;vi controller/opendaylight/commons/opendaylight/pom.xml
...
&lt;span class="nt"&gt;&amp;lt;yangtools.version&amp;gt;&lt;/span&gt;0.5.8-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/yangtools.version&amp;gt;&lt;/span&gt;
...
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编译控制器&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;
&lt;span class="n"&gt;mvn&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第二步：使用YANG定义model-ping&lt;/h3&gt;
&lt;p&gt;在ODL中使用YANG来描述底层的数据结构，所以我们需要首先要建立一个YANG model文件，目的是为了生成JAVA API。YANG文件定义的数据结构可以一一对应生成java 接口等API，更详细的资料请看：  &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;https:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;wiki&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="sr"&gt;/view/&lt;/span&gt;&lt;span class="n"&gt;YANG_Tools:YANG_to_Java_Mapping&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;最简单的方式是在md-sal/model中建立model，这样可以和使用其他模块的pom.xml。在完成第一步的基础上，按照以下命令，创建YANG工程&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="sr"&gt;/../m&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sal&lt;/span&gt;&lt;span class="sr"&gt;/model/&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后在src/main/yang目录创建文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个ping model的yang文件首先需要定义一个简单的RPC(Remote Procedure Call Protocol)来完成ping request的初始化，这个过程需要IPV4的地址作为参数，所以我们需要import “ietf-inet-types” model。同时，我们也要为这个调用设置返回值。具体如下：（复制粘贴时请将中文注释删除）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;        &lt;span class="c1"&gt;#模块名称&lt;/span&gt;
  &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;urn:opendaylight:ping&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ietf&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;inet&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;&lt;span class="c1"&gt;#import&lt;/span&gt;
  &lt;span class="n"&gt;revision&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;2013-09-11&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;TCP ping module&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;#对模块/模型描述&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;rpc&lt;/span&gt; &lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;          &lt;span class="c1"&gt;#定义rpc &lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Send TCP ECHO request&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    &lt;span class="c1"&gt;#输入&lt;/span&gt;
      &lt;span class="n"&gt;leaf&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;inet:ipv4&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;#参数为ipv4地址&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;   &lt;span class="c1"&gt;#输出&lt;/span&gt;
      &lt;span class="n"&gt;leaf&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;enumeration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;reachable&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    &lt;span class="c1"&gt;#返回类型&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Received reply&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;unreachable&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;No reply during timeout&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;error&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Error happened&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Result types&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成之后，我们需要为maven项目model-ping构建pom.xml文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;pom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在pom.xml中使用model-parent 会使整个pom.xml变得很简单。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;&lt;/span&gt;
 &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
 &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;model-parent&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller.model&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;relativePath&amp;gt;&amp;lt;/relativePath&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;model-ping&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;bundle&lt;span class="nt"&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成以上的步骤之后，就可以使用maven编译生成API和bundle了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mvn&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;若想运行ODL的时候运行bundle，则需要将生成的jar包复制到plugins目录。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="sr"&gt;/target/mo&lt;/span&gt;&lt;span class="n"&gt;del&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SNAPSHOT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="sr"&gt;/../&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="sr"&gt;/distribution/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/target/&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
&lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;osgipackage&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;/\&lt;/span&gt;
&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SNAPSHOT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;第三步：ping plugin&lt;/h3&gt;
&lt;p&gt;上一步我们创建了一个model，定义了数据结构，这一步我们需要创建一个bundle来实现这个ping的插件。从而提供ping的服务。&lt;/p&gt;
&lt;p&gt;在controller/opendaylight/ping目录创建工程，命令如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="sr"&gt;/../&lt;/span&gt;&lt;span class="o"&gt;../&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="sr"&gt;/plugin/s&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="sr"&gt;/org/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/controller/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="sr"&gt;/plugin/i&lt;/span&gt;&lt;span class="n"&gt;nternal&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这依然是一个maven工程，所以我们需要创建他的pom.xml文件，用于描述工程。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;pom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在pom.xml文件中，我们需要为上一步定义的model-ping描述依赖关系。并需要引入上一步编译生成的包：org.opendaylight.yang.gen.v1.urn.opendaylight.ping.rev130911。 同时，为了定义ipv4，我们还需要引入依赖包：org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;&lt;/span&gt;
 &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
 &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;commons.opendaylight&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.4.2-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;relativePath&amp;gt;&lt;/span&gt;../../commons/opendaylight&lt;span class="nt"&gt;&amp;lt;/relativePath&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;ping.plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.4.0-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;bundle&lt;span class="nt"&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;  #构建工程
   &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.felix&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-bundle-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;extensions&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;instructions&amp;gt;&lt;/span&gt;
           &lt;span class="nt"&gt;&amp;lt;Import&lt;/span&gt;&lt;span class="err"&gt;-Package&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
             org.opendaylight.yang.gen.v1.urn.opendaylight.ping.rev130911,
             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
             org.opendaylight.yangtools.yang.common,
             org.opendaylight.yangtools.yang.binding,
             org.opendaylight.controller.sal.binding.api,
             org.opendaylight.controller.sal.common.util,
             com.google.common.util.concurrent,
             org.osgi.framework
           &lt;span class="nt"&gt;&amp;lt;/Import-Package&amp;gt;&lt;/span&gt;
           &lt;span class="nt"&gt;&amp;lt;Export&lt;/span&gt;&lt;span class="err"&gt;-Package&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
             org.opendaylight.controller.ping.plugin.internal#生成包，java文件所在目录
           &lt;span class="nt"&gt;&amp;lt;/Export-Package&amp;gt;&lt;/span&gt;
           &lt;span class="nt"&gt;&amp;lt;Bundle&lt;/span&gt;&lt;span class="err"&gt;-Activator&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
             org.opendaylight.controller.ping.plugin.internal.PingProvider
           &lt;span class="nt"&gt;&amp;lt;/Bundle-Activator&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;/instructions&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;manifestLocation&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;/META-INF&lt;span class="nt"&gt;&amp;lt;/manifestLocation&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;#依赖关系
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.osgi&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;org.osgi.core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller.model&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;model-ping&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sal-binding-api&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sal-common-util&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.yangtools&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;yang-common&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;yangtools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.yangtools&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;yang-binding&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;yangtools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成pom.xml之后，我们需要在正确的目录添加接口实现文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="sr"&gt;/org/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/controller/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="sr"&gt;/plugin/i&lt;/span&gt;&lt;span class="n"&gt;nternal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;PingImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在第一步完成之后，我们已经由YANG文件生成了PingService的接口。PingImpl将实现PingService接口。在PingService中有sendEcho 的RPC方法声明，所以PingImpl也有这一方法。这个RPC方法将IPV4数据 “SendEchoInput”作为参数传入，并返回枚举类型"SendEchoOutput"。返回值是由YANG定义的EchoResult.Reachable或者EchoResult.Unreachable，错误还会返回EchoResult.Error。类中用InetAddress.isReachable(timeout)函数去检测IPV4地址是否可达。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;package&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IOException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InetAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rpcs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev130911&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev130911&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEchoInput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev130911&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEchoOutput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev130911&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEchoOutput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EchoResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev130911&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEchoOutputBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yangtools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RpcError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yangtools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RpcResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;google&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Futures&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;PingImpl&lt;/span&gt; &lt;span class="n"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;PingService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;EchoResult&lt;/span&gt; &lt;span class="n"&gt;pingHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InetAddress&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;IOException&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isReachable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EchoResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EchoResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unreachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;EchoResult&lt;/span&gt;&lt;span class="err"&gt;是在&lt;/span&gt;&lt;span class="n"&gt;YANG&lt;/span&gt;&lt;span class="err"&gt;文件中定义的输出数据格式，编译之后生成的&lt;/span&gt;&lt;span class="n"&gt;JAVA&lt;/span&gt;&lt;span class="err"&gt;类型。&lt;/span&gt;

    &lt;span class="nv"&gt;@Override&lt;/span&gt;
    &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;RpcResult&amp;lt;SendEchoOutput&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sendEcho&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SendEchoInput&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;InetAddress&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InetAddress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDestination&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;EchoResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pingHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="sr"&gt;/* Build the result and return it. */&lt;/span&gt;
            &lt;span class="n"&gt;SendEchoOutputBuilder&lt;/span&gt; &lt;span class="n"&gt;ob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SendEchoOutputBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;ob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setEchoResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;RpcResult&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;SendEchoOutput&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rpcResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                    &lt;span class="n"&gt;Rpcs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;SendEchoOutput&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getRpcResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                            &lt;span class="n"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;RpcError&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;emptySet&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Futures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;immediateFuture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rpcResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="sr"&gt;/* Return error result. */&lt;/span&gt;
            &lt;span class="n"&gt;SendEchoOutputBuilder&lt;/span&gt; &lt;span class="n"&gt;ob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SendEchoOutputBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;ob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setEchoResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EchoResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;RpcResult&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;SendEchoOutput&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rpcResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                    &lt;span class="n"&gt;Rpcs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;SendEchoOutput&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getRpcResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                            &lt;span class="n"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;RpcError&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;emptySet&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Futures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;immediateFuture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rpcResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Futures:represents the result of an asynchronous computation.&lt;/p&gt;
&lt;p&gt;more:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html&lt;/p&gt;
&lt;p&gt;完成PingImpl.java之后我们还需要一个java文件，作用在于在osgi上注册plugin service，是bundle的activator。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="sr"&gt;/org/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/controller/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="sr"&gt;/plugin/i&lt;/span&gt;&lt;span class="n"&gt;nternal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;PingProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个类需要继承AbstractBindingAwareProvider 接口（这个接口非常重要，后续的教程教详细介绍相关内容）。在我们的例子这个接口中的onSessionInitiated 是最重要的方法。我们使用这个方法，将pingservice的接口和实现作为参数参入，实现服务在OSGI框架注册，从而让其他bundle感知到。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="x"&gt;package org.opendaylight.controller.ping.plugin.internal;&lt;/span&gt;

&lt;span class="x"&gt;import java.util.Collection;&lt;/span&gt;

&lt;span class="x"&gt;import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;&lt;/span&gt;
&lt;span class="x"&gt;// import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;&lt;/span&gt;
&lt;span class="x"&gt;import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;&lt;/span&gt;
&lt;span class="x"&gt;import org.opendaylight.yang.gen.v1.urn.opendaylight.ping.rev130911.PingService;&lt;/span&gt;
&lt;span class="x"&gt;import org.opendaylight.yangtools.yang.binding.RpcService;&lt;/span&gt;
&lt;span class="x"&gt;import org.osgi.framework.BundleContext;&lt;/span&gt;

&lt;span class="x"&gt;public class PingProvider extends AbstractBindingAwareProvider {&lt;/span&gt;

&lt;span class="x"&gt;    PingImpl pingImpl;&lt;/span&gt;

&lt;span class="x"&gt;    public PingProvider() {&lt;/span&gt;
&lt;span class="x"&gt;        pingImpl = new PingImpl();//构造实例&lt;/span&gt;
&lt;span class="x"&gt;    }&lt;/span&gt;

&lt;span class="x"&gt;    @Override&lt;/span&gt;
&lt;span class="x"&gt;    public Collection&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;RpcService&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;getImplementations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;Override&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;ProviderFunctionality&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;getFunctionality&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;Override&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;onSessionInitiated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ProviderContext&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addRpcImplementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PingService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pingImpl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="c1"&gt;//注册服务&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;Override&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;startImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BundleContext&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这一步我们完成了activator和implementation。完成了服务的实现和注册。然后编译工程：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mvn&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;将生成的jar文件复制到plugins目录&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="sr"&gt;/ping.plugin-0.4.0-SNAPSHOT.jar ../&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="sr"&gt;/distribution/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/target/&lt;/span&gt;&lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;osgipackage&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.4.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SNAPSHOT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;测试&lt;/h4&gt;
&lt;p&gt;以上的步骤已经完成了YANG定义model,以及服务生产者的实现。我们可以通过自动生成的RESTAPI去调用send-echo RPC。可使用curl进行测试，命令如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Content-Type:application/json&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="n"&gt;admin:admin&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;{input:{destination:127.0.0.1}}&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost:8080&lt;/span&gt;&lt;span class="sr"&gt;/restconf/o&lt;/span&gt;&lt;span class="n"&gt;perations&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ping:send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其中destination的值可换成任意你想要ping的地址。&lt;/p&gt;
&lt;p&gt;如果ping成功将会返回&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;output&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;echo-result&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;reachable&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;否则返回其他。&lt;/p&gt;
&lt;h3&gt;第三步 通过REST API使用Ping RPC&lt;/h3&gt;
&lt;p&gt;接下来的部门将介绍如何为ping model构造消费者（以上的provider是生产者）,然后为这个消费者实现一个REST API.&lt;/p&gt;
&lt;h4&gt;Ping service&lt;/h4&gt;
&lt;p&gt;为了让北向接口和YANG model解耦，我们使用Ping service来连接ping plugin和Ping northbound。所以我们还需要构建一个作为osgi bundle的maven工程，构建目录在controller/opendaylight/ping&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="sr"&gt;/src/m&lt;/span&gt;&lt;span class="n"&gt;ain&lt;/span&gt;&lt;span class="sr"&gt;/java/o&lt;/span&gt;&lt;span class="n"&gt;rg&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/co&lt;/span&gt;&lt;span class="n"&gt;ntroller&lt;/span&gt;&lt;span class="sr"&gt;/ping/s&lt;/span&gt;&lt;span class="n"&gt;ervice&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="sr"&gt;/src/m&lt;/span&gt;&lt;span class="n"&gt;ain&lt;/span&gt;&lt;span class="sr"&gt;/java/o&lt;/span&gt;&lt;span class="n"&gt;rg&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/co&lt;/span&gt;&lt;span class="n"&gt;ntroller&lt;/span&gt;&lt;span class="sr"&gt;/ping/s&lt;/span&gt;&lt;span class="n"&gt;ervice&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;impl&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;每一个maven项目，我们都需要有一个pom.xml文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;pom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在pom.xml中，我们需要指明这个bundle的activator(osgi的每一个bundle都有activator，用于启动。详情请google),同时，还需要暴露出plugin service 接口，以便其他的bundle使用，比如Ping northbound。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
  &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;commons.opendaylight&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.4.2-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;relativePath&amp;gt;&lt;/span&gt;../../commons/opendaylight&lt;span class="nt"&gt;&amp;lt;/relativePath&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;ping.service&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;bundle&lt;span class="nt"&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.felix&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-bundle-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;extensions&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;instructions&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Import&lt;/span&gt;&lt;span class="err"&gt;-Package&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              org.opendaylight.yang.gen.v1.urn.opendaylight.ping.rev130911,
              org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
              org.opendaylight.yangtools.yang.common,
              org.opendaylight.yangtools.yang.binding,
              org.opendaylight.controller.sal.binding.api,
              org.osgi.framework
            &lt;span class="nt"&gt;&amp;lt;/Import-Package&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Export&lt;/span&gt;&lt;span class="err"&gt;-Package&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;org.opendaylight.controller.ping.service.api&lt;span class="nt"&gt;&amp;lt;/Export-Package&amp;gt;&lt;/span&gt;#导出api包
            &lt;span class="nt"&gt;&amp;lt;Bundle&lt;/span&gt;&lt;span class="err"&gt;-Activator&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;org.opendaylight.controller.ping.service.impl.PingServiceImpl&lt;span class="nt"&gt;&amp;lt;/Bundle-Activator&amp;gt;&lt;/span&gt;  #activator的指明
          &lt;span class="nt"&gt;&amp;lt;/instructions&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;manifestLocation&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;/META-INF&lt;span class="nt"&gt;&amp;lt;/manifestLocation&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.osgi&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;org.osgi.core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller.model&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;model-ping&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sal-binding-api&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.yangtools&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;yang-common&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;yangtools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.yangtools&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;yang-binding&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;yangtools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成pom.xml之后，我们需要开始定义ping service的接口和实现。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="sr"&gt;/org/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/controller/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="sr"&gt;/service/&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;PingServiceAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;ping service的接口非常简单。参数为传入的目标地址，返回会boolean类型，表明是否可达。具体如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;package&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt; &lt;span class="n"&gt;PingServiceAPI&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="o"&gt;/**&lt;/span&gt;
     &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pingDestination&lt;/span&gt;
     &lt;span class="o"&gt;*&lt;/span&gt;
     &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;@param&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="n"&gt;An&lt;/span&gt; &lt;span class="n"&gt;IPv4&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;pinged&lt;/span&gt;
     &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;@return&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;reachable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;unreachable&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="n"&gt;occurs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
     &lt;span class="o"&gt;*/&lt;/span&gt;
    &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;pingDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成接口定义之后，我们还需要实现接口。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="sr"&gt;/org/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/controller/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="sr"&gt;/service/im&lt;/span&gt;&lt;span class="n"&gt;pl&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;PingServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这里的PingServiceImpl类继承了AbstractBindingAwareConsumer类。在AbstractBindingAwareConsumer类中提供了回调函数，以osgi启动bundle。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;（这个重要的类所属的目录为：controller/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api。着这个目录中有非常重要的类如BindingAwareBroker.java。在后续的教程中将重点分析次目录。）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在onSessionInitialized方法中，'ConsumerContext'被存储等待后续使用。而startImpl方法则是调用了register函数，将bundle注册到了osgi平台。pingDestination方法首先寻找是否存在ping service 的RPC调用。如存在则继续使用ping.recv130911b包内的SendEchoInput类构建input,然后调用ping plugin中的sendEcho，返回的SendEchoOutput字符串映射成boolean值，返回调用者。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;package&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;impl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecutionException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingServiceAPI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AbstractBindingAwareConsumer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindingAwareBroker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConsumerContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindingAwareConsumer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ietf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ietf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev100924&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ipv4Address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev130911&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev130911&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEchoInputBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev130911&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEchoOutput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yangtools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RpcResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;osgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BundleActivator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;osgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BundleContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;PingServiceImpl&lt;/span&gt; &lt;span class="n"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AbstractBindingAwareConsumer&lt;/span&gt; &lt;span class="n"&gt;implements&lt;/span&gt;
        &lt;span class="n"&gt;BundleActivator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BindingAwareConsumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PingServiceAPI&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;PingService&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;ConsumerContext&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;@Override&lt;/span&gt;
    &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;onSessionInitialized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConsumerContext&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;@Override&lt;/span&gt;
    &lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;startImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BundleContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;registerService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingServiceAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;@Override&lt;/span&gt;
    &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;pingDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRpcService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

                &lt;span class="sr"&gt;/* No ping service found. */&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;Ipv4Address&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Ipv4Address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;SendEchoInputBuilder&lt;/span&gt; &lt;span class="n"&gt;ib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SendEchoInputBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;ib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;RpcResult&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;SendEchoOutput&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendEcho&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getResult&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getEchoResult&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;Reachable:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;Unreachable:&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;Error:&lt;/span&gt;
            &lt;span class="n"&gt;default:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;ie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExecutionException&lt;/span&gt; &lt;span class="n"&gt;ee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成以上内容之后，对bundle使用mvn进行编译，并将生成的jar包复制到指定目录。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mvn&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="sr"&gt;/ping.service-1.1-SNAPSHOT.jar ../&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="sr"&gt;/distribution/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/target/&lt;/span&gt;&lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;osgipackage&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SNAPSHOT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Ping Northbound&lt;/h4&gt;
&lt;p&gt;在完成了ping service之后，我们最后还需要构建一个北向API，调用ping service。&lt;/p&gt;
&lt;p&gt;在controller/opendaylight/ping目录在创建northbound目录。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;northbound&lt;/span&gt;&lt;span class="sr"&gt;/src/m&lt;/span&gt;&lt;span class="n"&gt;ain&lt;/span&gt;&lt;span class="sr"&gt;/java/o&lt;/span&gt;&lt;span class="n"&gt;rg&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/co&lt;/span&gt;&lt;span class="n"&gt;ntroller&lt;/span&gt;&lt;span class="sr"&gt;/ping/&lt;/span&gt;&lt;span class="n"&gt;northbound&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;northbound&lt;/span&gt;&lt;span class="sr"&gt;/src/m&lt;/span&gt;&lt;span class="n"&gt;ain&lt;/span&gt;&lt;span class="sr"&gt;/resources/&lt;/span&gt;&lt;span class="n"&gt;META&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;northbound&lt;/span&gt;&lt;span class="sr"&gt;/src/m&lt;/span&gt;&lt;span class="n"&gt;ain&lt;/span&gt;&lt;span class="sr"&gt;/resources/&lt;/span&gt;&lt;span class="n"&gt;WEB&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;northbound&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;同样的为工程添加pom.xml&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;pom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在pom.xml文件中我们需要import Ping service包，以便使用Ping Service。同时，我们也要需要确定许多WEB服务的信息。例如ContextPath,我们定义ContextPath为'/controller/nb/v2',所以我们可以通过HTTP PUT的方式向http://localhost:8080/controller/nb/v2/ping/{ipAddress}发送send ping请求。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;&lt;/span&gt;
 &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
 &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;commons.opendaylight&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.4.2-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;relativePath&amp;gt;&lt;/span&gt;../../commons/opendaylight&lt;span class="nt"&gt;&amp;lt;/relativePath&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;ping.northbound&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;bundle&lt;span class="nt"&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.codehaus.enunciate&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-enunciate-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;enunciate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sal&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.7.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.felix&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-bundle-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;extensions&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;instructions&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Import&lt;/span&gt;&lt;span class="err"&gt;-Package&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              org.opendaylight.controller.ping.service.api,
              org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
              org.apache.commons.logging,
              com.sun.jersey.spi.container.servlet,
              org.opendaylight.controller.northbound.commons,
              org.opendaylight.controller.northbound.commons.exception,
              org.opendaylight.controller.northbound.commons.utils,
              org.opendaylight.controller.sal.utils,
              org.opendaylight.controller.sal.authorization,
              org.opendaylight.controller.sal.packet.address,
              javax.ws.rs,
              javax.ws.rs.core,
              javax.xml.bind.annotation,
              javax.xml.bind,
              org.slf4j,
              org.apache.catalina.filters,
              com.fasterxml.jackson.jaxrs.base,
              com.fasterxml.jackson.jaxrs.json,
              !org.codehaus.enunciate.jaxrs
            &lt;span class="nt"&gt;&amp;lt;/Import-Package&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Web&lt;/span&gt;&lt;span class="err"&gt;-ContextPath&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;/controller/nb/v2&lt;span class="nt"&gt;&amp;lt;/Web-ContextPath&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/instructions&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;manifestLocation&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;/src/main/resources/META-INF&lt;span class="nt"&gt;&amp;lt;/manifestLocation&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller.thirdparty&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;com.sun.jersey.jersey-servlet&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.17&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;commons.northbound&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.4.2-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.codehaus.enunciate&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;enunciate-core-annotations&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;enunciate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller.thirdparty&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;org.apache.catalina.filters.CorsFilter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;7.0.42&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;ping.service&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;接下来我们创建enunciate.xml。什么是enunciate?  http://enueciate.codehaus.org&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;enunciate&lt;/span&gt; &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;full&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
    &lt;span class="na"&gt;xsi:noNamespaceSchemaLocation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://enunciate.codehaus.org/schemas/enunciate-1.26.xsd&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;services&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;rest&lt;/span&gt; &lt;span class="na"&gt;defaultRestSubcontext=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/controller/nb/v2/ping&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/services&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;modules&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;docs&lt;/span&gt; &lt;span class="na"&gt;docsDir=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rest&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Ping REST API&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;includeExampleXml=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;includeExampleJson=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/modules&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/enunciate&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;最后我们还需要配置web.xml&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="sr"&gt;/WEB-INF/&lt;/span&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;web.xml可以从其他类似的北向的项目中复制，然后修改。在servlet标签中声明：JAXRSPing,对应到param-value中的PingNorthboundRSApplication。我们将马上实现这个文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;ISO-8859-1&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;web-app&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://java.sun.com/xml/ns/javaee&amp;quot;&lt;/span&gt;
 &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
 &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://java.sun.com/xml/ns/javaee&lt;/span&gt;
&lt;span class="s"&gt; http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&amp;quot;&lt;/span&gt;
 &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;3.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;servlet&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;JAXRSPing&lt;span class="nt"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;servlet-class&amp;gt;&lt;/span&gt;com.sun.jersey.spi.container.servlet.ServletContainer&lt;span class="nt"&gt;&amp;lt;/servlet-class&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;javax.ws.rs.Application&lt;span class="nt"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;org.opendaylight.controller.ping.northbound.PingNorthboundRSApplication&lt;span class="nt"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;load-on-startup&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/load-on-startup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/servlet&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;servlet-mapping&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;JAXRSPing&lt;span class="nt"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/*&lt;span class="nt"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;filter&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;filter-name&amp;gt;&lt;/span&gt;CorsFilter&lt;span class="nt"&gt;&amp;lt;/filter-name&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;filter-class&amp;gt;&lt;/span&gt;org.apache.catalina.filters.CorsFilter&lt;span class="nt"&gt;&amp;lt;/filter-class&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;cors.allowed.origins&lt;span class="nt"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;cors.allowed.methods&lt;span class="nt"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;GET,POST,HEAD,OPTIONS,PUT&lt;span class="nt"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;cors.allowed.headers&lt;span class="nt"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;Content-Type,X-Requested-With,accept,authorization, origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers&lt;span class="nt"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;cors.exposed.headers&lt;span class="nt"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;Access-Control-Allow-Origin,Access-Control-Allow-Credentials&lt;span class="nt"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;cors.support.credentials&lt;span class="nt"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;cors.preflight.maxage&lt;span class="nt"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;10&lt;span class="nt"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;filter-mapping&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;filter-name&amp;gt;&lt;/span&gt;CorsFilter&lt;span class="nt"&gt;&amp;lt;/filter-name&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/*&lt;span class="nt"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/filter-mapping&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;security-constraint&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;web-resource-collection&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;web-resource-name&amp;gt;&lt;/span&gt;NB api&lt;span class="nt"&gt;&amp;lt;/web-resource-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/*&lt;span class="nt"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;http-method&amp;gt;&lt;/span&gt;POST&lt;span class="nt"&gt;&amp;lt;/http-method&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;http-method&amp;gt;&lt;/span&gt;GET&lt;span class="nt"&gt;&amp;lt;/http-method&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;http-method&amp;gt;&lt;/span&gt;PUT&lt;span class="nt"&gt;&amp;lt;/http-method&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;http-method&amp;gt;&lt;/span&gt;PATCH&lt;span class="nt"&gt;&amp;lt;/http-method&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;http-method&amp;gt;&lt;/span&gt;DELETE&lt;span class="nt"&gt;&amp;lt;/http-method&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;http-method&amp;gt;&lt;/span&gt;HEAD&lt;span class="nt"&gt;&amp;lt;/http-method&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/web-resource-collection&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;auth-constraint&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;System-Admin&lt;span class="nt"&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;Network-Admin&lt;span class="nt"&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;Network-Operator&lt;span class="nt"&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;Container-User&lt;span class="nt"&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/auth-constraint&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/security-constraint&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;security-role&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;System-Admin&lt;span class="nt"&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/security-role&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;security-role&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;Network-Admin&lt;span class="nt"&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/security-role&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;security-role&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;Network-Operator&lt;span class="nt"&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/security-role&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;security-role&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;Container-User&lt;span class="nt"&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/security-role&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;login-config&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;auth-method&amp;gt;&lt;/span&gt;BASIC&lt;span class="nt"&gt;&amp;lt;/auth-method&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;realm-name&amp;gt;&lt;/span&gt;opendaylight&lt;span class="nt"&gt;&amp;lt;/realm-name&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/login-config&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/web-app&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;完成xml文件之后，我们首先需要完成源文件PingNorthboundRSApplication.java&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="sr"&gt;/org/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/controller/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="sr"&gt;/northbound/&lt;/span&gt;&lt;span class="n"&gt;PingNorthboundRSApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个文件将PingNorthbound作为一个web service app。当REST 调用对应URI的资源时将被调用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="x"&gt;package org.opendaylight.controller.ping.northbound;&lt;/span&gt;

&lt;span class="x"&gt;import java.util.HashSet;&lt;/span&gt;
&lt;span class="x"&gt;import java.util.Set;&lt;/span&gt;

&lt;span class="x"&gt;import javax.ws.rs.core.Application;&lt;/span&gt;

&lt;span class="x"&gt;public class PingNorthboundRSApplication extends Application {&lt;/span&gt;
&lt;span class="x"&gt;    @Override&lt;/span&gt;
&lt;span class="x"&gt;    public Set&amp;lt;Class&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;getClasses&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PingNorthbound&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在PingNorthbound文件中应用的实例定义为PingNorthbound，所以我们需要实现这个类。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="sr"&gt;/main/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="sr"&gt;/org/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/controller/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="sr"&gt;/northbound/&lt;/span&gt;&lt;span class="n"&gt;PingNorthbound&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;PingNorthnound定义了ping方法，用于相应特定URI路径的资源相应。ping方法会查找ping service的接口和pingDestination的方法，并根据返回值构建HTTP相应。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;package&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;northbound&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;javax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;javax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;javax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PathParam&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;javax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;codehaus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enunciate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jaxrs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;codehaus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enunciate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jaxrs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingServiceAPI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceHelper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;PingNorthbound&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;/**&lt;/span&gt;
     &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Ping&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;
     &lt;span class="o"&gt;*/&lt;/span&gt;
    &lt;span class="nv"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/ping/{ipAddress}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;@PUT&lt;/span&gt;
    &lt;span class="nv"&gt;@StatusCodes&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nv"&gt;@ResponseCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Destination reachable&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nv"&gt;@ResponseCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Internal error&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nv"&gt;@ResponseCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Destination unreachable&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@PathParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;ipAddress&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;ipAddress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;PingServiceAPI&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingServiceAPI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ServiceHelper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getGlobalInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;PingServiceAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="sr"&gt;/* Ping service not found. */&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;No ping service&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pingDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipAddress&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipAddress&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; - reachable&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipAddress&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; - unreachable&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;终于，我们完成了northbound的实现，别忘记对工程进行编译。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mvn&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;还要把对应的jar包复制到plugins目录下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="sr"&gt;/ping.northbound-1.0-SNAPSHOT.jar ../&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="sr"&gt;/distribution/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;&lt;span class="sr"&gt;/target/&lt;/span&gt;&lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;osgipackage&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;northbound&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SNAPSHOT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;测试&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;运行odl，并通过curl测试&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="sr"&gt;/../&lt;/span&gt;&lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="sr"&gt;/distribution.opendaylight-0.1.0-SNAPSHOT-osgipackage/o&lt;/span&gt;&lt;span class="n"&gt;pendaylight&lt;/span&gt;
&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;此时可以输入命令&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ss&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;启动关于ping内容的bundle,可以看到5个内容，其中4个是我们刚刚添加的bundle.再开终端使用curl测试，测试命令和结果如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="n"&gt;PUT&lt;/span&gt; &lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost:8080&lt;/span&gt;&lt;span class="sr"&gt;/controller/&lt;/span&gt;&lt;span class="n"&gt;nb&lt;/span&gt;&lt;span class="sr"&gt;/v2/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt;
&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;reachable&lt;/span&gt;
&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="n"&gt;PUT&lt;/span&gt; &lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost:8080&lt;/span&gt;&lt;span class="sr"&gt;/controller/&lt;/span&gt;&lt;span class="n"&gt;nb&lt;/span&gt;&lt;span class="sr"&gt;/v2/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;128.0.0.1&lt;/span&gt;
&lt;span class="mf"&gt;128.0.0.1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;unreachable&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;到目前位置，我们已经完成了绝大部分的工作！最后我们还需要将工程和整个工程一起编译。&lt;/p&gt;
&lt;h3&gt;最后一步  编译整个工程&lt;/h3&gt;
&lt;p&gt;全部的ping工程都需要作为控制器的一部分进行编译和安装，我们需要通过在pom.xml的修改达到这一目的。&lt;/p&gt;
&lt;p&gt;官网上的教程说的是'sal/yang-prototype/sal/modules'目录，但是新版的控制器并没有这一目录，所以博主努力寻找了一下，在opendylight/md-sal/model下找到了类似的pom.xml。博主认为这就是正确的文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/m&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sal&lt;/span&gt;&lt;span class="sr"&gt;/model/&lt;/span&gt;&lt;span class="n"&gt;pom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;将 &lt;module&gt;model-ping&lt;/module&gt;添加到一下部分中&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; ...
 &lt;span class="nt"&gt;&amp;lt;modules&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;module&amp;gt;&lt;/span&gt;model-inventory&lt;span class="nt"&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;module&amp;gt;&lt;/span&gt;model-flow-base&lt;span class="nt"&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;module&amp;gt;&lt;/span&gt;model-flow-service&lt;span class="nt"&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;module&amp;gt;&lt;/span&gt;model-flow-statistics&lt;span class="nt"&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;module&amp;gt;&lt;/span&gt;model-topology-bgp&lt;span class="nt"&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;module&amp;gt;&lt;/span&gt;model-ping&lt;span class="nt"&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/modules&amp;gt;&lt;/span&gt;
 ...
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;剩下的3个工程同样需要编译，将其加入到对应的pom.xml中。官网给的文件目录是对的，但是内容不对。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;vi&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;pom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;添加内容如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; ...
 &lt;span class="c"&gt;&amp;lt;!-- Ping --&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;ping.northbound&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;   
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;    
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;    
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;ping.plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.4.0-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;   
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;    
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;    
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;ping.service&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt; 
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

 &lt;span class="c"&gt;&amp;lt;!--Southbound bundles--&amp;gt;&lt;/span&gt;
 ...
 ...
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;    
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.opendaylight.controller.model&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;  
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;model.ping&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;   
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- toaster example I&amp;#39;m pretty sure we should trim --&amp;gt;&lt;/span&gt;
...
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;两处修改大概在500+和1000+行处。&lt;/p&gt;
&lt;p&gt;最后编译所有文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;
&lt;span class="n"&gt;mvn&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;运行odl,再次测试，无误！&lt;/p&gt;
&lt;p&gt;官网对应教程：https://wiki.opendaylight.org/view/Ping&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 06 Aug 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-08-06:pages/2014/08/06/opendaylightzhong-kai-fa-mo-kuai-ping.html</guid><category>opendaylight</category><category>SDN</category><category>Ping</category></item><item><title>OpenDaylight入门教程</title><link>http://www.muzixing.com/pages/2014/08/02/opendaylightru-men-jiao-cheng.html</link><description>&lt;h3&gt;关于OpenDaylight&lt;/h3&gt;
&lt;p&gt;OpenDaylight is an open platform for network programmability to enable SDN and create a solid foundation for NFV for networks at any size and scale.&lt;/p&gt;
&lt;p&gt;对于SDN而言，ODL（OpenDaylight）是一个开源的可编程的平台，简单的说是一个非常有野心开源控制器而不仅仅只是控制器。&lt;/p&gt;
&lt;p&gt;opendaylight官网:http://www.opendaylight.org/&lt;/p&gt;
&lt;h3&gt;环境配置&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;jdk需要1.6以上。&lt;/p&gt;
&lt;p&gt;sudo apt-get -y install openjdk-7-jdk&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更多安装信息请查看:https://wiki.opendaylight.org/view/OpenDaylight_Controller:Installation&lt;/p&gt;
&lt;p&gt;或者查看《opendaylight学习及开发初级教程-北邮天依》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;安装maven&lt;/p&gt;
&lt;p&gt;sudo apt-get install maven&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;下载与安装&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;https:&lt;/span&gt;&lt;span class="sr"&gt;//gi&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="sr"&gt;/gerrit/&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;编译&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Controller:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt;   &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="sr"&gt;/opendaylight/&lt;/span&gt;&lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;
&lt;span class="n"&gt;mvn&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;执行&lt;/p&gt;
&lt;p&gt;cd controller/opendaylight/distribution/opendaylight/target/distribution.opendaylight-OSGIpackage/opendaylight
./run.sh&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;maven&lt;/h3&gt;
&lt;p&gt;opendaylight的工程是基于osgi的maven工程。使用maven对odl进行编译，并运行osgi架构。&lt;/p&gt;
&lt;p&gt;opendaylight的文件目录是maven标准目录。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;src/main/java: Application/Library sources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;src/main/resources:Application/Library resources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;src/main/filters: Resource filter files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;src/main/assembly: Assembly descriptors&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;src/main/config: Configuration files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;src/main/webapp: Web application sources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;src/test/java: Test sources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;src/test/resources: Test resources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;src/test/filters: Test resource filter files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;src/site: Site&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LICENSE.txt: Project's license&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;README.txt: Project's readme&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中pom.xml是非常重要文件，是maven工程的核心文件，是maven的项目对象模型。用于描述资源，包括版本号，依赖关系，资源url等信息。&lt;/p&gt;
&lt;p&gt;其中每一个工程由的3个坐标定位：groupId:artifactId:version定位。在ODL中groupId可以是：org.opendaylight.controller&lt;/p&gt;
&lt;p&gt;artifactId可以是controller的一个模块名如：hosttracker.&lt;/p&gt;
&lt;h3&gt;OSGI&lt;/h3&gt;
&lt;p&gt;ODL的每一个maven文件都是OSGI的一个bundle，需要在OSGI中注册使用。更多信息可查看：http://www.opendaylight.org/project/technical-overview&lt;/p&gt;
&lt;p&gt;我们使用mvn clean install 编译完ODL之后，进入生成的target目录（前面有介绍）找到opendaylight目录下的run.sh（linux下为.sh,windows下为.bat）,并运行，实际上就是运行了osgi框架。然后osgi根据项目的pom.xml把相关的bundle注册运行。&lt;/p&gt;
&lt;h3&gt;OpenDayLight目录简介&lt;/h3&gt;
&lt;p&gt;&lt;img alt="opendaylight" src="http://www.opendaylight.org/sites/www.opendaylight.org/files/pages/images/odp_ds_ltr_diagram.png" /&gt;&lt;/p&gt;
&lt;p&gt;本图来自：http://www.opendaylight.org&lt;/p&gt;
&lt;p&gt;从上图可以看出ODL从层次上可分为三层:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;南向接口和协议插件&lt;/li&gt;
&lt;li&gt;控制器平台&lt;/li&gt;
&lt;li&gt;网络应用 业务和服务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此处主要介绍ODL中controller各目录主要功能。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;——&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;
    &lt;span class="err"&gt;——&lt;/span&gt;&lt;span class="n"&gt;features&lt;/span&gt;
    &lt;span class="err"&gt;——&lt;/span&gt;&lt;span class="n"&gt;opendaylight&lt;/span&gt;  &lt;span class="c1"&gt;#主文件 包含各个模块的源文件&lt;/span&gt;
    &lt;span class="err"&gt;——&lt;/span&gt;&lt;span class="n"&gt;third&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;party&lt;/span&gt;    
    &lt;span class="err"&gt;——&lt;/span&gt;&lt;span class="n"&gt;itest&lt;/span&gt;    
    &lt;span class="err"&gt;——&lt;/span&gt;&lt;span class="n"&gt;LICENSE&lt;/span&gt;
    &lt;span class="err"&gt;——&lt;/span&gt;&lt;span class="n"&gt;NOTICE&lt;/span&gt;
    &lt;span class="err"&gt;——&lt;/span&gt;&lt;span class="n"&gt;README&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OPENDAYLIGHT&lt;/span&gt;
    &lt;span class="err"&gt;——&lt;/span&gt;&lt;span class="n"&gt;pom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;  &lt;span class="c1"&gt;#maven文件对象模型，用于描述项目如何工作。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在opendaylight中有ODL的模块源文件，各目录的功能简介如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;appauth:关于app授权，定义 abstract class Authrization &lt;/li&gt;
&lt;li&gt;archetypes:工程使用的maven的archetype&lt;/li&gt;
&lt;li&gt;arphandler:用于处理arp数据&lt;/li&gt;
&lt;li&gt;forwarding:静态路由&lt;/li&gt;
&lt;li&gt;forwardrulesmanager:管理流表数据和转发规则&lt;/li&gt;
&lt;li&gt;connectionmanager:交换机连接管理：单一，集群，轮询，负载均衡，VTN等连接管理。&lt;/li&gt;
&lt;li&gt;containermanager:VTN管理，每一个VTN对应一个container&lt;/li&gt;
&lt;li&gt;clustering:控制器集群&lt;/li&gt;
&lt;li&gt;commons:公共信息&lt;/li&gt;
&lt;li&gt;hosttracker（new）:主机发现，管理，追踪&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;md-sal:&lt;/p&gt;
&lt;p&gt;Model-driven approach to service abstraction presents an opportunity to unify both northbound and southbound APIs and the data structures used in various services and components of an SDN Controller.
MD-SAL使得在SDN控制器那些丰富的服务和模块可以使用统一的数据结构和南向和北向的API。&lt;/p&gt;
&lt;p&gt;In order to describe the structure of data provided by controller components a domain-specific language, YANG, is proposed as the modeling language for service and data abstractions. Such language allows to:&lt;/p&gt;
&lt;p&gt;为了描述控制器组件提供的数据结构，我们使用一种领域专门的语言YANG作为服务和数据抽象的建模语言。&lt;/p&gt;
&lt;p&gt;—— Modeling the structure of XML data and functionality provided by controller components&lt;/p&gt;
&lt;p&gt;—— Define sem
antic elements and their relationships&lt;/p&gt;
&lt;p&gt;—— Model all the components as a single system.&lt;/p&gt;
&lt;p&gt;The XML nature of YANG data model presents an opportunity for self-describing data, which controller components and applications using the controller’s northbound APIs can consume in a raw format, along with the data’s schema.&lt;/p&gt;
&lt;p&gt;Utilizing a schema language simplifies development of controller components and application. A developer of a module that provides some functionality (a service, data, functions/procedure) can define a schema and thus create simpler, statically typed APIs for the provided functionality, and thus lower the risk of incorrect interpretation of data structures exposed through the Service Abstraction Layer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;northbound:北向相关（控制器管理，HTTP,web UI,统计，子网，交换机管理，用户管理，网络配置，静态路由，流表编程，主机管理，连接管理等组建的北向接口）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;protocol_plugins:协议插件（openflow,拓扑）&lt;/li&gt;
&lt;li&gt;routing:Dijkstra算法实现&lt;/li&gt;
&lt;li&gt;sal:（最重要的文件之一！）服务抽象层，action，match等功能抽象&lt;/li&gt;
&lt;li&gt;samples:例子（流聚合，负载均衡，二三层转发等）&lt;/li&gt;
&lt;li&gt;security：安全相关&lt;/li&gt;
&lt;li&gt;statisticsmanager:统计模块接口&lt;/li&gt;
&lt;li&gt;switchmanager:交换机管理&lt;/li&gt;
&lt;li&gt;usermanager:用户管理（接口和实现）&lt;/li&gt;
&lt;li&gt;web：web UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其他目录不再介绍。&lt;/p&gt;
&lt;h3&gt;Opendaylight模块开发&lt;/h3&gt;
&lt;p&gt;在ODL中开发模块需要掌握：YANG,XML,MAVEN,JAVA,RESTAPI，等多项知识。每一个模块基本上可以由四个bundle联合实现功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建model bundle,使用YANG描述数据结构，和RPC调用&lt;/li&gt;
&lt;li&gt;创建plugin bundle 用于插件的具体实现，实现model的声明&lt;/li&gt;
&lt;li&gt;创建service bundle 提供连接北向实现和南向的MD-SAL定义的服务&lt;/li&gt;
&lt;li&gt;创建northbound bundle 用于提供北向的接口和实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更具体的操作将在下一篇教程&lt;opendaylight开发ping模块&gt;中详细介绍如何一步一步在ODL中开发模块。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sat, 02 Aug 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-08-02:pages/2014/08/02/opendaylightru-men-jiao-cheng.html</guid><category>SDN OpenDaylight</category></item><item><title>【python爬虫】抓取淘宝模特图片——20分钟爬虫之旅</title><link>http://www.muzixing.com/pages/2014/07/24/pythonpa-chong-zhua-qu-tao-bao-mo-te-tu-pian-20fen-zhong-pa-chong-zhi-lu.html</link><description>&lt;h1&gt;前言&lt;/h1&gt;
&lt;p&gt;很多人说学Python最终需要写一个爬虫才能算是学成出山了，而我就是那个留级生，一直没有写过。炎热的夏日，以及看java的抑郁，让我无聊之中萌生了这个想法。于是在百度的帮助下，写完了这个教程。视频教程可以去百度学堂看，我就是在那里看的。&lt;/p&gt;
&lt;h1&gt;spider&lt;/h1&gt;
&lt;p&gt;代码详解就不多加介绍，注释相信已经很明确了，请看代码。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib2&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;get_mm_pic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;page_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page_num&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mmurl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;http://mm.taobao.com/json/request_top_list.htm?type=0&amp;amp;page=&amp;quot;&lt;/span&gt;&lt;span class="c1"&gt;#抓取的链接&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_pic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;page_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page_num&lt;/span&gt;
    &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&amp;#39;&amp;lt;img src=&amp;quot;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;page_num:&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mmurl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cont&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="c1"&gt;#读取页面内容&lt;/span&gt;
        &lt;span class="n"&gt;pa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;True:&lt;/span&gt;
            &lt;span class="n"&gt;ahref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&amp;#39;&amp;lt;a href=&amp;quot;http&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
            &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;target&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;pa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cont&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ahref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#匹配字符串&lt;/span&gt;
            &lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cont&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pa&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;break&lt;/span&gt;
            &lt;span class="n"&gt;modelurl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cont&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ahref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;mup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modelurl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;mcont&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;lt;img style&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;.jpg&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;iph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;True:&lt;/span&gt;
                &lt;span class="n"&gt;iph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mcont&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;ipj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mcont&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;iph&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;#匹配失败则跳出循环&lt;/span&gt;
                    &lt;span class="n"&gt;break&lt;/span&gt;
                &lt;span class="n"&gt;mpic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mcont&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;iph&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ipj&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
                &lt;span class="n"&gt;ips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mpic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;src&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;urlpic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mpic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ips&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;src =&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):]&lt;/span&gt;
                &lt;span class="n"&gt;try:&lt;/span&gt;
                    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;gt;&amp;gt;&amp;gt;downloading : lady_p&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_no_&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_pic_&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.jpg......&amp;quot;&lt;/span&gt;
                    &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlretrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlpic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;lady_p&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_no_&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_pic_&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.jpg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#下载图片&lt;/span&gt;
                &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;KeyboardInterrupt:&lt;/span&gt;
                    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;SIGINT, exit...&amp;quot;&lt;/span&gt;
                    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;except:&lt;/span&gt;
                    &lt;span class="n"&gt;pass&lt;/span&gt;
                &lt;span class="n"&gt;mcont&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mcont&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ipj&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
                &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;cont&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cont&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
            &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;gt;&amp;gt;&amp;gt;download completed&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;get_mm_pictures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_mm_pic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;@Author:www.muzixing.com&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;get_mm_pictures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_pic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="c1"&gt;#python spider.py number&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;就是这么一个简单的40+行，就可以将淘女郎大量的图片下载下来了。好好欣赏吧！技术能让生活更有趣！&lt;/p&gt;
&lt;h1&gt;后语&lt;/h1&gt;
&lt;p&gt;如果你还有什么好玩的Python项目，可以告诉我，我也想学！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 24 Jul 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-07-24:pages/2014/07/24/pythonpa-chong-zhua-qu-tao-bao-mo-te-tu-pian-20fen-zhong-pa-chong-zhi-lu.html</guid><category>python</category><category>spider</category></item><item><title>关于这个世界的思考</title><link>http://www.muzixing.com/pages/2014/07/14/guan-yu-zhe-ge-shi-jie-de-si-kao.html</link><description>&lt;h2&gt;宇宙的位置&lt;/h2&gt;
&lt;p&gt;我时常在想地球作为一个行星在太阳系中，而太阳系作为一个星系在银河系中这种情况和电子围绕原子运转，而不同的原子组成一个微观世界一样。从而我得出结论，在某种意义上，微观世界和宏观的宇宙遵循着同样的物理原理。这一点也可以由万有引力得以印证。当然这种认识是非常肤浅的！仅仅是感官上的认识。没有太大的根据。&lt;/p&gt;
&lt;p&gt;那么如果我们的宏观作为另一个更大的世界的微观，那么我们就成为了别人世界的原子和电子。依次类推，我们的世界可能是很多重世界中的一个环节。但是我们本身并不能看到这个层次。就像假如我们是生存在电子上的生物，而他们的一生，或者从这个种族有意识，有记录的历史环节中都无法和这个原子以及这个原子周边的世界发生交集。当发生交集的时候，很可能就是毁灭的一刻。所以在他们的意识形态中，他们的世界就是这个电子，或者更大一点的范围。但是他们无法意识到他们是组成宏观世界材料的一个极其普通以及微小到甚至宏观世界的概念里很长一段时间没有他们的存在。所以他们就生存在他们认为的全世界中，安然繁衍。不知道当某一天电子上的生物得知自己在这个世界中是那么微小，稍有不慎，整个电子星球就毁灭，而他们却完全没有还手之力的时候，会不会充满恐惧。当然我觉得在那样的世界里面，时间也应当和空间一样，需要用非常细小的粒度去衡量，举个不恰当的例子，比如飞秒是他们世界的秒。那么我们就可以想象一个围观的世界上面，时间和空间都浓缩的空间里，有另一个小世界存在。而他们的意识中他们的世界是很大的，正如我们意识中的一样。&lt;/p&gt;
&lt;p&gt;从另一个角度看。如果我们这个世界是外面“大世界”的一个微小到根本看不见的存在。那么也可以理解。在他们的很长一段时间之内，他们也无法认识到由许多我们这样的世界组成的系统构成了他们世界中的组基础的材料如我们世界中的碳或者铁等元素。所以他们的生活中大体是在宏观上对由我们这些微观世界组成的材料进行处理，而没有深入到我们世界的粒度去探寻，直到某一天，就像某一天我们发现可以操纵原子，质子，中子发生核聚变核裂变等。也许他们也像我们一样停留在并不能了解到微观世界的具体层面上。这样，两个不同量级的世界就很安然地隔离开来了。同样，在那样的世界中，可能存在一些我们无法理解的巨大到比我们宇宙还要大的生物，而我们原来就是组成那种生物的最核心的组成部分，那么我们肯定是我们感受到这样的存在的。就像我们身体内的碳元素上的生物永远也无法认识到他们组成了一个非常庞大的生物，因为他们的世界里面看不到这么大的世界。&lt;/p&gt;
&lt;p&gt;解决了一个世界最根本的物质的来源，可以想象有非常大的可能存在一个有序的，有他们意识形态下的文明存在。那么我觉得我们的宇宙在整个所谓的世界中的位置并不十分确定。但是在我们意识形态中，我们的宇宙几乎就是全世界。&lt;/p&gt;
&lt;p&gt;有时候我在想，如果某一天我们发现我们的世界是一个大世界的微小组合，而我们的命运在大世界的意识形态中并不具有意识，也就是说我们无法进行自我防御，或者我们的自我防御的量级，完全不能再那个大世界中产生影响，那么我们只有接受大世界宰割的命运。那个时候我们会不会特别恐慌呢？但是仔细一想估计也不会。因为同样的大世界中的时间度量也必将是我们世界中无法想象的度量值。也许我们的世纪是他们的飞秒级别甚至更小。也就是说，当我们出于一种安全状态时，我们可以繁衍无数代，而大世界的时间甚至才走过了一个毫秒，甚至来不及发生任何的动作。而当我们意识到我们的世界即将接受外界的强烈打击而无法还手时，这个星球就会毁灭，关于他的所以的意识形态，文明都会在黑暗的宇宙中毁灭。如果没有人知道曾经有这么样的文明存在，也就不会有那样的悲伤了。所以想想，如果我们的世界是那样的，其实，我想应该是不需要恐慌的。而且这些假设都是我胡思乱想的。&lt;/p&gt;
&lt;h2&gt;关于外星人&lt;/h2&gt;
&lt;p&gt;关于外星人，我想是肯定有的。&lt;/p&gt;
&lt;p&gt;但是我们的意识形态决定我们始终在寻找和我们一样的生物，或者生存在我们同样的频率，同样的物质环境下的生物，甚至更狭隘的寻找同样意识形态的生物。因为所有的一切都是出于我们的意识形态。&lt;/p&gt;
&lt;p&gt;但是有时候我就在想,我们认为的高频率被我们用于通信。那么如果，存在这么一种生物他们的通信频率和我们的通信频率没有交集，那么我们就完全无法得知他们的存在。比如某个外星生物之间使用超级低的频率在交流，他们的频率可能是0.1HZ以至于我们完全无法感知到。当然这样的生物可能比较庞大，通信距离也比较远。也许有的生物使用极其高的频率在通信，而他们体积比较小，信号很快就衰减掉了。等等，我觉得都是有可能的。关于通信方面如果能想象可能存在很多“外星人”使用的频率不同，那么外星人就会有很多种存在形态了。&lt;/p&gt;
&lt;p&gt;另一方面，我们的意识形态决定了我们对外星人的定义可能是：会动的，和人差不多比例，有五官，有四肢。当然这也可能是因为我本身看的科幻电影中都是这样描述的。大家不一定这样认为。但是如果在一个世界中，他们不需要空气，或者他们呼吸的是痰气，或者其他的其他，甚至我们没有见过的，那么他们没有呼吸系统，或者存在一个我们无法想象的呼吸系统也是可以理解的。&lt;/p&gt;
&lt;p&gt;如果他们行动缓慢，但是社会竟然有序，因为他们的时间度量极其的大，我们完全观察不出来，那么我们也无法理解这是一种生物。如果他们行动迅速，以至于我们肉眼无法停留地得到他们的反射光，那么我们意识形态中就不会出现这样的东西。如一个有许多元素组成的生物，但是他在以极高的频率在运动，人可能根本无法在大脑中留下印象的情况下，他始终存在，那么我们就无法获得他们的存在，但是他们确实存在。&lt;/p&gt;
&lt;p&gt;如果他们生活所需的温度很高或者很低，远超出我们人生生存说需要的范围，那么我们无法理解他们是什么机理，也无法寻找到他们的存在，因为没有人会去太阳上寻找生命的。因为我们会觉得那么高的温度已经不可能有生物存在，而且我们也无法或者到达那样的地方。但是这都是我么意识形态中的生物，不是广义上的生物。那么有耐高温或者耐低温的生物也是可以理解的了。&lt;/p&gt;
&lt;p&gt;如果像我说的这样，那么“外形人”的定义就太广泛了。他可能不需要呼吸，不需要水，他们可能吃的就是石油或者土壤，或者我们不知道的物质，这都是有可能的。就像加入他们呼吸痰气，不需要水，就无法理解为什么在我们的世界我们需要氧气和水一样。物质形态的不同决定了需求不同，抱着开放的思想，我可以认同有的外星人是不需要水，不需要氧气，等我们地球人所需要的生存基础。那么存在外星人就太正常了。但是这样的外星人往往无法被正常人所接受，当然目前为止，还没有发现这样的存在没有让我们的世界发生混乱。也可以说，发生混乱了，而我们并无法发现他们的存在。反过来，很可能他们的世界里也无法想象我们的存在。也就是说，我所说的这些超乎常理的外星人，就像我们无法意识到他们的存在一样，他们也无法意识到我们的存在，于是两个世界就在这样的平静中各自发展。&lt;/p&gt;
&lt;p&gt;但是目前位置，我们所要寻找的外星人都是我们意识形态中的外星人。我觉得一方面是受困于我们的意识形态，另一方面，假使我们能突破我们的意识形态，找到存在，那么对于我们来说可能并没有太多的帮助，反而可能会徒增许多恐慌。同时，寻找类似于我们的存在的最大目的是寻找资源，寻找种族下一个繁衍的星球。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;写到这里，我发现了许多逻辑漏洞，也发现了许多没有必要担心的东西。比如关于外星人中的描述。如果他们生存在我们无法感知的世界中，那么反过来，他们应该也无法感知我们才对。如果他们有能力对我们这个世界有所感知而有所作为，同时又可以避免人类感知，那么我们做什么都是没有用的。这些东西，在远古时代就存在，人们称之为神或者鬼。但是具有相对于我们来说的超能力，那么我们也无能为力。幸亏，目前位置，一切都是安全的。所谓的神或者鬼，更好的理解是当一个生物需要一个信仰或者心理安慰时，一个可以寄托情怀和罪恶的神或者鬼是最好不过的了。&lt;/p&gt;
&lt;p&gt;关于这个世界的思考，都是些平时在脑海里乱七八糟的想法，我相信不是我一个人有这样的想法。我也相信，我的想法绝对是有很多漏洞的。但是写出来，也许能找到和我想的一样的人呢。也许，我想的是对的呢。哈哈!欢迎在评论中对我们的错误进行批评指出！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Mon, 14 Jul 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-07-14:pages/2014/07/14/guan-yu-zhe-ge-shi-jie-de-si-kao.html</guid><category>胡思乱想</category></item><item><title>nox实现nat功能</title><link>http://www.muzixing.com/pages/2014/05/04/noxshi-xian-natgong-neng.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;nat功能是一个非常简单，但却非常重要的功能。保留10，127,192三个网段作为公网地址，通过nat实现地址复用，可以解决现网IPV4地址不够用的尴尬局面。本篇主要讲如何使用nox实现nat的demo.&lt;/p&gt;
&lt;h3&gt;环境&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;nox  安装比较困难，请参看其他教程&lt;/li&gt;
&lt;li&gt;mininet    网络环境搭建神器&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;控制器&lt;/h3&gt;
&lt;p&gt;首先在nox/src/coreapps/switch中找到switch.cc。
在class switch中添加成员变量uint32_t src_ip，nat_ip；由于只是一个简单的demo，就不做映射列表了。&lt;/p&gt;
&lt;p&gt;handle_packet_in中将if(setup_flows &amp;amp;&amp;amp; out_port!=-1)的逻辑修改如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setup_flows&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;fm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;v1::&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_mod&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
               &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;v1::ofp_flow_mod::&lt;/span&gt;&lt;span class="n"&gt;OFPFC_ADD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idle_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hard_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;v1::&lt;/span&gt;&lt;span class="n"&gt;OFP_FLOW_PERMANENT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;v1::&lt;/span&gt;&lt;span class="n"&gt;OFP_DEFAULT_PRIORITY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;将&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="err"&gt;为&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;的数据进行&lt;/span&gt;&lt;span class="n"&gt;nat&lt;/span&gt;&lt;span class="err"&gt;转换&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;   
        &lt;span class="n"&gt;nat_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inet_addr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;10.0.168.192&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;由于机器中字节序和网络字节序不一样，所以&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="err"&gt;为倒序，你可以使用函数将变成网络字节序&lt;/span&gt;
        &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&amp;lt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nat_ip:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;&amp;lt;nat_ip&amp;lt;&amp;lt;endl;&lt;/span&gt;
&lt;span class="s"&gt;        src_ip= flow.nw_src();//保存src_ip&lt;/span&gt;
&lt;span class="s"&gt;        cout&amp;lt;&amp;lt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;src_ip:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;&amp;lt;src_ip&amp;lt;&amp;lt;endl;&lt;/span&gt;
&lt;span class="s"&gt;        auto aset = v1::ofp_action_nw_src().nw_addr(nat_ip);&lt;/span&gt;
&lt;span class="s"&gt;        fm.add_action(&amp;amp;aset);//添加动作，修改数据的src_ip为nat_ip&lt;/span&gt;
&lt;span class="s"&gt;        cout&amp;lt;&amp;lt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;set_nw_src:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;&amp;lt;nat_ip&amp;lt;&amp;lt;endl;&lt;/span&gt;
&lt;span class="s"&gt;    }&lt;/span&gt;

&lt;span class="s"&gt;    cout&amp;lt;&amp;lt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nw_dst:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;&amp;lt;flow.nw_dst()&amp;lt;&amp;lt;endl;  &lt;/span&gt;
&lt;span class="s"&gt;    cout&amp;lt;&amp;lt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nat_ip:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;&amp;lt;nat_ip&amp;lt;&amp;lt;endl;&lt;/span&gt;
&lt;span class="s"&gt;    if ((nat_ip!=0)&amp;amp;&amp;amp;(flow.nw_dst()==nat_ip))//若dst_ip为nat_ip，则修改为src_ip，完成对接&lt;/span&gt;
&lt;span class="s"&gt;    {&lt;/span&gt;
&lt;span class="s"&gt;        auto aset_dst = v1::ofp_action_nw_dst().nw_addr(src_ip);&lt;/span&gt;
&lt;span class="s"&gt;        fm.add_action(&amp;amp;aset_dst);&lt;/span&gt;
&lt;span class="s"&gt;        cout&amp;lt;&amp;lt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;set_nw_dst:&lt;/span&gt;&lt;span class="err"&gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;src_ip&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;ao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;v1::&lt;/span&gt;&lt;span class="n"&gt;ofp_action_output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;fm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ao&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;最后，非常重要的一点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;由于修改完src_ip之后，其他主机并不能接受改数据，因为arp列表中没有此项。所以需要添加静态arp。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;主机&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在mininet中，查看nat转换的主机的mac信息：h2 ifconfig&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在其他主机如h3中 添加静态arp: h3 arp -s nat_ip h2_mac&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此时pingall可通。&lt;/p&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;arp缓存表很重要！Openflow1.0中没有修改arp的功能，1.3才有。考虑通信需要从全局的角度考虑，不能只考虑ICMP的转换，ICMP之前的arp的转换是必不可少的过程。希望读者能从中加深对网络通信流程的理解。感谢@地球-某某老师长久支持和教导！哈哈！&lt;/p&gt;
&lt;h3&gt;修改&lt;/h3&gt;
&lt;p&gt;台湾-linton同学提供了更好的解决方案：在nat之前，给目的主机发送arp_request,sender_ip为nat_ip,以此来给目的主机添加arp信息。
只需要在下发flow_mod之前，下发一个pkt_out，用于发送nat arp即可。不再赘述。&lt;/p&gt;
&lt;p&gt;以上的解决方案并不完美，如果目标主机arp缓存表刷新之后，nat arp数据丢失，到达主机的数据将被丢弃。所以必须保证在发送数据之前发送arp_request。@地球-某某 老师解决方案为：周期发送arp_request，这能一定程度上解决这个问题。flow_mod的周期小于arp缓存表刷新周期也能一定程度解决这个问题。解决这个问题的根本是要保证数据发送之前，发送arp_request，以保证dst host的arp缓存表中有对应项。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 04 May 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-05-04:pages/2014/05/04/noxshi-xian-natgong-neng.html</guid><category>sdn</category><category>openflow</category><category>nox</category></item><item><title>[c]线程池的实现</title><link>http://www.muzixing.com/pages/2014/04/28/cxian-cheng-chi-de-shi-xian.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;这是C语言培训的最后一题，线程池，今天看了看控制器的代码，看到了线程池的影子，然后发现应该赶紧写完这篇了。哎，文笔不行，写书写成屎了！希望再修改几次能不丢人吧。&lt;/p&gt;
&lt;p&gt;本篇主要介绍如何实现一个线程池模型，task是简单的打印，当然如果你想让线程池完成你的功能线程的管理，只需要将task换成你的线程就可以了。&lt;/p&gt;
&lt;h3&gt;线程池&lt;/h3&gt;
&lt;p&gt;（摘自百度百科）线程池是一种多线程处理形式，处理过程中将任务添加到队列，然后在创建线程后自动启动这些任务。线程池线程都是后台线程。&lt;/p&gt;
&lt;p&gt;组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程池管理器（ThreadPoolManager）:用于创建并管理线程池&lt;/li&gt;
&lt;li&gt;工作线程（WorkThread）: 线程池中线程&lt;/li&gt;
&lt;li&gt;任务接口（Task）:每个任务必须实现的接口，以供工作线程调度任务的执行。&lt;/li&gt;
&lt;li&gt;任务队列:用于存放没有处理的任务。提供一种缓冲机制。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更多可访问：http://baike.baidu.com/link?url=caXqYSEEEDLS28VYuSzSxPbTM3dt_5WwXqF2-TUxR8ptJxggJaJHfTZ3_9Hs4urU#2&lt;/p&gt;
&lt;h3&gt;threadpool.h&lt;/h3&gt;
&lt;p&gt;threadpool.h的功能主要是定义工作线程的结构和线程池结构，声明相关的函数，如创建函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#ifndef _THREADPOOL_&lt;/span&gt;
&lt;span class="c1"&gt;#define _THREADPOOL_&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="c1"&gt;#include &amp;lt;pthread.h&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;threadpool_work&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;threadpool_work&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;tpool_work_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;tpool&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num_thread&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//co&lt;/span&gt;&lt;span class="n"&gt;unt&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;max_queue_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="sr"&gt;//m&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;pthread_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tpool_work_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;rear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;closed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//c&lt;/span&gt;&lt;span class="n"&gt;lose&lt;/span&gt; &lt;span class="n"&gt;putting&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;existed&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="nb"&gt;shutdown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="sr"&gt;//s&lt;/span&gt;&lt;span class="n"&gt;hutdown&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;works&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;pthread_mutex_t&lt;/span&gt; &lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;
    &lt;span class="n"&gt;pthread_cond_t&lt;/span&gt; &lt;span class="n"&gt;queue_has_task&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;pthread_cond_t&lt;/span&gt; &lt;span class="n"&gt;queue_has_space&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="sr"&gt;//s&lt;/span&gt;&lt;span class="n"&gt;pace&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt;
    &lt;span class="n"&gt;pthread_cond_t&lt;/span&gt; &lt;span class="n"&gt;queue_empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;thread_creat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;tpool_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;tpool_p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num_thread&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;max_queue_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tpool_add_work&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;routine&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;第二个参数是任务函数的地址，&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="err"&gt;是任务函数的参数、&lt;/span&gt;

&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tpool_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;get_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;#endif&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;threadpool.c&lt;/h3&gt;
&lt;p&gt;threadpool.c是threadpool.h的实现。主要实现了，threadpool.h中定义的所有函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;threadpool.h&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;pthread.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;unistd.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;string.h&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;tpool_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;tpool_p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num_thread&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;max_queue_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;malloc&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;num_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_queue_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_queue_size&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;为了留出一个位置，用于区别队列满和空的区别，详情看博客中循环队列那篇。&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;num_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num_thread&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                        &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rear&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;closed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;shutdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="sr"&gt;//i&lt;/span&gt;&lt;span class="n"&gt;nit&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pthread_mutex_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pthread_mutex_init&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pthread_cond_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_has_task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;初始化&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pthread_cond_init:queue_has_task&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pthread_cond_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_has_space&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pthread_cond_init:queue_has_space&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pthread_cond_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pthread_cond_init:queue_empty&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;threadpool_work&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_queue_size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;malloc pool-&amp;gt;queue:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pthread_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;num_thread&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;malloc pool-&amp;gt;tid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num_thread&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pthread_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;thread_creat&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;创建线程，执行实体为&lt;/span&gt;&lt;span class="n"&gt;thread_creat&lt;/span&gt;&lt;span class="err"&gt;函数。&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pthread_create error&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tpool_p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;thread_creat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;creating&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;tpool_work_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;thread_creat start\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="n"&gt;forever&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pthread_mutex_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;在操作数据之前，需要先&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;!&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;shutdown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="sr"&gt;//i&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;I am sleep..\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pthread_cond_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_has_task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;I am awake\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;shutdown&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;exit\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pthread_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;is_full&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
        &lt;span class="n"&gt;work&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;
        &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pool-&amp;gt;front:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;%pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_queue_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pool-&amp;gt;front(after)%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_full&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pthread_cond_broadcast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_has_space&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;broadcast&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;been&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pthread_cond_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_empty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;读写完成，解锁&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;))(&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tpool_add_work&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;添加任务函数&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tpool_work_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pthread_mutex_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;shutdown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;closed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;queue full\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;pthread_cond_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_has_space&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//i&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;shutdown&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;closed&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;we&lt;/span&gt; &lt;span class="nb"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;   
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;shutdown&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;closed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;shutdown\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;is_empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;is empty:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_empty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;len:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rear&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rear&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;%tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_queue_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;       
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;signal has task\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;pthread_cond_broadcast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_has_task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pthread_cond_broadcast\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;pthread_cond_broadcast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_has_task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;




&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tpool_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tpool_destroy\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pthread_mutex_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;closed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;works&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wait for all work done\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pthread_cond_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;shutdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pthread_cond_broadcast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue_has_task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wait for worker thread exit\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;num_thread&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pthread_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;All&lt;/span&gt; &lt;span class="n"&gt;awake&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;shotdown&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;free thread pool\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rear&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;%pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_queue_size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;用于区别循环链表中的&lt;/span&gt;&lt;span class="n"&gt;full&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;get_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rear&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_queue_size&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;%pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_queue_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;main.c&lt;/h3&gt;
&lt;p&gt;main函数主要负责调用，测试线程池。工作任务是最简单的打印。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;pthread.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;threadpool.h&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string 0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string 1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string 2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string 3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string 4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string 5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string 6&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,};&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;long&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;watching&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tpool_t&lt;/span&gt; &lt;span class="n"&gt;test_pool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;tpool_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;test_pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;工作线程为&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;，最大为&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="err"&gt;个&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;loop\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;tpool_add_work&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;tpool_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;后续&lt;/h3&gt;
&lt;p&gt;现在写教程都不知道说什么好了，感觉要说的都在代码，注释里，就不多废话了。有问题的请评论。希望能对你有帮助。另外你可能需要在添加完县城之后，将线程join一下才能看打印。释放的时候可以运行等待的线程。&lt;/p&gt;
&lt;p&gt;c语言培训题到此结束。希望是一个新的开始！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Mon, 28 Apr 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-04-28:pages/2014/04/28/cxian-cheng-chi-de-shi-xian.html</guid><category>c</category><category>thread_pool</category></item><item><title>[c]生产者消费者模式实现</title><link>http://www.muzixing.com/pages/2014/04/19/csheng-chan-zhe-xiao-fei-zhe-mo-shi-shi-xian.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;本文主要内容是：使用多线程，运行生产者函数和消费者函数，去实现队列（临界区）的读写操作。&lt;/p&gt;
&lt;p&gt;其意义在与熟悉多线程的互斥过程。生产者消费者模式是最好，最简单的选择。&lt;/p&gt;
&lt;h3&gt;数据结构&lt;/h3&gt;
&lt;p&gt;首先我们要操作的数据结构是队列。那么我首先要构造一个队列：&lt;/p&gt;
&lt;p&gt;queue.h&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#ifndef _QUEUE_&lt;/span&gt;
&lt;span class="c1"&gt;#define _QUEUE_&lt;/span&gt;


&lt;span class="n"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_QUEUE_&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;bad&lt;/span&gt; &lt;span class="n"&gt;design&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;queue_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;队列的初始化。如&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="err"&gt;的设置。&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;     &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;获取队列的长度&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;入队&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;            &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;出队&lt;/span&gt;

&lt;span class="c1"&gt;#endif&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;接下来是queue的实现：&lt;/p&gt;
&lt;p&gt;queue.c&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#include &amp;quot;queue.h&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;queue_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;设置&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="err"&gt;指针开始的位置，长度为&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="err"&gt;的内存为&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; queue empty\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;get end:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;get begin:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;%queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;使用循环数组实现队列&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="err"&gt;空余一个存储单位，用于区别空和满的状态。若不空余一个，则无法直接判别空与满的状态。&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; put seccessful:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; queue full.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//m&lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;problem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; queue empty.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;函数实现很简单，主要需要注意的就是空和满的判断。所以需要空余一个单位来区别这两者。&lt;/p&gt;
&lt;p&gt;接下来就是生产者和消费者函数的定义了。&lt;/p&gt;
&lt;h3&gt;生产者/消费者&lt;/h3&gt;
&lt;p&gt;pro_con.h&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#ifndef _PROCON_&lt;/span&gt;
&lt;span class="c1"&gt;#define _PROCON_&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;queue.h&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;生产者函数，用于入队&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;消费者函数，用于出队&lt;/span&gt;
&lt;span class="c1"&gt;#endif&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;pro_con.c&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;pro_con.h&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;pthread.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;unistd.h&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;pthread_cond_t&lt;/span&gt; &lt;span class="n"&gt;unempty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PTHREAD_COND_INITIALIZER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;初始化一个条件：&lt;/span&gt;&lt;span class="n"&gt;unempty&lt;/span&gt;
&lt;span class="n"&gt;pthread_mutex_t&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PTHREAD_MUTEX_INITIALIZER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;初始化一个互斥锁：&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;

&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;Producer&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;producer start\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pthread_mutex_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;对临界区进行操作之前，必须&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;num1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;producer lock\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;producer set lock error \n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;been&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pthread_cond_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;unempty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;队列已满，&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="err"&gt;所以给&lt;/span&gt;&lt;span class="n"&gt;unempty&lt;/span&gt;&lt;span class="err"&gt;条件加上锁，让本线程进入等待状态，交出&lt;/span&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="err"&gt;。&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;producer flag: %d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;producer_get_len:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pthread_cond_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;unempty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="err"&gt;若没有满，则通过&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="err"&gt;唤醒因为&lt;/span&gt;&lt;span class="n"&gt;unempty&lt;/span&gt;&lt;span class="err"&gt;条件而等待的一个线程。&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;producer set signal\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;处理完成之后，需要&lt;/span&gt;&lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="err"&gt;，以让其他线程获得该&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;num2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;producer unlock successful\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;prodecer unlock successful\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//s&lt;/span&gt;&lt;span class="n"&gt;leep&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;cpu&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;接下来是消费者函数的实现。同样写在pro_con.c文件下。逻辑和生产者差不多，只不过操作是出栈。条件相反而已。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;consumer start\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;pthread_mutex_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;同样的，先加锁、&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;consumer_get_len:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;flag%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pthread_cond_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;unempty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;若空，则无法读取，进入等待状态&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;consumer get,%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;queue-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;非满，通过&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="err"&gt;唤醒等待线程中的一个。&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pthread_cond_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;unempty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;consumer set signal\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;最后打开锁。&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;consumer unlock\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;main.c&lt;/h3&gt;
&lt;p&gt;主函数主要负责调用和测试。代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;queue.h&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;producerandconsumer.h&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;pthread.h&amp;gt;&lt;/span&gt;
&lt;span class="sr"&gt;//i&lt;/span&gt;&lt;span class="n"&gt;nclude&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;

&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;queue_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;初始化队列&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;queue_init%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;pthread_t&lt;/span&gt; &lt;span class="n"&gt;tid_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;tid_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="err"&gt;定义两个线程号。&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;queue:%p\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pthread_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tid_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;参数表（线程号，&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="err"&gt;，执行程序地址，参数）&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pthread_create producer\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;pthread_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tid_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pthread_create consumer\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="sr"&gt;//g&lt;/span&gt;&lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;下面给出一些队列数据结构的单元测试用例。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;len:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;len:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;len:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;len:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;len:%d\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;get_len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sat, 19 Apr 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-04-19:pages/2014/04/19/csheng-chan-zhe-xiao-fei-zhe-mo-shi-shi-xian.html</guid><category>multi_thread</category></item><item><title>[c]time_server</title><link>http://www.muzixing.com/pages/2014/04/18/ctime_server.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;本篇内容主要是介绍如何编写一个通过socket通信，实现获取服务器当前时间的例子。&lt;/p&gt;
&lt;h3&gt;实现&lt;/h3&gt;
&lt;p&gt;首先我们需要定义两个函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;time_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;get_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这两个函数是用于提供时间获取服务和，客户端调用去获取时间的函数。&lt;/p&gt;
&lt;p&gt;以下是time_server.h的内容：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#ifndef _TIME_SERVER_&lt;/span&gt;
&lt;span class="c1"&gt;#define _TIME_SERVER_&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;string.h&amp;gt;&lt;/span&gt;

&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;time_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;get_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;#endif&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;time_server.c文件是实现time_server中的函数声明。
头文件如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#include &amp;quot;time_server.h&amp;quot;&lt;/span&gt;
&lt;span class="c"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#include &amp;lt;time.h&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#include &amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#include &amp;lt;netinet/in.h&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;我们需要把系统时间返回所以需要用到time.h&lt;/p&gt;
&lt;p&gt;需要使用socket，所以需要include &lt;socket.h&gt;&lt;/p&gt;
&lt;p&gt;netinet/in.h则是因为要使用inet_addr()函数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;time_server函数实现如下：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;time_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;server_fd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;用于记录&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="err"&gt;的&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sock_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//si&lt;/span&gt;&lt;span class="n"&gt;ze&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;socket_in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; server start.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="sr"&gt;//c&lt;/span&gt;&lt;span class="n"&gt;reate&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;server_fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;若成功返回一个非&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;的整数&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="err"&gt;，若失败，返回&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;server_fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; create socket failed.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; create socket successful.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="sr"&gt;//s&lt;/span&gt;&lt;span class="n"&gt;et&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;
    &lt;span class="n"&gt;bzero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;server_addr&lt;/span&gt;
    &lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_family&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;设置协议族为&lt;/span&gt;&lt;span class="n"&gt;IPV4&lt;/span&gt;&lt;span class="err"&gt;。另还有其他几种如&lt;/span&gt;&lt;span class="n"&gt;AF_UNIX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;可&lt;/span&gt;&lt;span class="n"&gt;google&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inet_addr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.0.0.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;将十进制点分&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;转化为&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="err"&gt;的整数，同时&lt;/span&gt;&lt;span class="mf"&gt;0.0.0.0&lt;/span&gt; &lt;span class="err"&gt;为监听所有地址。服务器可能不止一个地址。&lt;/span&gt;
    &lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;函数是将&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="err"&gt;转化为网络字节序（大小端问题）&lt;/span&gt;

    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;bind&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_fd&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; bind failed\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; bind seccessful\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;listen&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; listen failed\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; listen seccessful\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="nb"&gt;recv&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sock_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;client_fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_fd&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;client_addr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sock_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_socket_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;store_mem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; accept failed.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; accept seccessful\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;time_t&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;asctime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;localtime&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;time_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asctime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;localtime&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;time_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="sr"&gt;//s&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; send failed.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;send time seccessful\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上是time_server的函数实现。但是比较忧伤的是我使用的time的格式不太对，发送过去的星期。接下来是客户端的代码。两个函数都写在一个time_server.c文件里就好了。直接通过函数名调用即可。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;get_time()&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;get_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;参数是&lt;/span&gt;&lt;span class="n"&gt;server_ip&lt;/span&gt; &lt;span class="err"&gt;和&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;   
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;recv_length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sock_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; client start.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="sr"&gt;//c&lt;/span&gt;&lt;span class="n"&gt;reate&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;client_fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; create socket failed.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; create socket successful.\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="sr"&gt;//s&lt;/span&gt;&lt;span class="n"&gt;et&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;
    &lt;span class="n"&gt;bzero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="sr"&gt;//s&lt;/span&gt;&lt;span class="n"&gt;et&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_family&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;server_addr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;connect failed\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;connect successful\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recv_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;receive failed\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;receive:\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;recv_length&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;getchar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;基本上time_server.c就是以上的内容，并不复杂。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;main.c&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;time_server.h&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;netinet/in.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;   
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;server_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inet_addr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.0.0.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;time_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;主函数也非常简单，在一台服务器机器上运行time_server(port).&lt;/p&gt;
&lt;p&gt;在客户端上，运行get_time(server_ip,port)即可。&lt;/p&gt;
&lt;p&gt;另，启动顺序是先启动server,再启动client,不然会有refused。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 18 Apr 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-04-18:pages/2014/04/18/ctime_server.html</guid><category>c</category><category>socket</category></item><item><title>编程真的不简单</title><link>http://www.muzixing.com/pages/2014/04/17/bian-cheng-zhen-de-bu-jian-dan.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;以前觉得编程嘛，不就是写代码嘛。谁不会啊！后来，和大男哥聊天的过程中，他说到一句话：大家都说我会c编程，然后我也觉得我会用c。就像我会打篮球，科比也会打篮球一样。&lt;/p&gt;
&lt;p&gt;当时真的笑翻了！不过说来也是！编程真的不简单！&lt;/p&gt;
&lt;h3&gt;编程真的不简单&lt;/h3&gt;
&lt;p&gt;下面是上个周我做的c语言培训题收获的感想。&lt;strong&gt;编程真的不简单啊！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;之前都是用python写程序，很少会注意到一些方面，比如头文件之类的，指针之类的。这次的c题培训，让我对编程的认识上升到了另一个阶段。&lt;/p&gt;
&lt;h3&gt;编码&lt;/h3&gt;
&lt;p&gt;编程并不是仅仅把功能实现而已。还有许多重要的东西，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;逻辑的严谨性&lt;/strong&gt;：一些边界条件，可能的逻辑分支等，都需要考虑到。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;模块化思想&lt;/strong&gt;：将相对独立的功能写在一个文件中，有利于解耦和移植。提高代码的复用性，同时也为单元测试提供了可能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;头文件的重要性&lt;/strong&gt;：在C语言中通过include 头文件的方式把某一些模块添加进来。同时一个头文件所包含的的内容应该是静态的声明，而不应该有实现。所有的实现都应该出现在同名的.c文件中。同时，在运行的时候我们必须保证.C的实现与.h的声明一致，某种程度上是对代码的保护。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可读性&lt;/strong&gt;：可读性的重点是对编程者而言。一个好的代码，应该可读性很高。我们可以从函数明直观的明白函数的功能，同时可以从变量名清楚地知道其作用。从文本的角度提高可读性。一段苦涩难懂的代码，也许机器容易度，但是其可读性过低，对于后期维护，成本过高。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;追求高效&lt;/strong&gt;：在保证可读性的同时，应该追求代码的高效性，如多重循环中，上层计算结果应该用变量去保存，用于底层的循环，而不应该在底层进行多次计算重复值。
如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;函数&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;是一个计算庞大的函数。&lt;/span&gt;
&lt;span class="n"&gt;For&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;   
    &lt;span class="n"&gt;For&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="n"&gt;anything&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这样每一次循环内循环的时候，在判断j是否小于foo(i)的时候都需要花大量的时间去计算foo(i)的结果。正确的方式应该是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;For&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;   &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;For&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="n"&gt;anything&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;如此一来仅仅计算了一次，就可以将值使用多次，减少了没有必要的循环。
虽然写起来可能不太好看。但是花费一个变量可以省去许多计算是很值得的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;设计的重要性&lt;/strong&gt;：能实现功能的方式有很多种，如何采用高效的算法，设计优雅的数据结构，定义正确的函数功能，参数。这些是我这些天学到的宝贵的一点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;算法&lt;/strong&gt;：一个程序的灵魂是算法。宁可花掉时间想算法，也不可以退而求其次采用低效的算法解决问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据结构的重要性&lt;/strong&gt;：在写代码的过程中好多时候我的数据结构都设计得不好，男哥给我很多的帮助。首先要清楚要做什么，需要什么，然后再去设计。后来的数据结构好与坏，我基本能有一些感觉了。好的数据结构能让算法更简单。&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;函数定义&lt;/strong&gt;：函数定义涉及到函数的名称，参数，返回值这三大要素。好的名称可以提高可读性，正确的参数，能让整个程序运行得更合理，为算法提供正确的数据。返回值的重要性体现在函数调用的情况下。比如一个pop()函数，它不应该是在函数体里面打印pop出来的数值，而返回void，而是将pop的数值返回。打印的任务应该是打印返回值。这样的函数定义才是正确的，因为更多的场景需要得到这个数值，而不是在控制台下面打印一个值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;代码的优雅度&lt;/strong&gt;：渐渐觉得，其实写代码不是一件简单的事情。他需要一个人拥有足够的背景知识，如英文的熟练程度，逻辑思维严谨度，设计思想等等。能把一个功能成功拆分成许多的相对独立的模块，然后有机的组合在一起，而且可读性很高，鲁棒性（稳定性）很强，可移植性很强，这就是代码的优雅度。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;语言的熟练度非常重要&lt;/strong&gt;:刚开始的时候举步维艰，一个指针就能搞疯掉。但是慢慢的就习惯了，速度也就上来了，遇到的问题多了，也就知道怎么解决了。写的多了，也就快了。所以语言的熟练程度也是我在这次培训中得到的提升。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;知识广度&lt;/strong&gt;:除了基础的语法以外，比较成熟的接口，架构是我需要大大补充的。比如通用线程编程中很多知识还没有摸透。还需要多练习，多看书，多理解。有其事在线程池一题，pthread_cond_t 的一些操作我还不是特别清晰。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;指针&lt;/strong&gt;: 从python这种不需要接触指针的语言转到c这种一直使用指针的语言，还是需要一个过渡的。幸亏大一的时候学C++，还算认真。基本上已经捡起来以前的东西了。只是始终没有使用完调用free的习惯，看来还需要培养。 因为指针出现的问题是这次训练中遇到的最多的问题。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;调试&lt;/h3&gt;
&lt;p&gt;以上的都是在编码的过程中的一些总结。但是这显然不是最重要的，最重要的是：&lt;strong&gt;调试&lt;/strong&gt;！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何定位错误是一个很重要的能力！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我目前使用打印信息调试，慢慢定位到错误断点。&lt;/p&gt;
&lt;p&gt;调试方式有很多种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;打印调试信息&lt;/li&gt;
&lt;li&gt;gcc --debug   + gdb &lt;/li&gt;
&lt;li&gt;使用eclipse等集成环境会让你调试爽一点哦。起码不需要一直面对黑框子。&lt;/li&gt;
&lt;li&gt;更多的我就不知道了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我觉得我应该学习一下如何在bash中使用 gdb 进行调试。这是我以后要学习的知识之一，写代码不难，调试才难！因为出错是正常的。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;写一个程序其实就是在做一个产品&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;需要考虑到产品的功能，是否能够为用户创造价值。如何从无到有设计，实现一个功能，这个过程本身就是在做一个产品，只不过范围上比较小而已。在设计的时候不仅仅要考虑到产品的功能性，还要考虑到许多方面，比如与其他产品配合工作等等。我觉得这8道题给我的提升是非常大的！不仅仅是c语言方面，而是编码设计方面。更大的范围内，这次培训改变了我的思维模式。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 17 Apr 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-04-17:pages/2014/04/17/bian-cheng-zhen-de-bu-jian-dan.html</guid><category>code</category></item><item><title>[C语言]两个栈实现队列</title><link>http://www.muzixing.com/pages/2014/04/15/cyu-yan-liang-ge-zhan-shi-xian-dui-lie.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;这是学习c语言的第一个训练题。刚开始写得真的非常差！！后来在大男哥的知道下学会了如何写c语言。本篇教程是：如何使用两个栈实现队列的功能。基本上这个代码也是他手把手教的。&lt;/p&gt;
&lt;h3&gt;算法&lt;/h3&gt;
&lt;p&gt;如何使用两个栈实现队列？
大家都能想到需要在pop的时候从一个栈到另一个栈倒一下，再pop，这样就有做到先入先出了。但是如何判别哪一个是目前正在使用的，而哪一个又是用来接收第一个栈pop数据的呢？&lt;/p&gt;
&lt;p&gt;其实有一个好办法就是，指定一个是专门用于入栈的栈in_stack，所有数据入栈的时候必须入到这个栈中，而出栈的时候，需要将数据pop到另一个栈中，然后再从另一个栈中出栈。第二次出栈的时候直接从out_stack。直到out_stack的数据为空，则将in_stack的数据pop到out_stack中。这样就能保证出栈的顺序是FIFO了。&lt;/p&gt;
&lt;p&gt;同时，in_stack的深度就是队列的最小深度。&lt;/p&gt;
&lt;p&gt;最大深度是len(in_stack+out_stack).当且仅当第一次push时，全部push到满，然后pop数据，之后继续push直到满。严格意义上来说应该是len(in_stack+out_stack)-1，因为有一个pop掉了。&lt;/p&gt;
&lt;h3&gt;实现&lt;/h3&gt;
&lt;h4&gt;stack的实现&lt;/h4&gt;
&lt;p&gt;首先我们要实现stack。以下是stack.h&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;/*&lt;/span&gt;
&lt;span class="c1"&gt;##################&lt;/span&gt;
&lt;span class="n"&gt;Author:&lt;/span&gt; &lt;span class="n"&gt;muzi&lt;/span&gt;
&lt;span class="n"&gt;Date:2014&lt;/span&gt;&lt;span class="sr"&gt;/4/&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;TODO:&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;complete&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="c1"&gt;##################&lt;/span&gt;
&lt;span class="o"&gt;*/&lt;/span&gt;
&lt;span class="c1"&gt;#ifndef _STACK_H_&lt;/span&gt;
&lt;span class="c1"&gt;#define _STACK_H_&lt;/span&gt;

&lt;span class="n"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_stack&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;buttom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;max_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;stack_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;stack_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;#endif&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;stack.h中定义了stack的结构体，以及以下相关的函数，如push，pop等。当然类似于面向对象中的构造函数的stack_create()也是必须的。最后还不忘定义destroy去释放内存。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;stack.h&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;stack_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack_create&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_t&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buttom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;stack_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buttom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;max_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buttom&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buttom&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这些都是基本的函数，相比应该不难，不做更多解释。&lt;/p&gt;
&lt;h4&gt;queue的实现&lt;/h4&gt;
&lt;p&gt;同样的先，先写queue.h&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#ifndef _QUEUE_H_&lt;/span&gt;
&lt;span class="c1"&gt;#define _QUEUE_H_&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;stack.h&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_QUEUE_H_&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;stack_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;queue_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;span class="c1"&gt;#endif&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个文件定义了struct queue_t,成员有 两个stack的指针。（喜欢python的人是绝对不喜欢c的指针的，比如我。不过不得不说，不会c的程序员，真不好意思说自己是程序员。）&lt;/p&gt;
&lt;p&gt;我们要在queue.c中去实现queue.h定义的内容。&lt;/p&gt;
&lt;p&gt;关键算法也在这里。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#include &amp;quot;queue.h&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue_create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;queue_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;stack_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;stack_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;stack_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;最关键的其实就是这个判断以及这个判断所执行的语句&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;如果&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="err"&gt;都出栈了，那么需要从&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="err"&gt;中倒换过来。&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;如果&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="err"&gt;中有数据的话。&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;stack_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;stack_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;stack_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;始终返回的是&lt;/span&gt;&lt;span class="n"&gt;out_stack&lt;/span&gt;&lt;span class="err"&gt;的数据&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;就是这么简单，就把功能实现了。跟着大男哥学习c语言编程，还是有很多收获的。&lt;/p&gt;
&lt;h4&gt;main函数测试。&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;quot;queue.h&amp;quot;&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="c1"&gt;#include &amp;quot;stack2list.h&amp;quot;&lt;/span&gt;


&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;int_printer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;queue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;queue_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;queue_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;queue_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;queue_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;queue_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;queue_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;queue_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;queue_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;queue_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;int_printer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;至此功能实现。&lt;/p&gt;
&lt;p&gt;在写代码的过程中，发现设计的重要性，一个好的逻辑思维，设计风格，能让代码写得非常优雅。其实写代码也是一个有讲究的活。就像一个工程师设计一个模型一样，既要美观实用，又要能随时被拿走，放到别处使用。代码的风格，结构的设计，实现方案等等，都是一个很好玩的事情。&lt;/p&gt;
&lt;p&gt;希望不久之后我能学好c语言！感谢大男哥的帮助！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 15 Apr 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-04-15:pages/2014/04/15/cyu-yan-liang-ge-zhan-shi-xian-dui-lie.html</guid><category>c</category></item><item><title>The study notes of East-west Bridge for SDN Network Peering</title><link>http://www.muzixing.com/pages/2014/04/10/the-study-notes-of-east-west-bridge-for-sdn-network-peering.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;这是一篇学习笔记，是在阅读了林萍萍女士的论文"East-West Bridge for SDN Network Peering  "之后的总结与思考。&lt;/p&gt;
&lt;p&gt;东西向接口通信中交换的数据是一个域中的数据。&lt;/p&gt;
&lt;h3&gt;控制器之间的发现&lt;/h3&gt;
&lt;p&gt;最简单的方式就是直接指定,但是这明显不是一个合理的方法。比较好的做法是让所有的控制器在开启的时候向一个注册服务器注册自己的信息，然后再获取所有控制器的信息，如IP,PORT,用于建立控制器之间的连接。另有更智能的方法是通过lldp去发现邻居。即LLDP报文中携带本域中控制器的信息。
即有如下三种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过配置信息设置&lt;/li&gt;
&lt;li&gt;访问注册服务器获取&lt;/li&gt;
&lt;li&gt;通过LLDP去发现邻居 &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我认为，第一种方法最简单，但是需要手动配置。第二种方法最易于设计。第三种方法最智能。我觉得使用LLDP去发现邻居是一种不错的方式。每一次接入网络都需要探测自己的邻居，然后发送自己的拓扑信息给邻居，同时当拓扑发生变化时也需要给邻居同步，此处的拓扑发生变化可以包含如下两点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;域内拓扑发生变化，如link down&lt;/li&gt;
&lt;li&gt;邻居C拓扑变化传送过来导致本地存储拓扑变化，从而需要更新拓扑，并通知其他邻居。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;网络信息的存储&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;分布式存储在每一个控制器，每一个控制器只保存自己的视图，需要全局数据时再发送请求从别的控制器获取。此方式为主动请求方式，能减少拓扑信息传递的数量。但是耗时大。&lt;/li&gt;
&lt;li&gt;分布式存储在每一个控制器，每一个控制器都有全网视图。时刻保持tcp连接，实时更新全网拓扑。&lt;/li&gt;
&lt;li&gt;集中式存储，全网视图在某一指定服务器上。当全网视图发生改变，则分发给订阅的控制器。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上3种方法都需要在控制器启动的时候，将自己的拓扑信息提交给集中式存储的服务器或者发布给订阅的控制器。&lt;/p&gt;
&lt;p&gt;个人以为第三种集中式存储会比较好。控制器连接的时候也不需要去建立多个连接，只需订阅这一服务即可。（如何分析？）&lt;/p&gt;
&lt;h3&gt;网络视图&lt;/h3&gt;
&lt;p&gt;每一个网络都有一个视图，这个视图包含了如下的信息：（此表摘自参考文献）&lt;/p&gt;
&lt;table class="table-bordered table-striped table-condensed"&gt;
   &lt;tr&gt;
      &lt;td&gt;Name&lt;/td&gt;
      &lt;td&gt;Type&lt;/td&gt;
      &lt;td&gt;Columns&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
      &lt;td&gt;Node_id&lt;/td&gt;
      &lt;td&gt;Virtual/physical&lt;/td&gt;
      &lt;td&gt;IP/MAC, OF_version, port_numbers，is_edge_node, Vendor_name,MTU，Device_type，Deveice_function&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
      &lt;td&gt;Link_id&lt;/td&gt;
      &lt;td&gt;Virtual/physical&lt;/td&gt;
      &lt;td&gt;Node_ID_src, Port_ID_src, Node_ID_dst,
      Port_ID_dst,
      Bandwidth,is_interdomain_link&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
      &lt;td&gt;Port_id&lt;/td&gt;
      &lt;td&gt;Virtual/physical&lt;/td&gt;
      &lt;td&gt;Node_ID,
      Port_MAC,is_active, is_edge_port,
      VLAN_ID,
      throughput&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
      &lt;td&gt;Node_capbility&lt;/td&gt;
      &lt;td&gt;NULL&lt;/td&gt;
      &lt;td&gt;protocol_name, version, port&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
      &lt;td&gt;Reachability&lt;/td&gt;
      &lt;td&gt;NULL&lt;/td&gt;
      &lt;td&gt;IP_prefixes,length&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
      &lt;td&gt;Node_table_ID(Flow entity)&lt;/td&gt;
      &lt;td&gt;NULL&lt;/td&gt;
      &lt;td&gt;Columns names are the same as the fields defined in the flowtable in OpenFlow specification&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
      &lt;td&gt;Link_Utilities&lt;/td&gt;
      &lt;td&gt;NULL&lt;/td&gt;
      &lt;td&gt;Link_ID， Link utilities&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
      &lt;td&gt;Flow_path(Node_ID_src  Node_ID_dst)&lt;/td&gt;
      &lt;td&gt;NULL&lt;/td&gt;
      &lt;td&gt;Port_ID (in), Node_ID_src, Port_ID (out),Port_ID (in), Node_ID_dst, Port_ID (out)&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
      &lt;td&gt;&lt;/td&gt;
   &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;在上表之外，东西向接口还应该交换主机数据。如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;MAC&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;DPID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;用于回复ARP信息。&lt;/p&gt;
&lt;h3&gt;网络视图学习&lt;/h3&gt;
&lt;p&gt;网络试图的基础信息可以通过LLDP报文获取，若更多高级的信息，我们需要通过对LLDP的数据段进行拓展，以携带相关的信息。本处所提到的学习是指从底层网络获取相关信息。&lt;/p&gt;
&lt;h3&gt;交换数据格式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Json，xml均可。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于这些我表示不太懂。一般的我使用scapy封装数据包，转换成stream之后，使用socket传输。&lt;/p&gt;
&lt;h3&gt;网络虚拟化&lt;/h3&gt;
&lt;p&gt;为了私有原因或者安全原因，我们有时候并不希望别的控制器全部知道我们的拓扑，所以网络虚拟化是很有必要的。&lt;strong&gt;我们可以将拓扑简化为几个边源端口组成的大交换机&lt;/strong&gt; 从而隐藏内部拓扑的细节。&lt;/p&gt;
&lt;p&gt;这一点非常必要，而网络虚拟化可以完美解决。网络虚拟化产品有很多，有flowvisor，也有北京邮电大学开发的CNVP&lt;/p&gt;
&lt;h3&gt;交换事件&lt;/h3&gt;
&lt;p&gt;当网络信息（拓扑信息）发生变化时，我们需要实时地通知其他控制器这一变化。模拟BGP协议，我们可以设置5种类型的消息结构。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open&lt;/li&gt;
&lt;li&gt;Update&lt;/li&gt;
&lt;li&gt;Notification&lt;/li&gt;
&lt;li&gt;Keep-alive&lt;/li&gt;
&lt;li&gt;View-refresh&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当启动控制器时，控制器与其他控制器连接，发送open消息。然后发送update消息，将自己的网络信息传递给对方，同时获取对方传递过来的网络信息，以获得更新的全网拓扑。在无数据传输的时候，需要传递Keep-alive消息保持TCP连接。View-refresh消息用于主动获取网络信息。&lt;/p&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;这是昨天拜读林萍萍女士论文的总结与思考。虽然东西向接口大家都能想到，但是早在一年前就做出来，并做了implementation 和evaluation，这是非常厉害的！向前辈们学习！更多详细信息可以直接阅读参考文献。&lt;/p&gt;
&lt;h3&gt;参考文献：&lt;/h3&gt;
&lt;p&gt;Pingping Lin, Jun Bi, and Yangyang Wang&lt;/p&gt;
&lt;p&gt;East-West Bridge for SDN Network Peering&lt;/p&gt;
&lt;p&gt;Institute for Network Sciences and Cyberspace, Department of Computer Science,
Tsinghua University&lt;/p&gt;
&lt;p&gt;Tsinghua National Laboratory for Information Science and Technology (TNList)&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 10 Apr 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-04-10:pages/2014/04/10/the-study-notes-of-east-west-bridge-for-sdn-network-peering.html</guid><category>sdn Ewbridge</category></item><item><title>[POX]messenger component getting started</title><link>http://www.muzixing.com/pages/2014/03/26/poxmessenger-component-getting-started.html</link><description>&lt;h3&gt;关于messenger getting started的来历&lt;/h3&gt;
&lt;p&gt;在POX中，Murphy专门开发了一个叫messenger的模块，用于实现POX与其他程序的通信。我曾有一个想法想实现分布式的POX。于是我在整个Internet上面寻找了好久，依然没有找到什么有用的东西！很忧伤！自己看代码也没有看明白怎么用！后来直接去Stanford的网站上面问Murphy！在我再三脑残的追问之下，终于他觉得应该写一个Getting started了。于是就在POX+wiki上面添加了Messenger的Getting started.&lt;/p&gt;
&lt;h3&gt;Messenger 的作用&lt;/h3&gt;
&lt;p&gt;从以下的英文中，我们可以对Messenger有一定的了解。messenger是一个API,是用与POX与其他程序建立连接的API,通过他实现的有PoxDesk,也就是POX的web ui。&lt;/p&gt;
&lt;p&gt;The messenger component provides an interface for POX to interact with external processes via bidirectional JSON-based messages.  The messenger by itself is really just an API, actual communication is implemented by transports.  Currently, transports exist for TCP sockets and for HTTP.  Actual functionality is implemented by services.  POX comes with a few services.  messenger.log_service allows for interacting with the log remotely (reading it, reconfiguring it, etc.).  openflow.of_service allows for some OpenFlow operations (e.g., listing switches, setting flow entries, etc.).  There are also a few small example services in the messenger package, and pox-log.py (in the tools directory) is a small, standalone, external Python application which interfaces with the the logging service over TCP.
By writing a new service, it becomes available over any transport.  Similarly, writing a new transport allows for accessing any service in a new way.
The messenger package in the repository has a fair amount of comments.  Additionally, you can see POXDesk (mentioned elsewhere) as an example of both implementing a new service, and communicating with messenger over HTTP from JavaScript. &lt;/p&gt;
&lt;h3&gt;加载messenger模块&lt;/h3&gt;
&lt;p&gt;我们在以下的代码中在运行的POX的时候加载了Messenger组件。同时，我们也把tcp_transport作为组件加载进来，最后我们运行Messenger组件。这个example启动了一个服务端线程，监听本机的7790端口。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pox_dart&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="err"&gt;./&lt;/span&gt;&lt;span class="nv"&gt;pox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt; &lt;span class="n"&gt;messenger&lt;/span&gt; &lt;span class="n"&gt;messenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tcp_transport&lt;/span&gt; &lt;span class="n"&gt;messenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;
&lt;span class="n"&gt;POX&lt;/span&gt; &lt;span class="mf"&gt;0.3.0&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;Copyright&lt;/span&gt; &lt;span class="mi"&gt;2011&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2014&lt;/span&gt; &lt;span class="n"&gt;James&lt;/span&gt; &lt;span class="n"&gt;McCauley&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;et&lt;/span&gt; &lt;span class="n"&gt;al&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;DEBUG:boot:Not&lt;/span&gt; &lt;span class="n"&gt;launching&lt;/span&gt; &lt;span class="n"&gt;of_01&lt;/span&gt;
&lt;span class="n"&gt;DEBUG:core:POX&lt;/span&gt; &lt;span class="mf"&gt;0.3.0&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;going&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;DEBUG:core:Running&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;CPython&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.7.5&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Sep&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="mi"&gt;2013&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;DEBUG:messenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tcp_transport:Listening&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="mf"&gt;0.0.0.0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;7790&lt;/span&gt;
&lt;span class="n"&gt;DEBUG:core:Platform&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;Darwin&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;13.1.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x86_64&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i386&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;
&lt;span class="n"&gt;INFO:core:POX&lt;/span&gt; &lt;span class="mf"&gt;0.3.0&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后我们开启另一个终端，然后进入到POX的messenger目录之下，运行test_client文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;test_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;之后，我们在test_client的输入框之下，输入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CHANNEL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;upper&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;msg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello world&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;马上就会收到pox返回的信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Recv:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;msg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;HELLO WORLD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;CHANNEL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;upper&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;当然，这个前提是在test_client的主函数中的IP+Port都设置正确的情况下才会产生，即test_client中开启了一个半连接socket，做为客户端去connect server TCP.&lt;/p&gt;
&lt;h3&gt;小提示&lt;/h3&gt;
&lt;p&gt;如果想让POX运行CLI，你需要在运行POX的时候加上 py ,例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;pox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这就会出现CLI。同时如果想让显示漂亮，可以加上samples.pretty_log。&lt;/p&gt;
&lt;h3&gt;后语&lt;/h3&gt;
&lt;p&gt;更多的尝试我没有继续，因为实在是看不懂这个POX的代码逻辑。最后选择自己去开启一个线程，直接简历socket连接。但是这些连接需要设计一些逻辑，可能工作量还是有一些的。但是不是特别多。如果你对这个感兴趣，你可以尝试。如果你知道更好的方法，你可以给我留言哦！我非常喜欢有人和我交流，一个人做这个很郁闷！&lt;/p&gt;
&lt;p&gt;如有问题，请留言。&lt;/p&gt;
&lt;p&gt;更多POX相关解答：https://openflow.stanford.edu/display/ONL/POX+Wiki&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 26 Mar 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-03-26:pages/2014/03/26/poxmessenger-component-getting-started.html</guid></item><item><title>mininet与外部host通信</title><link>http://www.muzixing.com/pages/2014/03/25/mininetyu-wai-bu-hosttong-xin.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;好多同学都在尝试使用mininet搭建拓扑。有的同学在尝试如何让mininet与外网通信，比如虚拟机，比如mininet之外的另一个网络。问题已经存在很久，本文将介绍如何使用mininet的接口实现与外界通信。&lt;/p&gt;
&lt;h3&gt;Intf()接口&lt;/h3&gt;
&lt;p&gt;在mininet的源码中，我们可以找到一个link的文件，也是一个类。这个文件中有一个接口类Intf()&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Intf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="s"&gt;&amp;quot;Basic interface object that can configure itself.&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;使用这个接口类，可以把安装mininet的机器的网卡接到mininet的ovs之上。&lt;/p&gt;
&lt;p&gt;剩下的就简单了。最重要的接口解决之后一切就都解决了。&lt;/p&gt;
&lt;p&gt;如果需要例子，可以在本站查看：mininet搭建自定义拓扑
http://www.muzixing.com/pages/2013/12/06/yuan-chuang-mininetda-jian-zi-ding-yi-wang-luo-tuo-bu-by-muzi.html&lt;/p&gt;
&lt;p&gt;另，也可以查看mininet中的hwintf文件。&lt;/p&gt;
&lt;p&gt;希望能对你有帮助。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 25 Mar 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-03-25:pages/2014/03/25/mininetyu-wai-bu-hosttong-xin.html</guid></item><item><title>markdown添加视频教程：Idina Menze和Caleb Hyles激情对唱Let It Go</title><link>http://www.muzixing.com/pages/2014/03/21/markdowntian-jia-shi-pin-jiao-cheng-idina-menzehe-caleb-hylesji-qing-dui-chang-let-it-go.html</link><description>&lt;p&gt;首先，在markdown中写好标题，如：这个网站还不错。然后冒号：然后添加视频的地址等信息就好了。&lt;/p&gt;
&lt;p&gt;格式如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    Idina Menze和Caleb Hyles激情对唱Let It Go：&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;498&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;510&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://player.youku.com/embed/XNjcyMDU4Njg0&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;frameborder=&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt; &lt;span class="err"&gt;allowfullscreen&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这样就可以添加成功了。&lt;/p&gt;
&lt;p&gt;冒号后面的信息请在相关视频的分享键附近寻找把视频分享给朋友的地址，然后选择通用地址复制，格式上面已经有给出。&lt;/p&gt;
&lt;p&gt;然后就可以了！简单吧！我可是偷偷看别人的github源码才学会的！&lt;/p&gt;
&lt;p&gt;视频附上：&lt;/p&gt;
&lt;p&gt;Menze和Caleb Hyles激情对唱Let It Go:&lt;/p&gt;
&lt;iframe height=498 width=510 src="http://player.youku.com/embed/XNjcyMDU4Njg0" frameborder=0 allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;非常赞的一个视频！学习如何使用MARKDOWN添加视频的成果咯！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 21 Mar 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-03-21:pages/2014/03/21/markdowntian-jia-shi-pin-jiao-cheng-idina-menzehe-caleb-hylesji-qing-dui-chang-let-it-go.html</guid><category>Song</category></item><item><title>SDN实现HTTP网络加速实验</title><link>http://www.muzixing.com/pages/2014/03/13/sdnshi-xian-httpwang-luo-jia-su-shi-yan.html</link><description>&lt;h3&gt;由于篇幅太长，且这个实验室是很久以前，我和我的小伙伴们一起做的课设，没有时间进行排版书写。&lt;/h3&gt;
&lt;p&gt;附上链接：&lt;/p&gt;
&lt;p&gt;http://user.qzone.qq.com/350959853/blog/1394681174&lt;/p&gt;
&lt;p&gt;北邮学弟学妹做这个课设的可以联系628中某学长。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 13 Mar 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-03-13:pages/2014/03/13/sdnshi-xian-httpwang-luo-jia-su-shi-yan.html</guid><category>SDN</category><category>HTTP</category><category>OpenFlow</category></item><item><title>【原】基于mininet的OpenFlow拓展性拓扑搭建</title><link>http://www.muzixing.com/pages/2014/03/11/yuan-ji-yu-mininetde-openflowtuo-zhan-xing-tuo-bu-da-jian.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;我们普遍情况下，都是单一控制器去控制一个网络。但是如果多控制器呢？我们如何实现多控制情况下的通信要求呢？&lt;/p&gt;
&lt;p&gt;这有点难度！需要一些东西向的协议来实现控制器之间的数据共享与交换。不是我一个人一两天能搞定的事情。且不同控制器对拓扑信息等存储方式不一样，需要一个统一的标准就显得比较困难。我们先不去想太多。首先，我们需要完成的第一项工作就是数据平面上，不同控制器之间的网络可以相互通信。&lt;/p&gt;
&lt;p&gt;最简单的通信莫过于ping了！&lt;/p&gt;
&lt;h2&gt;实验目的&lt;/h2&gt;
&lt;p&gt;使用mininet搭建两个独立的网络，分别属于不同的控制器。同时，底层数据平面可以相互ping通。这就是我们这个实验的目的。&lt;/p&gt;
&lt;h2&gt;拓扑搭建&lt;/h2&gt;
&lt;p&gt;底层拓扑搭建我们使用mininet2.0，因为mininet1.0版本好像没有link文件，也没有intf类。也许是我没有找到吧。&lt;/p&gt;
&lt;p&gt;以下的代码的作用在于创建一个OVS的网络，并使虚拟机的某个（无ip）网卡连接到这个网中。&lt;/p&gt;
&lt;p&gt;直接上代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="c1"&gt;#!/usr/bin/python&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    This is a topu of our test. It shows that how to add an interface(for example a real hardware interface) to a network after the network is created.&lt;/span&gt;
&lt;span class="s"&gt;    This code writed by li cheng, after learning mininet of sprient&amp;#39;s.&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cli&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CLI&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;setLogLevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mininet&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;link&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Intf&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;topolib&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TreeTopo&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;quietRun&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RemoteController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OVSKernelSwitch&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;checkIntf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;#make sure intface exists and is not configured.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39; %s:&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;quietRun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ip link show&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Error:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;does not exist!\n&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;\d+\.\d+\.\d+\.\d+&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quietRun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;ifconfig &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ips:&lt;/span&gt;
        &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;has an IP address,&amp;#39;&lt;/span&gt;
            &lt;span class="s"&gt;&amp;#39;and is probably in use!\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;setLogLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;info&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;OVSKernelSwitch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;intfName_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;eth1&amp;quot;&lt;/span&gt;  &lt;span class="c1"&gt;#将虚拟机的eth1赋值给intfName_1,&lt;/span&gt;
    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;****checking****&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intfName_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;checkIntf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intfName_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#检查eth1是否可用&lt;/span&gt;

    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;****creating network****\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Mininet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listenPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6633&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#监听端口是6633&lt;/span&gt;

    &lt;span class="n"&gt;mycontroller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RemoteController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;muziController&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;192.168.0.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#设定远程控制器&lt;/span&gt;

    &lt;span class="n"&gt;switch_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;s1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#添加交换机s1&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controllers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mycontroller&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="c1"&gt;#添加控制器&lt;/span&gt;

    &lt;span class="n"&gt;_intf_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Intf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intfName_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;switch_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#使用接口函数把虚拟机的网卡和mininet中的交换机的端口1连接&lt;/span&gt;

    &lt;span class="n"&gt;h1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;h1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#创建host1&lt;/span&gt;
    &lt;span class="n"&gt;h2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;h2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#将h1连接到s1上&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;*****Adding hardware interface &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intfName_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;to switch:&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;switch_1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="c1"&gt;#启动mininet类的对象net&lt;/span&gt;
    &lt;span class="n"&gt;CLI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#启动命令行&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上的代码写完之后，保存为topo.py文件，我们无需再输入什么sudo mn等命令，只需要运行它就可以了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;另外我们还需要在远端运行一个控制器。这个太简单，不懂的同学可以google一下。&lt;/p&gt;
&lt;p&gt;这就完成了一个虚拟机的代码编写，另外一个虚拟机的情况同理去做就可以了。&lt;/p&gt;
&lt;h2&gt;关键配置&lt;/h2&gt;
&lt;p&gt;在这个时候，两个mininet中的网络是无法相互ping通的。&lt;/p&gt;
&lt;p&gt;因为还有一些关键配置我们没有做。&lt;/p&gt;
&lt;h3&gt;host的ip配置成与虚拟机网卡同一网段的ip&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;这一点需要非常注意！&lt;/strong&gt;因为mininet模拟出来的host默认情况下，是10网段的，而普通的虚拟机会得到的网段是192的网段。这两个网段并不一样，所以host无法ping通虚拟机网卡也是很正常的，即使物理上做了连接。&lt;/p&gt;
&lt;p&gt;所以我们需要对host进行ip配置&lt;/p&gt;
&lt;p&gt;在mininet之下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;h1&lt;/span&gt; &lt;span class="n"&gt;ifconfig&lt;/span&gt; &lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;eth0&lt;/span&gt; &lt;span class="mf"&gt;192.168.0.6&lt;/span&gt;&lt;span class="c1"&gt;#ip只要是同一网段就可以&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;最好我们需要把所有的host的ip都修改成192网段的。所以模拟的时候建议host数量不用过多。也许mininet中可以直接指定所有host的ip网段，我还没有研究到，如果你知道，你可以告诉我！相互交流学习！&lt;/p&gt;
&lt;p&gt;这个时候你会发现还是没有ping通！我们需要进行下一步。&lt;/p&gt;
&lt;h3&gt;将网卡设为桥接模式，并全部允许混杂，同时不给网卡分配IP。&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;桥接模式能确保虚拟机能和主机通信，并通过主机网卡与两一个虚拟机网卡连接。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;混杂模式之下会把目的地址不是自己的数据接受并转发出去。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不给网卡进行dhclient服务，则网卡没有配置ip，从而作为一个二层原件去转发数据。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当两台虚拟机都完成了以上的工作的时候，相信两个mininet网络之间的host是可以互ping的！好玩吧！&lt;/p&gt;
&lt;h2&gt;后续&lt;/h2&gt;
&lt;p&gt;多控制器的沟通，其实更重要的是控制器之间的信息共享，但是那还比较难，以后做出来再说吧。谢谢浏览！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 11 Mar 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-03-11:pages/2014/03/11/yuan-ji-yu-mininetde-openflowtuo-zhan-xing-tuo-bu-da-jian.html</guid><category>SDN</category><category>mininet</category></item><item><title>关于澄迈县农村小学现状的采访总结</title><link>http://www.muzixing.com/pages/2014/02/23/guan-yu-cheng-mai-xian-nong-cun-xiao-xue-xian-zhuang-de-cai-fang-zong-jie.html</link><description>&lt;p&gt;调查者：美在心灵研究中心 李呈、王毓茂、汤茗茹&lt;/p&gt;
&lt;p&gt;2014年2月，美在心灵大学生支教志愿者协会的三名志愿者开始了关于澄迈县农村小学生存现状的调查。为得到良好的对比，志愿者选择了4所典型的学校：珠宝岭小学，槟郎根小学，石浮中心学校和加乐中心小学四所小学。调查过程中，记录了相关的照片和视频，并形成了如下的采访记录。而由于研究人员后续时间精力不足，无法完成视频的处理，目前暂时搁置。采访笔记见下文。&lt;/p&gt;
&lt;h3&gt;珠宝岭小学&lt;/h3&gt;
&lt;p&gt;珠宝岭小学位于文儒镇石浮乡珠宝岭村，是一所典型的的农村小学。拥有两栋两层的教学楼，一个篮球场，还有一大片空地。校舍面积相当一个足球场大小。全校师生26人，其中教师5人，学生21人，学生全部都来自本村。&lt;/p&gt;
&lt;p&gt;珠宝岭小学名义上是一所完全小学，但只剩下三个年级，四年级以上的要到石浮中心学校或者其他更远的镇小学读书。学生数量逐年减少，学校已经没了当年两百多人时的影子。全校用于教学的只有三个教室，教室宽敞，窗户明亮，教室里寥寥地放着几张课桌，桌椅都是新的。剩下的教室里，除了少量用于教师宿舍和堆放杂物，其余的被毫无用处的空余出来。&lt;/p&gt;
&lt;p&gt;珠宝岭小学现有教师5名，均为男性，有两名教师来自本村。教师的工资都有3000元以上，教龄长一点的还会增加。除了校长未满50岁，其余四位教师都年逾花甲。校长告诉我们，以前教师们会参加教育局组织的普通话考试，但是考了几次，只有他自己一个人能及格，其他教师都已经觉得无关紧要，不打算考了。但即便如此，校长还是表示，课堂教学还是“以普通话为主”。&lt;/p&gt;
&lt;p&gt;全校现有学生21人，其中最高年纪三年级有6名学生。当这些学生在这所学校“毕业”之后，学校还能不能招到几名一年级新生，校长自己也不知道。珠宝岭村外出务工人员近400人，并带走了一部分村里的生源。大部分的孩子从小就到镇上读书，这所村里面的小学对他们没有任何记忆和情感。校长任教三年级语文，教5名女生和1名男生。其他年级的情况也大概如此，女多男少。有先见之明的家长都把男孩送到好一点的学校去了。在经济条件有限的情况下，都会首先选择让男孩享受更好的教育。&lt;/p&gt;
&lt;p&gt;学生每天要上5节课，上午三节，下午两节。学习的科目有语文、数学、品德、美术、音乐和体育。这些科目经常都由一个老师包揽。素质教育开展的情况基本可以忽略不计，美术和音乐对学生来说就是画一个简单的图形，唱一首歌。学校没有体育器材，体育课就是玩玩游戏、让学生在操场上跑跑闹闹。在这样的气氛下，学生对学习没有积极性。即便老师可以照顾到每一个学生，但是学生在课堂上还是掌握不了那些最基本的知识。自小学生减负令下来后，教师的压力也随之变小，学生学习成效如何，老师也不会太上心。&lt;/p&gt;
&lt;p&gt;学生对待考试和对待上课一样随意，试卷发下来后，他们匆匆写完，然后交卷，终于放假了。三年级语文期末的考试平均分是15分，每一个人都得了15分。低分率高的惊人。很多很简单的题目都没有写，或者像他们老师说的，根本就不会写。这样的考试分数，学生不在意，老师不在意，家长也不在意。&lt;/p&gt;
&lt;p&gt;在走访的几个家庭中，他们都普遍反映了自己的无奈。对这所小学的无奈，和对孩子的教育前途的无奈。随着农民赖以生存的橡胶和槟榔收益逐年减少，供一个孩子外出读书让很多家长叫苦不迭。所以，把孩子留在村里读书是家长们无奈的选择。把孩子留在村里，意味着他们对孩子失去了信心和期望。这种力不从心和无奈都转化为对这所学校的失望和责怪。&lt;/p&gt;
&lt;h3&gt;石浮中心学校&lt;/h3&gt;
&lt;p&gt;石浮中心学校是一所乡级小学，前身是一所小学和初中一体的学校。后来中学部分撤并到文儒中学，剩下的小学部分成为石浮乡的中心小学，管理着包括珠宝岭小学在内的6所村级小学，非完全小学的高年级学生大多在这里求学。约300名师生，教师29人，学生280多人，有7个班级，包括一个学前班。&lt;/p&gt;
&lt;p&gt;29名教师中，本科以上学历4名，其余大多为大专学历。年龄结构上，三分之一为50岁以上老教师，知识和储备落后，精神和体力不足。所以，接近10:1的师生比例，也让这所中心学校感到师资缺乏。和村级小学相比，中心小学的教师资源更加丰富，有专业的音乐和美术老师，还开设了英语课程。但即便如此，教师也无法做到专业对口的教学，大多数教师身兼多职，任教多门课程。&lt;/p&gt;
&lt;p&gt;学校继承了先前初中部的资源，校舍面积大，食堂和学生宿舍设备齐全。寄宿的学生每学期可以领到500元的伙食补助，但只限于来自非完全小学的高年级学生。寄宿在校的学生每月的伙食费是260元，加上来回路费和零花钱，每个月花费都不下300元。低年级的寄宿生没有伙食补助，所有的上学费用都要由家庭承担。&lt;/p&gt;
&lt;p&gt;从村级小学转上来的学生，基础“普遍”差，学习成绩跟不上，久而久之，彻底丧失对学习的乐趣。大多数情况下，“差生”的头衔一直伴随到小学毕业。毕业生中，除了极少数能考上澄迈中学和澄迈第二中学等县重点，绝大部分的学生都会到文儒中学继续他们的“差生”生涯。外出求学的初中生，生活环境发生变化，常常会遭到本地学生的排挤和欺负，加之学业不精，早早地就丧失了读书的念头。仅在去年，文儒中学就流失了一百多个石浮乡的学生。这些学生要不辍学在家，要不外出打工，没能完成九年义务教育。&lt;/p&gt;
&lt;h3&gt;槟榔根小学&lt;/h3&gt;
&lt;p&gt;槟榔根小学位于石浮乡槟榔根村，是石浮乡唯一一所村级的完全小学，还开设了一个学前班。教师10人，包括一名代课老师。除了2名50岁以上，其余8名教师都正值青壮年，课堂上全部用普通话教学。他们要共同管理全校250余学生。相比石浮中心学校，这所村级小学的师资更加缺乏。无奈之下，学校只能自行出资，在村里聘请了一名代课老师。工资1500元，比其他老师少了一倍。&lt;/p&gt;
&lt;p&gt;学校的生源大都来自本村，村民都认为这是他们心目中最好的学校，把孩子送到这里是他们的首要选择。还有一部分来自其他的村级小学，甚至还包括从石浮中心学校转来的。家长都认为，这是一所教育好、管理好、对孩子负责的好学校。对于每一个来此求学的外村学生，学校都来者不拒。不收取任何费用，只要报名、注册，并留下家长联系电话，就正式成为学校的一员了。学校在村民心中的信任度极高，除了个别跟随务工父母外求学，本村的所有学生都就读于此。&lt;/p&gt;
&lt;p&gt;学校正在新建教学楼，教室都安排在移动板房里，甚至还用到了村里的祠堂。学校面积小，资源有限，有时会用到村里的资源，对此村民都无不赞成。学校和村民之间来往密切，有5名教师来自本村，他们和村民之间彼了解和信任。
和其他村级小学一样，教师们都要兼教其他科目，素质教育开展并不顺利。相比于中心学校，村级小学由于资源限制，无法开始小学英语课程，这让学校和家长都深感遗憾。语文和数学等主要学科的教学，都是以课文为主，同时辅助视频教学，让学生学到更多。全校只有一间多媒体教室，和250多名学生的需求互相矛盾。学校没有学生宿舍，但还是为了十几个外村学生腾出了两间教室，供学生中午休息。请了一个煮饭阿姨，收150元一个月的伙食费。&lt;/p&gt;
&lt;p&gt;和其他村级小学70%的低分率相比，槟榔根小学的低分率只有十几个百分点。对此，学校感到并不满意。对于差生，尤其是来自他村级小学的差生，老师会进行针对性的辅导，完成课堂教学的同时，还会在课后进行基础知识的补充与巩固。近年来，随着澄迈中学的考取越来越难，整个石浮乡的学生只有分到几个指标，成绩优秀的学生都没有机会就读县重点中学。槟榔根小学毕业生的去向大多是澄迈二中和文儒中学，澄迈二中是大多数学生的最高追求。&lt;/p&gt;
&lt;p&gt;学校能够受到学生和家长的欢迎，和村民的支持息息相关。村小学作为一个村的文化支撑，在槟榔根村表现的更加具体。村民们注重教育，爱护学校，外出工作的人都会时不时进行捐助。力求弥补一所村小学由于各方面因素造成的资源缺乏。&lt;/p&gt;
&lt;h3&gt;加乐中心学校&lt;/h3&gt;
&lt;p&gt;澄迈县加乐中心学校成立于1917年，学校面积18000平方米，现有两栋教学大楼和一栋综合大楼。同时建有两栋学生宿舍和两栋教师套件楼。除此之外，学校还专门设有图书室、电子阅览室、心理咨询室、医务室和舞蹈室等，功能室齐全，设施完备，是澄迈县唯一一所实现多媒体进教室的小学。加乐中心学校凭借出色的办学条件长年吸引着学生和家长。现学校在校学生1900余人，教师71人，其中特岗教师12名。开设37个教学班。&lt;/p&gt;
&lt;p&gt;加乐镇现只有两所完小，加乐中心学校和加朗小学。作为中心学校，加乐中心学校要承载加乐镇所有村级教学点的生源。学生人数太多，为了达到省规范学校“一班不超过45人，不超过30个班”的标准，学校不得不采取措施来控制生源的大量涌入。除了来自本镇教学点的高年级学生，学校对于其他学校学生的转学要求，学校会根据原则不予接收。但即便如此，加乐中心学校的人数和班额都已超标。&lt;/p&gt;
&lt;p&gt;学校除去产假、病假的教师，现今只有65名教师能正常上课。要应对全校将近两千名学生。教师不仅要应对繁重的课业，同时还有处理很多学校事务，很多老师都表示力不从心。学校现有英语教师9名，他们全都身兼不同的年级的语文和数学教学。有必要时他们还是体育或者音乐老师，而领到的工资只有一份。
相比于其他村级小学，加乐中心学校素质教育开展情况更加可观，学校有专业的美术、音乐和舞蹈老师，开成立设和舞蹈队和绘画班，对这方面有特长的学生进行辅导和栽培，并且取得了不错的成绩，多次在县级或省级的比赛中获奖。虽然成果累累，但无奈学校资源有限，无法达到素质教育的目标。学校仍然以应试教育为主，考试分数是学生、老师和家长共同的基本追求。 &lt;/p&gt;
&lt;p&gt;为了管理数量众多的寄宿学生，学校制定了严格的管理条例，每一栋宿舍楼都有专人管理。每一间宿舍有10个床位，2个卫生间。学校对学生的作息时间有严格的规定。中午12点开始午休，晚上10点熄灯睡觉，无论多么顽皮的学生都会自觉遵守。学校有专门的食堂，正餐通常是一荤一素，每月的伙食费260元，冬天的时候，学生还能在食堂打一桶洗澡的热水。学校对生源控制严格，为了能够顺利在这所学校读书，很多家长从学前班开始就将孩子送来这里。                             &lt;br /&gt;
加乐中心学校曾经凭借小学奥数竞赛取得的辉煌成绩而颇负盛名，但也容易造成“重数学，轻语文”的极端现象，不利于学生的平衡发展。近年来，奥数竞赛被取消后，加乐中心学校注重抓学生的均衡发展，逐渐改变了以前偏科的学风。但是对于那些来自村级教学点的差生，学校也没有太多办法。虽然在良好的学习环境下，差生的状况会有一定的改观，但大多数情况仍不乐观。长期的学习成绩不佳导致学习兴致不高，进而形成消极的学习态度。想要在新环境里很快转变学习态度、进而提高学习成绩，显得不太现实。&lt;/p&gt;
&lt;p&gt;相比其他学校，这里的毕业生升学有更多的选择，每年都会有嘉积中学、国兴中学等中学点来此招生。这所学校名声在外，很多学校都想来这里挖走优秀的苗子。但也只有极少数苗子会被挖走。其他大多数毕业生都会进入加乐中学读书，一所并不太好的中学，很多学生都会在初中消耗掉自己在小学时打下的好基础。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;农村小学的消失已经成为一种趋势，而这种趋势带来的后果如何目前还不得而知。而处于这个过程中的那一代孩子，尤其是农村的孩子则经受了很多。撤点并校是否能够提高教育资源的利用率？农村小学资产如何处理？学生安全，心理健康问题是否收到威胁？家庭教育成本是否过高？这一系列的问题都需要政策来解决。希望这个问题能得到足够的重视。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sun, 23 Feb 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-02-23:pages/2014/02/23/guan-yu-cheng-mai-xian-nong-cun-xiao-xue-xian-zhuang-de-cai-fang-zong-jie.html</guid><category>农村小学</category></item><item><title>属于我的2013和2014</title><link>http://www.muzixing.com/pages/2014/01/01/shu-yu-wo-de-2013he-2014.html</link><description>&lt;h2&gt;过去的我，站在风中，微笑向现在的我招手&lt;/h2&gt;
&lt;p&gt;远去了，2013的那个我！&lt;/p&gt;
&lt;h3&gt;心变了，世界就变了&lt;/h3&gt;
&lt;p&gt;我不再像前三年一样，喜欢每一堂课都坐在前排，和老师交流。也许是因为大四的课已经不那么重要，也许是因为我对学习有了其他的认识。&lt;/p&gt;
&lt;p&gt;依然和每一个任课老师都关系很好，依然会被老师记住，只是那个忠实的听众已经不满足于课堂上的知识。&lt;/p&gt;
&lt;p&gt;当外面的世界，给你带来更多的冲击与进步的时候，你很容易就做出选择。&lt;/p&gt;
&lt;p&gt;走出校园，开始实习的生活让我懂得太多太多，那种心理变化，心理成长的过程不是三年在象牙塔里乖乖读书能得到的。&lt;/p&gt;
&lt;p&gt;我开始认识到生存的压力，我开始为自己自力更生而自豪！我开始迷恋上自己赚钱自己花的日子，我为伸手要钱而感到羞愧!&lt;/p&gt;
&lt;p&gt;我开始思考我想要的未来，我开始掂量自己到底几斤几两，我开始计划怎么提升自己，直到满意。&lt;/p&gt;
&lt;h3&gt;实习那些事&lt;/h3&gt;
&lt;p&gt;我一直都是幸运儿，我坚信这一点。当我第一次接触到SDN的时候，我不知道我会继续下去，我不知道这是我第几次尝试，那是大三刚开始的时候。&lt;/p&gt;
&lt;p&gt;大三的暑假到了，保研的事情还没有着落，回家并不是一种明智的选择，实习才是。&lt;/p&gt;
&lt;p&gt;可是我高估了自己的实力。第一次面试是腾讯后台，竞争对手是谁这些都不重要，重要的是自己真的很嫩，真的懂得太少。那是我的第一个面试官，很和蔼，很耐心。我们聊了半个多小时，我回答的一般般，没有什么出彩，也没有太不堪。但是那是我第一次危机感！&lt;/p&gt;
&lt;p&gt;编程能力也就是入门水平。很多东西都只是知道，停留在功能层面，性能完全没有考虑到。&lt;/p&gt;
&lt;p&gt;第二次面试是一个小小的创业公司，虽然是前端，我什么都不懂，但是面试官还是看中了我的能力，最后还是去了那里实习。虽然故事有一点曲折。&lt;/p&gt;
&lt;p&gt;第三次面试是中科曙光的云存储实习，我可以毫不犹豫的说，那些代码优化的东西真的不懂！最后结果也是很理所应当的。对不起宇哥的推荐。&lt;/p&gt;
&lt;p&gt;第四次面试是因为我实在不喜欢第一个实习，那对于我来说就是在浪费生命。于是来到了工信部电信研究院。最后，我在这里留了下来，记得第一次和博士碰面，博士说，你一定要有自己的兴趣做下去，不然最好不用来。当时我满口答应！因为确实，这个实习就是关于SDN的，我未来的研究方向，我自己选择的方向，能有这样的实习真的是太幸福了！谢谢带我的两个学长！richardzhao，kimi。&lt;/p&gt;
&lt;p&gt;后来婉拒了去蓝汛的实习，也许是CDN的实习。谢谢我的亲叔叔给我找的实习！&lt;/p&gt;
&lt;h3&gt;工信部的岁月&lt;/h3&gt;
&lt;p&gt;快半年的实习，让我和这里的人和事产生了很多感情。我怀念那一张干净的桌子，我怀念那个被我随便玩的服务器。我怀念跟博士，学长一起加班的那天，那是我第一次加班。那天我们聊得很开心！我们说了很多，你们给了我很多建议，我都听进去了。那是一个团队共同作战的感觉，感觉很好！&lt;/p&gt;
&lt;p&gt;无论走到哪里都会认识很多人，好吧，尤其是女的。&lt;/p&gt;
&lt;p&gt;基本上我见过的女保安都会认出我，很多时候没有带卡，刷脸也是可以的。5楼的门禁我从来都不需要刷卡，也不需要等级，只需要跟他们开个玩笑，就可以进去。还有那个喜欢问我叫什么名字的女保安，让我都有点不好意思了。&lt;/p&gt;
&lt;p&gt;在这里，我做了很多事情，画了一遍openflow的数据结构，写了一篇openflow通信流程解读，写了一篇sdn控制器开发教程。在实习的过程中，我认识了一堆人，他们不在身边，他们在SDNAP的大家庭里。在那个QQ群里，有很多很厉害的老师。他们教会了我很多东西，特别是地球某某。他们给了我很多鼓励，让我很自信，我喜欢这群人！一群志趣相投的人相互鼓励，一起研究，真的感觉很有动力。&lt;/p&gt;
&lt;p&gt;当然，在工信部也会做一些工作以外的事情，比如写了一个pc版的微信打飞机游戏，还上了北邮人论坛十大，虽然这已经是我第5次上十大了。但是这跟以前都不一样，这一次我收获了许多称赞，我收获了很多自信！也许一个大神，真的在不断的称赞中进化而来的。我希望我能得到这样的机会。&lt;/p&gt;
&lt;p&gt;另外，自己还搭建了一个技术博客，很好玩，花了一个星期终于搭建完成。www.muzixing.com&lt;/p&gt;
&lt;p&gt;我可以在我搭建的博客上，发表我的教程，可以给别人带来帮助，那种感觉太好了！同时，也希望有些人能因为我的博客而认识我吧，对以后找工作有很大的帮助。&lt;/p&gt;
&lt;p&gt;走了，我的第一个实习！不过需要我帮忙，我还会回去的。哈哈！谢谢一路走来给我帮助的那些人，谢谢看好我，给我机会的人！&lt;/p&gt;
&lt;h3&gt;两个人的生活，同样一种幸福&lt;/h3&gt;
&lt;p&gt;这一年我们家小乖乖，越来越乖！也长大了很多，会思考一些东西了。虽然还是会赖床，会熬夜，会刷剧，会闹小脾气。但是还是变乖了很多！&lt;/p&gt;
&lt;p&gt;第一次出去是清明节，碰上阴雨天，我们基本都没有干什么。还记得那条宽阔的马路，没有什么人，风却是特别大。我们两个小二货，手牵手一路走一路笑。我老是跟你说快了，过了前面那个转角就到住的地方了。你却也就这样就跟我走完了。当然路上也撒娇让我背了你一段，嘿嘿！趴到我背上就跟软泥一样全身放松，手托着你的大腿好累的啊！每次背你都是手臂先累得不行！所以后来我在健身房开始锻炼我的手臂！哈哈！&lt;/p&gt;
&lt;p&gt;国庆的时候，是我们第一次坐火车出去玩。虽然一路上都是硬座，让你受了很多苦，很心痛，但是我们还是玩的很开心的。&lt;/p&gt;
&lt;p&gt;天子山上，你的盛装吸引了太多的目光。你就像一个美丽的新娘，只可惜当时我是你的摄影师，而不是你的新郎！不过以后会咯！走过路过的人，好多忍不住拿起相机拍你，我还故意让他们拍够了我再拍！我就喜欢我们家小朋友这么漂亮。拍你的照片比山上拿来打广告不知道好看多少倍！&lt;/p&gt;
&lt;p&gt;空中走廊回来的路上，天已经黑了，只能看到青石板路的白光。我带着你，走在看不见出路的小树林里。那是我第一次觉得压力好大，如果我把你带迷路了，如果你不相信我了怎么办？我带着你深一脚浅一脚地走在回来的路上。我们翻过了一个又一个小山坳，你说怎么还没到啊？我一直都安慰你，快了，过了前面那个转弯会出现什么东西，再下面会是什么，再过多久我们就可以走出去了。你信了！可是，我越来越紧张。虽然我相信我自己的方向感，我从来不会迷路。终于我们走完了青石板路，算是阶段性成功！我们又开始 更艰难的林间小道，那是一条没有开发的小路，只能顺着往前走，有些地方还会有泥。走了5分钟之后，你问我走的对吗？我肯定地说：没错！再走一短时间我们就可以走出去了。为了不让你着急，我给你讲很多其他的话题，逗你开心，给你讲故事。就这么一步一步往前走着，终于，我们走到了大路！当时我舒一口气！那是那次旅行给我印象最深的事情，我没有让你失望，你相信你我！&lt;/p&gt;
&lt;p&gt;周年纪念日的时候，我给你准备了好多活动。那一天我们过得很开心！夏天的时候，我们要去那里拍照！&lt;/p&gt;
&lt;h3&gt;锻炼身体&lt;/h3&gt;
&lt;p&gt;大二的时候再田径短跑队待了一年。学会了很多！大三一年都很忙，不再训练，告别了曾经奋斗的事。多少有些留恋。大四的时候，我终于可以重返健身房。&lt;/p&gt;
&lt;p&gt;练了两个月，涨了8斤。114到122。来年加油！我想140,150都无所谓，只要身体健康，强壮是可以接受的！130 的我，可能真的还太瘦！&lt;/p&gt;
&lt;p&gt;很幸运我有好基因，练哪里都很快出效果！估计这次回家，妈妈都会惊呆吧！来年，我要练出大胸肌和背扩！腿也要继续加强，我的扣篮梦，我要名正言顺地完成！在健身房各种被虐，也只剩下腿的力量值得骄傲了，最后的荣耀！&lt;/p&gt;
&lt;p&gt;这学期篮球打得也少了。一起打篮球的小伙伴们都开始各奔东西，能一起打球的日子不多！我会提升自己，下次，你们会看到更好的我。转型投手之后，突破都不会了真惨！&lt;/p&gt;
&lt;h2&gt;现在的我，迎着微风，向着未来的我跑去。&lt;/h2&gt;
&lt;p&gt;现在自己一个人坐在某一个周围没有熟人的环境，戴着耳机，听着自己喜欢的歌。写着自己想要写的文字！想象着未来的我会是什么模样。&lt;/p&gt;
&lt;p&gt;昨晚，讨论到我们班唯一找工作的姑娘，话说真的很厉害，微软工作着，年薪真的很高！想想自己，现在能值个什么价位呢?我不知道!但是无论如何，我已经落后太多了。不为了攀比，只为了更好的自己！有时候，别人的刺激，会激发内心无穷的动力。谢谢你为我树立一个好榜样，一个好目标！three姐，加油！&lt;/p&gt;
&lt;p&gt;3年之后，我希望，我是我现在想要的自己，甚至更好！不再感叹于自己太弱，或是别人太强。一切，都在有了这个想法的那一刻开始改变了。&lt;/p&gt;
&lt;p&gt;为了更好的自己，2014，我已经出发！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Wed, 01 Jan 2014 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2014-01-01:pages/2014/01/01/shu-yu-wo-de-2013he-2014.html</guid><category>胡思乱想</category></item><item><title>SDN的初步认识</title><link>http://www.muzixing.com/pages/2013/12/24/sdnde-chu-bu-ren-shi.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;（习惯性乱扯两句，可跳过）一年之前第一次接触SDN的时候，我甚至连pox的发音都发不对。第一次看OF1.0spec的时候，更是不懂secure channel到底是什么概念，Datapath一样是云里雾里。我不知道流是一个什么概念，不知道SDN如何DN，我只是觉得，我可能会比较喜欢IP这一方面的东西，具体哪一方面我也不知道。但是无所谓啊，我还年轻，我有选择的机会。抱着试一试的态度，去学习了SDN的一些知识，慢慢地就喜欢上了。不仅仅是因为知识本身，更是因为当我获得成功时刻的成就感与自豪感，让我觉得我愿意去做这件事情！一年之后，我写过Openflow协议通信流程的教程，画过所有Openflow协议的数据结构，写完自己的一个控制器，还写了一边关于如何编写控制器的教程，懂得怎么使用mininet搭建自定义的拓扑，懂得使用spirent testcenter去打流测试，懂得pox是如何运作的，等等。我甚至可以去教一些新手一些关于SDN的技术，但是，当我想要写点东西的时候，我却突然发现，我不知道什么是SDN！我并不清楚SDN是从何而来，不知道SDN发展历程，不知道SDN目前面临的问题，不明白SDN的现状到底什么状态，不知道SDN的未来有什么前景。我只知道一些具体的技术细节，也许对于一个本科生已经不错了。但是这也正是我们本科生的弱点所在吧。缺少大局观，目光不够长远，对知识的掌握更倾向于操作而非原理。正好需要写一写小论文，抓住机会，好好学习一下SDN的相关知识是一个非常明智的选择。&lt;/p&gt;
&lt;h2&gt;什么是SDN？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;SDN是software defined network 的首字母缩写，翻译成中文即：软件定义网络&lt;/strong&gt;。利用OpenFlow协议，把路由器的控制平面（control plane）从数据平面（data plane）中分离出来，以软件方式实现。这个架构可以让网络管理员，在不改动硬件设备的前提下，以中央控制方式，用程序重新规划网络，为控制网络流量提供了新的方法，也提供了核心网络及应用创新的良好平台。&lt;/p&gt;
&lt;h2&gt;SDN的发展历程&lt;/h2&gt;
&lt;h3&gt;起源与发展&lt;/h3&gt;
&lt;p&gt;OpenFlow起源于斯坦福大学的Clean Slate项目组 [1] 。CleanSlate项目的最终目的是要重新定义英特网，旨在改变设计已略显不合时宜，且难以进化发展的现有网络基础架构。&lt;/p&gt;
&lt;p&gt;在2006年，斯坦福的学生Martin Casado领导了一个关于网络安全与管理的项目Ethane[2]，该项目试图通过一个集中式的控制器，让网络管理员可以方便地定义基于网络流的安全控制策略，并将这些安全策略应用到各种网络设备中，从而实现对整个网络通讯的安全控制。受此项目（及Ethane的前续项目Sane[3]）启发，Martin和他的导师Nick McKeown教授（时任Clean Slate项目的Faculty Director）发现，如果将Ethane的设计更一般化，&lt;strong&gt;将传统网络设备的数据转发（data plane）和路由控制（control plane）两个功能模块相分离，通过集中式的控制器（Controller）以标准化的接口对各种网络设备进行管理和配置，那么这将为网络资源的设计、管理和使用提供更多的可能性，从而更容易推动网络的革新与发展。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;于是，他们便提出了OpenFlow的概念，并且Nick McKeown等人于2008年在ACM SIGCOMM发表了题为OpenFlow: Enabling Innovation in Campus Networks[4]的论文，首次详细地介绍了OpenFlow的概念。该篇论文除了阐述OpenFlow的工作原理外，还列举了OpenFlow几大应用场景，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;校园网络中对实验性通讯协议的支持（如其标题所示）&lt;/li&gt;
&lt;li&gt;网络管理和访问控制；&lt;/li&gt;
&lt;li&gt;网络隔离和VLAN；&lt;/li&gt;
&lt;li&gt;基于WiFi的移动网络；&lt;/li&gt;
&lt;li&gt;非IP网络；&lt;/li&gt;
&lt;li&gt;基于网络包的处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，目前关于OpenFlow的研究已经远远超出了这些领域。&lt;/p&gt;
&lt;h3&gt;扩展为SDN&lt;/h3&gt;
&lt;p&gt;基于OpenFlow为网络带来的可编程的特性，Nick和他的团队（包括加州大学伯克利分校的Scott Shenker教授）进一步提出了SDN（Software Defined Network, 目前国内多直译为“软件定义网络”）的概念–其实，SDN的概念据说最早是由KateGreene于2009年在TechnologyReview网站上评选年度十大前沿技术时提出[5]。如果将网络中所有的网络设备视为被管理的资源，那么参考操作系统的原理，可以抽象出一个&lt;strong&gt;网络操作系统（Network OS）&lt;/strong&gt;的概念—这个网络操作系统一方面抽象了底层网络设备的具体细节，同时还为上层应用提供了统一的管理视图和编程接口。这样，基于网络操作系统这个平台，用户可以开发各种应用程序，通过软件来定义逻辑上的网络拓扑，以满足对网络资源的不同需求，而无需关心底层网络的物理拓扑结构。&lt;/p&gt;
&lt;p&gt;关于SDN的概念和原理，可以参考开放网络基金会（Open NetworkingFoundation）于今年4月份发表的SDN白皮书Software Defined Networking：The New Norm forNetworks [6] 。&lt;/p&gt;
&lt;p&gt;从上面的描述中，可以看出OpenFlow/SDN的原理其实并不复杂，从严格意义上讲也很难算是具有革命性的创新。然而OpenFlow/SDN却引来了业界越来越多的关注，成为近年来名副其实的热门技术。截止2012年，包括HP、IBM、Cisco、NEC以及国内的华为和中兴等传统网络设备制造商都已纷纷加入到OpenFlow的阵营，同时有一些支持OpenFlow的网络硬件设备已经面世。&lt;/p&gt;
&lt;p&gt;2011年，开放网络基金会（Open Networking Foundation）在Nick等人的推动下成立，专门负责OpenFlow标准和规范的维护和发展；同年，第一届开放网络峰会（OpenNetworking Summit）召开，为OpenFlow和SDN在学术界和工业界都做了很好的介绍和推广。&lt;/p&gt;
&lt;p&gt;2012年年初召开的第二届峰会上，来自Google的Urs Hölzle在以OpenFlow@Google[7]为题的Keynote演讲中宣布Google已经在其全球各地的数据中心骨干网络中大规模地使用OpenFlow/SDN，从而证明了OpenFlow不再仅仅是停留在学术界的一个研究模型，而是已经完全具备了可以在产品环境中应用的技术成熟度。而后，Facebook也宣布其数据中心中使用了OpenFlow/SDN的技术。&lt;/p&gt;
&lt;h3&gt;OpenFLow协议发展历程&lt;/h3&gt;
&lt;p&gt;自2009年初发布第一个版本（v1.0）以来，OpenFlow规范已经经历了1.1、1.2以及比较成熟的1.3，目前1.4版本也已经出现。从下图我们可以看出，1版本更新的速度很快。1.1的时候应经支持VLAN,多级刘表，group等操作。而1.1,1.2都是过渡版本，很少有商家支持这些版本。到1.3的时候，基本上多级流表已经完善。所以许多厂家的of交换机开始支持改版本。&lt;/p&gt;
&lt;h4&gt;版本之间的差异&lt;/h4&gt;
&lt;p&gt;图片均来自:http://www.sdnap.com&lt;/p&gt;
&lt;p&gt;www.sdnap.com是学习SDN的好地方，这里有一个学习SDN的大家庭。更多资讯，可以直接访问sdnap。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://www.sdnap.com/wp-content/uploads/2013/05/openflow%E5%8D%8F%E8%AE%AE%E5%8F%91%E5%B1%95%E5%8E%86%E7%A8%8B1.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://www.sdnap.com/wp-content/uploads/2013/07/openflow%E5%8D%8F%E8%AE%AE%E8%BF%9B%E5%B1%952_DCN.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;SDN的现状&lt;/h2&gt;
&lt;p&gt;虽然SDN很火热，但是，并不像人们想象的那样推倒过去的网络，在SDN发展的道路上依然存在着许多问题，如技术，如用户心态等等问题都是继续解决的。&lt;/p&gt;
&lt;p&gt;OpenFlow并不是一统天下的协议，至少现在不是。这句话是对的。但是我们看好OpenFlow能在未来赢得一片属于自己的天地。&lt;/p&gt;
&lt;h3&gt;SDN的疑惑&lt;/h3&gt;
&lt;p&gt;软件定义网络真的是正确的方向嘛？&lt;/p&gt;
&lt;p&gt;软件定义的理想是远大的。但是伟大的梦想，实现的道路注定是曲折的。到底SDN能不能发展好，目前业界都持乐观态度，但是事实上大家都是在探索中，并没有爆发性的进步。也许这是暴风雨前的宁静吧。
但是，在SDN的热潮影响下，传统厂商的利益就受到了影响。如cisco，juniper等传统网络巨头的利益就收到了影响。一方面，他们也积极投身其中。目的是为了不至于由于坚持传统而被新事物取代。当你无法阻挡某些事情的发展的时候，你要试着加入这个行列。但是，传统厂商并不这么容易放弃。因为这意味着市场将面临一次洗牌，而对于习惯了巨头地位的那些厂商们，最不愿意看到的就是动荡。只有那些试图改变自己在行业格局内地位的小公司才会积极去参与这样的改革。所以说，本身这就动了巨头的蛋糕。所以改革本身也有一定难度。&lt;/p&gt;
&lt;p&gt;更聪明的巨头，如cisco，不仅仅一边跟进火热的SDN，争取在这一个新事物的市场中占领同样的巨头地位，同时他们还推行另外一个，反其道而行的概念：HDN(hardware defined network)。主张与SDN（software defined network）正好想法。HDN鼓吹以硬件定义网络。&lt;/p&gt;
&lt;h3&gt;什么是HDN?&lt;/h3&gt;
&lt;p&gt;Insieme(思科内部创业公司)将在11月6日发布一款号称“足以改变业内游戏规则”的重量级产品，“它是思科的未来！”然而，令业界琢磨不定的却是Insieme到底走SDN路线还是超越SDN的HDN路线？所谓HDN，是业界根据Insieme在纽约Interop展演示的Application Centric Infrastructure(ACI)架构得到的结论。根据演示，将在11月6日发布的ACI主要关注基于物理基础设施的服务及基于hypervisor的虚拟环境可编程性，与目前流行的SDN思路不同，更多是基于硬件的功能定义，因此被称为“硬件定义网络”HDN。[8]&lt;/p&gt;
&lt;p&gt;且不去讨论那些行业利益的影响，我们再去看看用户到底愿不愿意接受SDN和OpenFlow。
目前为止，google,facebook等大公司的数据中心已经采用了sdn的方案，并且google声称链路利用率高达99%，说实话，这着实把我们华为的工程师吓了一跳！但是我们必须很清晰地认识到的是目前SDN只适用于数据中心，其他地方，都在尝试中。而最复杂，最难办的广域网，SDN短期内是无法应用的。关于SDN的应用在下一小节将重点介绍。&lt;/p&gt;
&lt;h2&gt;SDN的应用&lt;/h2&gt;
&lt;p&gt;SDN的应用场景[9]：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据中心网络&lt;/li&gt;
&lt;li&gt;数据中心互联&lt;/li&gt;
&lt;li&gt;政企网络&lt;/li&gt;
&lt;li&gt;电信运营商网络&lt;/li&gt;
&lt;li&gt;互联网公司业务部署&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;SDN在数据中心网络的应用&lt;/h3&gt;
&lt;p&gt;数据中心网络的需要主要表现在海量的虚拟租户、多路径转发、VM的智能部署和迁移、网络集中自动化管理、绿色节能、数据中心能力开放等方面的需求。
SDN控制逻辑集中的特点，可充分满足网络集中自动化管理，多路径转发，绿色节能等方面的要求；SDN网络能力开放化的特点，可充分满足数据中心能力开放，VM的智能部署和迁移，海量虚拟租户的需求。并且，数据中心的建设和维护一般统一由数据中心运营商或ICP/ISP维护，具有相对的封闭性，可统一规划、部署和升级改造，SDN部署的可行性高。数据中心网络是SDN目前最为明确的应用场景，也是最有前景的应用场景。&lt;/p&gt;
&lt;h3&gt;SDN在数据中心互联的应用&lt;/h3&gt;
&lt;p&gt;数据中心之间互联网的网络具有流量大、突发性强、周期性强的特点，需要网络具备多路径转发与负载均衡、网络带宽按需提供、绿色节能、集中管理和控制的需求。&lt;/p&gt;
&lt;p&gt;SDN转发与控制分离，控制逻辑集中，网络虚拟化、开放化的特点，可通过部署统一的控制器，收集各数据中心之间的流量需求，进行统一的计算和调度，实施带宽的灵活按需分配，最大程度优化网络，提高资源利用率。目前Google已经在其数据中心之间应用了SDN技术，将数据中心之间的链路利用率提升至接近100%，成效显著。&lt;/p&gt;
&lt;h3&gt;SDN在政企网络中的应用&lt;/h3&gt;
&lt;p&gt;政府及企业网络业务类型多，网络设备功能复杂、类型多，对网络的安全性要求高，需要集中的管理和控制，网络灵活、定制化需求多。&lt;/p&gt;
&lt;p&gt;SDN转发与控制分离的架构，使得网络设备通用化、简单化，将复杂的业务功能剥离，由上层应用服务器实现，不仅可以降低设备硬件成本，更可使得企业网络更加简化，层次更加清晰。同时，SDN控制的逻辑集中，可以实现企业网络的集中管理与控制，企业的安全策略集中部署和管理，更可以在控制器或上层应用灵活定制网络功能，更好满足企业网络的需求；由于企业网络一般由企业自己的信息化部门建设、管理和维护，具有封闭性，可统一规划、部署和升级改造，SDN部署的可行性高。&lt;/p&gt;
&lt;h3&gt;SDN在电信运营商网络的应用&lt;/h3&gt;
&lt;p&gt;电信运营商网络包括宽带接入层、城域层、骨干层，具体的网络还可分为有线网络和无线网络，存在多种方式，如传输网、数据网、交换网等。总的来说，电信运营商网络具有覆盖范围大、网络复杂、网络安全可靠性要求高、网络制式多、多厂商共存等特点。&lt;/p&gt;
&lt;p&gt;SDN的转发向控制分离特点，可有效实现设备的逐步融合，降低设备硬件成本。SDN的控制逻辑集中特点，可逐步实现网络的集中化管理和全局优化，有效提升运营效率，提供端到端的网络服务；SDN的网络能力虚拟化和开放化，也有利于电信运营商网络向智能化、开放化发展，发展更丰富的网络服务，增加收入。&lt;/p&gt;
&lt;p&gt;但是，SDN技术目前尚不够成熟，标准化程度也不够。大范围、大量网络设备的管理问题、超大规模SDN控制器的安全性和稳定性问题、多厂商的协同和互通问题、不同网络层次/制式的协同和对接问题等均需得到解决。目前SDN技术在电信运营商网络大规模应用还难以实现。然而，可在局部网络或特定应用场景逐步使用，如移动回传场景、分组与光网络的协同场景等。&lt;/p&gt;
&lt;h3&gt;SDN在互联网公司业务部署中的应用&lt;/h3&gt;
&lt;p&gt;SDN即软件定义网络，然而笔者认为SDN的研究重点不应放在软件如何定义网络，而应在于如何开放网络能力。网络的终极意义在于为上层应用提供网络服务，承载上层应用。NaaS是网络的最终归宿。
互联网公司业务基于SDN架构部署，将是SDN的重要应用场景。&lt;/p&gt;
&lt;p&gt;SDN具有网络能力开放的特点，通过SDN控制器的北向接口，向上层应用提供标准化、规范化的网络能力接口，为上层应用提供网络能力服务。&lt;/p&gt;
&lt;p&gt;ICP/ISP可根据需要获得相应的网络服务，有效提升最终用户的业务体验。&lt;/p&gt;
&lt;p&gt;SDN转发和控制分离的特点可有效降低设备硬件成本；控制逻辑集中的特点可使得网络具有全局的视图实现全局优化，实现多网融合和集中管控；网络能力开放化可促进更多的业务创新和网络服务创新。这三大驱动力推动着SDN的发展，也使得SDN有着众多的应用场景。&lt;/p&gt;
&lt;h3&gt;SDN的未来&lt;/h3&gt;
&lt;p&gt;SDN的未来可以说说:充满希望,但并无定数。在推进SDN的过程中，技术问题不断的克服，渐渐地我们还需要解决一些用户习惯，用户心理等问题。目前的状态是，大家都相信SDN能有所作为，但是并不愿意去部署SDN。第一是因为这需要学习一整套的知识，第二是因为效果并得不到保障。目前很多功能，SDN能是实现的，传统的设备也可以实现。用户的思维模式需要一定的时间去改变。同时我们的技术还有待成熟，版本统一，设备互通等工作还有待进一步的完善。&lt;/p&gt;
&lt;p&gt;未来SDN会崛起，会在许多场合应用，但是SDN不会一统网络，这是业界共识。当然协议也不会仅仅是OpenFlow一种，但是OpenFlow会有一席之地。控制器也会百花齐放，如古老的pox，floodlight,以及新生代ODL,contrail,以及未来不可预见的其他控制器的诞生，将给SDN带来更多的生机。
随着技术的进步，功能的完善，现有网络的架构将会承受中大的冲击，也许不会是革命，诞生绝对是大力量的改革。&lt;/p&gt;
&lt;h2&gt;后续&lt;/h2&gt;
&lt;p&gt;写到这里，我想我写这篇小论文的目的达到了。在搜索资料的过程中，我认真地学习了SDN的发展历程，思考了SDN的现状与未来，相比以前的一无所知，我现在算有了一个大题的感知。这也算是这篇小文章的作用吧。倒是有一点需要澄清，文中许多篇幅都是在查资料的时候阅读到的，觉得讲得合理，就引用了。如发展史，现状的段落。其他的如思考，未来等篇幅，均为原创。&lt;/p&gt;
&lt;h2&gt;参考资料&lt;/h2&gt;
&lt;p&gt;[1]斯坦福大学Clean Slate项目网站, http://cleanslate.stanford.edu/&lt;/p&gt;
&lt;p&gt;[2] Ethane项目首页，http://yuba.stanford.edu/ethane/&lt;/p&gt;
&lt;p&gt;[3] Sane项目首页，http://yuba.stanford.edu/sane/&lt;/p&gt;
&lt;p&gt;[4] OpenFlow: EnablingInnovation in Campus Networks， www.openflow.org/documents/openflow-wp-latest.pdf&lt;/p&gt;
&lt;p&gt;[5] TechnologyReview网站关于2009年十大前沿技术的评选，http://www.technologyreview.com/article/412194/tr10-software-defined-networking/&lt;/p&gt;
&lt;p&gt;[6] Software DefinedNetworking: The New Norm for Networks,https://www.opennetworking.org/images/stories/downloads/white-papers/wp-sdn-newnorm.pdf&lt;/p&gt;
&lt;p&gt;[7] Open Networking Summit2012日程安排，http://opennetsummit.org/speakers.html&lt;/p&gt;
&lt;p&gt;[8]  思科的SDN纠结 – 专家解读思科ACI http://www.sdnap.com/sdn-technology/3387.html&lt;/p&gt;
&lt;p&gt;[9]SDN的应用场景分析与探讨 http://www.sdnap.com/sdn-study/1346.html&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 24 Dec 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-12-24:pages/2013/12/24/sdnde-chu-bu-ren-shi.html</guid><category>SDN</category><category>OpenFlow</category></item><item><title>OpenFlow1.0数据结构图示</title><link>http://www.muzixing.com/pages/2013/12/20/openflow10shu-ju-jie-gou-tu-shi.html</link><description>&lt;p&gt;每一次查看协议都是看到代码定义，总感觉不够清晰，那么自己去画一遍数据结构能给你带来很大的帮助！&lt;/p&gt;
&lt;p&gt;以下的图片是OpenFlow1.0的相关数据结构。希望能给你带来一点帮助。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://b.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=db393793f0d3572c62e29cd9ba28121a/63d9f2d3572c11df7804df59612762d0f603c2f7.jpg?referer=cba40445dbf9d72a4e73242d2ead&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://b.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=db393793f0d3572c62e29cd9ba28121a/63d9f2d3572c11df7804df59612762d0f603c2f7.jpg?referer=cba40445dbf9d72a4e73242d2ead&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://f.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=b34cdcc8bb014a90853e46b8994c482f/8b82b9014a90f603ded6ff3d3b12b31bb051ed62.jpg?referer=04b7dc59612762d0d929918f4b20&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://d.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=a98d86e80ef431adb8d2433c7b0ddd92/d1a20cf431adcbef6d331d7caeaf2edda3cc9f40.jpg?referer=36cfb6b49b25bc31724a34a8d95e&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://b.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=f63a6604271f95caa2f592b3f92c0e03/314e251f95cad1c8c6b69f5d7d3e6709c93d51be.jpg?referer=b1265f6ea918972bfa2d35fa9f54&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://g.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=96ec874ab8a1cd1101b672258929b9c1/d000baa1cd11728b2920ef58cafcc3cec3fd2cbe.jpg?referer=a6a58709af4bd1135dda82028c54&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://f.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=d5120477249759ee4e5060ce82c0322b/503d269759ee3d6d8813e7b141166d224e4adef7.jpg?referer=c8266399d739b60014d93b871aad&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://g.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=ab2a57a33b01213fcb334ed964dc47ec/00e93901213fb80e5dd602ad34d12f2eb9389440.jpg?referer=fb6e00049058d1099df49c82d45e&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://f.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=88ca1a0022a446237acaa567a8190333/4e4a20a4462309f775bacd68700e0cf3d6cad6f7.jpg?referer=23b445725143fbf29c3b921312ad&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://a.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=11417775ba0e7bec27da03e41f15c805/203fb80e7bec54e71e917964bb389b504fc26a4e.jpg?referer=ba188743b1de9c82ff72ccbfd644&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://f.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=04fb6f91b4fd5266a32b3c119b23e616/38dbb6fd5266d0168c14fd52952bd40735fa35be.jpg?referer=9b27dcc8bb014a90d829738d7355&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://f.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=d22bc6a574c6a7efbd26a823cdc1de6c/91ef76c6a7efce1ba82cabb0ad51f3deb48f6540.jpg?referer=9324fe99ff1f4134b920304ec35e&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://g.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=95905c0cf01fbe09185ec3115b5b7d0e/0b46f21fbe096b63187f3d2a0e338744ebf8ac62.jpg?referer=7f78c197a344ad3477a8b2b70c20&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://a.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=d4d4a65538292df593c3ac108c0a2d5d/f11f3a292df5e0fed91fea7b5e6034a85edf7240.jpg?referer=3f043143cb3d70cf15ed9f3dbe5e&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://g.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=d5cbada7a964034f0bcdc2039ff8080c/faedab64034f78f06906f9897b310a55b3191cbe.jpg?referer=8100bf6eba99a90162226e065c55&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;也许还有一些没有花全。因为这个是我初学OpenFlow时候画的，若有错误，欢迎指正！&lt;/p&gt;
&lt;p&gt;如果你觉得我的小站还不错，可以帮忙宣传宣传咯。创建初期，积攒人气！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 20 Dec 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-12-20:pages/2013/12/20/openflow10shu-ju-jie-gou-tu-shi.html</guid><category>SDN</category><category>OpenFlow</category></item><item><title>【原创】SDN控制器开发教程——打造属于你自己的控制器</title><link>http://www.muzixing.com/pages/2013/12/17/yuan-chuang-sdnkong-zhi-qi-kai-fa-jiao-cheng-da-zao-shu-yu-ni-zi-ji-de-kong-zhi-qi.html</link><description>&lt;hr /&gt;
&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;SDN(Software Defined Network)这些年越来越火。当我还是大三的小朋友的时候，我的学长带我走进了OpenFlow的世界。一年里，我慢慢学会了许多东西，研究过pox,写过mininet自定义拓扑，画过OpenFlow的数据结构，做过HTTP的流量引导，广播风暴解除等许多小东西。在SDN这条道路上越走越远，也希望有一天，我能在这个领域有所成就，做出一点自己的贡献。&lt;/p&gt;
&lt;p&gt;暑假的时候开始来工信部电信研究院实习，开始跟着学长一起开发，后来学长去美帝了，我继续完成剩下的工作。为了实现demo，我们顺便写了一个小小的控制器，其本质很简单，也许简单到你都不屑一顾。但是这个过程，我们需要从底层通信开始搭建，一直到最后的上层应用，无论哪一个环节，都会涉及到。到最后你会发现，其实也许这个控制器并没有太大的用处，但是更多的是这个过程中你学到的知识，那是使用别人开发的控制器说不能得到的宝贵知识。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;你能得到的&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;底层通信：基于Tornado架构的socket通信的搭建&lt;/li&gt;
&lt;li&gt;OpenFlow协议数据结构细节&lt;/li&gt;
&lt;li&gt;通信流程的事件处理&lt;/li&gt;
&lt;li&gt;若干网络协议的熟悉与掌握。&lt;/li&gt;
&lt;li&gt;最重要的，你自己从无到有，经历了一个开发过程，所有出现的你想到的想不到的问题，你都需要自己去解决。你会在解决问题的过程中收获太多太多你想不到的财富。&lt;/li&gt;
&lt;li&gt;自信！你可以大声对自己说，我可以！我可以做很多事情，因为我遇到了很多困难，但是我最终成功了！也许很简单，但是不是每一个人都能坚持去完成一个创新工作！&lt;strong&gt;有想法的人太多，持之以恒的人也很多，但是又想法，有持之以恒的人不多。我可以试着努力成为那样的人！&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;在下面的内容你会接触到的名词&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;socket&lt;/li&gt;
&lt;li&gt;tronado&lt;/li&gt;
&lt;li&gt;scapy&lt;/li&gt;
&lt;li&gt;mininet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;任何需要更多了解的请自行百度，google。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;底层通信&lt;/h2&gt;
&lt;p&gt;我们的控制器的底层通信是由socket通信搭建的。以下关于socket通信的内容均摘自：http://blog.csdn.net/xiaoweige207/article/details/6211577&lt;/p&gt;
&lt;p&gt;如果你想更详细地学习socket通信，可以去这个地址查看，也可以自行google。如果你已经了解socket通信，请跳到后面查看。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;socket的基本操作&lt;/h3&gt;
&lt;p&gt;socket操作模式：open -&amp;gt;write/read -&amp;gt;close&lt;/p&gt;
&lt;p&gt;基于这个模式，我们需要用到一下的函数。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;socket()函数&lt;/li&gt;
&lt;li&gt;bind()函数&lt;/li&gt;
&lt;li&gt;listen()、connect()函数&lt;/li&gt;
&lt;li&gt;accept()函数&lt;/li&gt;
&lt;li&gt;read()、write()函数等&lt;/li&gt;
&lt;li&gt;close()函数&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;socket()函数&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个函数相当于文件打开操作，会创建一个socket，返回的一个和文件描述符类似的标示符，这个标示符唯一对应一个socket。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数：&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;domain：即协议域，又称为协议族（family）。常用的协议族有，AF_INET、AF_INET6、AF_LOCAL（或称AF_UNIX，Unix域socket）、AF_ROUTE等等。协议族决定了socket的地址类型，在通信中必须采用对应的地址，如AF_INET决定了要用ipv4地址（32位的）与端口号（16位的）的组合、AF_UNIX决定了要用一个绝对路径名作为地址。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;type：指定socket类型。常用的socket类型有，SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等（socket的类型有哪些？）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;protocol：故名思意，就是指定协议。常用的协议有，IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等，它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意：并不是上面的type和protocol可以随意组合的，如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时，会自动选择type类型对应的默认协议。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当我们调用socket创建一个socket时，返回的socket描述字它存在于协议族（address family，AF_XXX）空间中，但没有一个具体的地址。如果想要给它赋值一个地址，就必须调用bind()函数，否则就当调用connect()、listen()时系统会自动随机分配一个端口。&lt;/p&gt;
&lt;h4&gt;bind()函数&lt;/h4&gt;
&lt;p&gt;正如上面所说bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。&lt;/p&gt;
&lt;p&gt;int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
函数的三个参数分别为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sockfd：即socket描述字，它是通过socket()函数创建了，唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。&lt;/li&gt;
&lt;li&gt;addr：一个const struct sockaddr *指针，指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;通常服务器在启动的时候都会绑定一个众所周知的地址（如ip地址+端口号），用于提供服务，客户就可以通过它来接连服务器；而客户端就不用指定，有系统自动分配一个端口号和自身的ip地址组合。&lt;/strong&gt;这就是为什么通常服务器端在listen之前会调用bind()，而客户端就不会调用，而是在connect()时由系统随机生成一个。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TIP:&lt;/strong&gt;（具体请看链接）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在将一个地址绑定到socket的时候，请先将主机字节序转换成为网络字节序，而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。由于这个问题曾引发过血案！公司项目代码中由于存在这个问题，导致了很多莫名其妙的问题，所以请谨记对主机字节序不要做任何假定，务必将其转化为网络字节序再赋给socket。&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;listen()、connect()函数&lt;/h4&gt;
&lt;p&gt;如果作为一个服务器，在调用socket()、bind()之后就会调用listen()来监听这个socket，如果客户端这时调用connect()发出连接请求，服务器端就会接收到这个请求。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;backlog&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="nb"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socklen_t&lt;/span&gt; &lt;span class="n"&gt;addrlen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;listen 函数的第一个参数即为要监听的socket描述字，第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的，listen函数将socket变为被动类型的，等待客户的连接请求。&lt;/p&gt;
&lt;p&gt;connect 函数的第一个参数即为客户端的socket描述字，第二参数为服务器的socket地址，第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。&lt;/p&gt;
&lt;h4&gt;accept()函数&lt;/h4&gt;
&lt;p&gt;TCP服务器端依次调用socket()、bind()、listen()之后，就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后，就会调用accept()函数取接收请求，这样连接就建立好了。之后就可以开始网络I/O操作了，即类同于普通文件的读写I/O操作。&lt;/p&gt;
&lt;p&gt;int accept(int sockfd, struct sockaddr &lt;em&gt;addr, socklen_t &lt;/em&gt;addrlen);
accept函数的第一个参数为服务器的socket描述字，第二个参数为指向struct sockaddr *的指针，用于返回客户端的协议地址，第三个参数为协议地址的长度。如果accpet成功，那么其返回值是由内核自动生成的一个全新的描述字，代表与返回客户的TCP连接。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt;accept的第一个参数为服务器的socket描述字，是服务器开始调用socket()函数生成的，称为监听socket描述字；而accept函数返回的是已连接的socket描述字。一个服务器通常通常仅仅只创建一个监听socket描述字，它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字，当服务器完成了对某个客户的服务，相应的已连接socket描述字就被关闭。&lt;/p&gt;
&lt;h4&gt;read()、write()等函数&lt;/h4&gt;
&lt;p&gt;主要的网络IO函数有如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;read()/write()&lt;/li&gt;
&lt;li&gt;recv()/send()&lt;/li&gt;
&lt;li&gt;readv()/writev()&lt;/li&gt;
&lt;li&gt;recvmsg()/sendmsg()&lt;/li&gt;
&lt;li&gt;recvfrom()/sendto()&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在tronado中我们使用的是read()/write()&lt;/p&gt;
&lt;p&gt;read函数是负责从fd中读取内容.当读成功时，read返回实际所读的字节数，如果返回的值是0表示已经读到文件的结束了，小于0表示出现了错误。如果错误为EINTR说明读是由中断引起的，如果是ECONNREST表示网络连接出了问题。&lt;/p&gt;
&lt;p&gt;write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数。失败时返回-1，并设置errno变量。 在网络程序中，当我们向套接字文件描述符写时有俩种可能。1)write的返回值大于0，表示写了部分或者是全部的数据。2)返回的值小于0，此时出现了错误。我们要根据错误类型来处理。如果错误为EINTR表示在写的时候出现了中断错误。如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接)。&lt;/p&gt;
&lt;h4&gt;close()函数&lt;/h4&gt;
&lt;p&gt;在服务器与客户端建立连接之后，会进行一些读写操作，完成了读写操作就要关闭相应的socket描述字，好比操作完打开的文件要调用fclose关闭打开的文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;close一个TCP socket的缺省行为时把该socket标记为以关闭，然后立即返回到调用进程。该描述字不能再由调用进程使用，也就是说不能再作为read或write的第一个参数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt;close操作只是使相应socket描述字的引用计数-1，只有当引用计数为0的时候，才会触发TCP客户端向服务器发送终止连接请求。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Tornado&lt;/h3&gt;
&lt;p&gt;我们的底层是利用tornado搭建的。tornado是什么？请看：http://www.tornadoweb.cn/&lt;/p&gt;
&lt;p&gt;如果你没有写过tornado，建议去tornado官网上把简单的demo做一做。也可以在本站学习tornado,站内搜索可以找到。&lt;/p&gt;
&lt;p&gt;首先我们把需要的文件import进来：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;errno&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tornado&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ioloop&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ioloop&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;error是系统错误处理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;functools一个python的模块，我们需要用到的是他的partial函数。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="err"&gt;函数&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;

&lt;span class="err"&gt;通过为已经存在的某个函数指定数个参数，生成一个新的函数，这个函数只需要传入剩余未指定的参数就能实现原函数的全部功能，这被称为偏函数。&lt;/span&gt;&lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="err"&gt;内置的&lt;/span&gt;&lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="err"&gt;模块提供了一个函数&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="err"&gt;，可以为任意函数生成偏函数&lt;/span&gt;

    &lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;][,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在整个底层通信中我们需要用到tornado的ioloop去进行系统IO的调用，去对socket的内容读取和写入。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用系统socket&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;import缓存队列,用于存储待发送&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;系统时间&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4&gt;创建new_sock函数&lt;/h4&gt;
&lt;p&gt;其实这个函数只是为了建立多个socket的时候省一些代码，直接调用总比一条一条配置要快一些。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;new_sock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOL_SOCKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SO_REUSEADDR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setblocking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;目的：返回一个IPV4,字符串格式的的socket。第二句不需要管，我也不是很懂。第一个参数是普通socket的意思。具体的可以去这里查看：http://blog.csdn.net/chary8088/article/details/2486377&lt;/p&gt;
&lt;h4&gt;main函数&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_sock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6634&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;io_loop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ioloop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;getsockname&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;KeyboardInterrupt:&lt;/span&gt;
        &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;quit&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;目的是创建一个socket。将其绑定在6634端口上，IP地址为本机地址。然后listen(30),30是允许最大的连接数，我们可以将其增大一点，以适应许多的交换机连接控制器。&lt;/p&gt;
&lt;p&gt;调用tornado.ioloop去创建一个IOLoop的实例。&lt;/p&gt;
&lt;p&gt;callback函数中是通过epoll方式实现并发。将sock作为agent的指定参数，生成一个可调用的partial对象，赋值给callback,作用相当于函数，实际上就是把sock作为参数传送给了agent函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;添加一个句柄处理这个socket。标示为fileno(),处理内容为callback中内容。初始状态为READ(可读)。&lt;/p&gt;
&lt;p&gt;最后一个逻辑是启动ioloop,如果键入停止，则stop()。&lt;/p&gt;
&lt;h4&gt;accept数据&lt;/h4&gt;
&lt;p&gt;当我们建立起一个半连接的server_socket之后，我们需要去收取socket的数据。这个时候我们就需要调用到accept函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;#print fd, sock, events&lt;/span&gt;
    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EWOULDBLOCK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EAGAIN&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;raise&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setblocking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fd_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;
    &lt;span class="n"&gt;client_handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;client_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;i n agent: new switch&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;client_handle&lt;/span&gt;
    &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;我们为了统一处理，定义agent函数。accept函数在agent中调用，同时在agent中也有except处理。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;socket.accept()是由数据和地址组成的。connection.setblocking(0)定义阻塞方式为无阻塞，收到数据位空时，马上返回0，而不是继续等待。&lt;/p&gt;
&lt;p&gt;调用handle_connection()&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1 connection,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;起作用很简单，打印一些关键信息。&lt;strong&gt;将其放在main函数之前就好。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同时我们还需要建立一个字典用于保存connection中的数据，key为connection.fileno(),即使用connection的文件标示符。&lt;/p&gt;
&lt;p&gt;下一句使用到的函数：&lt;/p&gt;
&lt;h4&gt;client_handler(address, fd, events)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;client_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fd_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;#以fd为标示符，从map中读取相应的connection数据，即收取到的字符流&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ:&lt;/span&gt;&lt;span class="c1"&gt;#如果状态是可读的&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;#收取1024字节数据，长度可调。&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;            &lt;span class="c1"&gt;#非阻塞情况下如果收到的是空数据，则取消句柄&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;connection dropped&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;           &lt;span class="c1"&gt;#openflow报文最短是8字节，即报头8字节&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;not a openflow message&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;rmsg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;#封装ofp_header&lt;/span&gt;
                &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;                  &lt;span class="c1"&gt;#取出body&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
                &lt;span class="n"&gt;rmsg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;xid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   
            &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;    &lt;span class="c1"&gt;#将msg放入发送队列&lt;/span&gt;
            &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#更改IOloop的状态。&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE:&lt;/span&gt;   &lt;span class="c1"&gt;#如果以上的操作可以执行完，则ioloop状态转变为可写。&lt;/span&gt;
        &lt;span class="n"&gt;try:&lt;/span&gt;
            &lt;span class="n"&gt;next_msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_nowait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="c1"&gt;#将队列中的数据取出来&lt;/span&gt;
        &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty:&lt;/span&gt;
            &lt;span class="c1"&gt;#print &amp;quot;%s queue empty&amp;quot; % str(address)&lt;/span&gt;
            &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#取完数据之后恢复可读状态，等待数据。&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;#print &amp;#39;sending &amp;quot;%s&amp;quot; to %s&amp;#39; % (of.ofp_header(next_msg).type,    address)&lt;/span&gt;
            &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#发送给dpid&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个函数是最重要，也是最核心的函数。其主要作用是对socket进行读写操作。先读后写，正常打开socket的写保护，保证文件锁的顺序，不会出现错误。&lt;/p&gt;
&lt;p&gt;这里的重点是ioloop的状态转变，从read初始状态到改变成write，把所有发给改dpid的数据发送完，然后再把ioloop的状态恢复为可读状态，程序执行过程中不断在等待数据到来。可读状态时，则读取数据，对数据进行操作。最后还需要将ioloop状态改为write，使能数据写入。&lt;/p&gt;
&lt;p&gt;代码中提到数据结构message_queue_map[sock]，我们需要在程序中定义一个数据结构:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;放在import之后就可以了。&lt;/p&gt;
&lt;p&gt;回到&lt;strong&gt;accept&lt;/strong&gt;函数：最后一句就是给message_queue_map[connection]初始成一个队列。&lt;/p&gt;
&lt;p&gt;至此底层的socket算是搭建完成。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;事件处理——OpenFlow协议&lt;/h2&gt;
&lt;p&gt;当底层通信搭建完成了之后，我们就需要对收到的数据进行一些处理，这些处理的规则就是OpenFlow协议。&lt;/p&gt;
&lt;p&gt;如何能实现事件处理？你需要做两件事情：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;编写一个静态库，用于定义OpenFlow数据结构。&lt;/li&gt;
&lt;li&gt;按照OpenFlow协议处理socket收取到数据，即事件处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;首先，我们需要一个静态库，里面是关于OpenFlow中使用到的报文的定义。&lt;/p&gt;
&lt;h3&gt;scapy&lt;/h3&gt;
&lt;p&gt;我们使用scapy来对数据进行封装和解封装。什么是scapy?http://www.secdev.org/projects/scapy/&lt;/p&gt;
&lt;p&gt;本博客中也有scapy的简单教程：http://www.muzixing.com/pages/2013/11/29/yuan-chuang-scapyjian-dan-jiao-cheng.html&lt;/p&gt;
&lt;p&gt;如果你想详细地了解openflow的数据结构，我建议你照着协议重新画一遍，或者到sdnap.com上搜索一篇叫：openflow美丽的数据结构的文章，稍后也将在搬到本博客。画完之后，我们再使用scapy去定义这些数据结构，经历了这些学习之后，你会对openflow协议有一个非常清晰明了的认识。&lt;/p&gt;
&lt;p&gt;scapy的封装非常简单。&lt;/p&gt;
&lt;p&gt;如定义ofp_header:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OpenFlow Header &amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;fields_desc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;XByteField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ByteEnumField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp_type&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ShortField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;IntField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;xid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;再如，定义ofp_phy_port&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ofp_phy_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OpenFlow Port&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;fields_desc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;ShortEnumField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;port_no&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp_port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;MACField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hw_addr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;00:00:00:00:00:00&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;StrFixedLenField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;port_name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not_defined&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_PACKET_IN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_FWD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_FLOOD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_RECV_STP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_RECV&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_STP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_PORT_DOWN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for state&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;else&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPS_LINK_DOWN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for Current features&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not_defined&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_PAUSE_ASYM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_PAUSE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_AUTONEG&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_FIBER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_COPPER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_10GB_FD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_1GB_FD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_1GB_HD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_100MB_FD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_100MB_HD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_10MB_FD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_10MB_HD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for features being advised by the port&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;advertised&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for features supported by the port&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;supported&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for features advertised by peer&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;peer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这里面的每一个字段，你都需要照着OpenFlow协议一个个定义。你可能会用到的函数有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bitfield("name",default_value,length)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XByteField("name",default_value)  length =8&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X3ByteField("name",default_value)  length =3X8=24&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ByteEnumField("name", default_value, type)  length=8&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IntField("name",default_value)   length =32&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ShortField("name",default_value) length =16&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MACField("name",default_value)  format:"00:00:00:00:00:00"&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ShortEnumField("name", default_value, type)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;StrFixedLenField("name", default_value, length)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPField("name",default_value)format ="0.0.0.0"&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还有其他的封装函数，理解起来也很简单，按照以上函数的逻辑去理解其他的函数应该没有问题。&lt;/p&gt;
&lt;p&gt;如果你想让自己学到更多，那么自己重新写一遍这些数据结构吧。如果你想直接用，你可以到我的github上去下载Controller中的libopenflow.py文件。里面已经写了很多。你可以去这里查看：https://github.com/muzixing/Controller/blob/master/libopenflow.py&lt;/p&gt;
&lt;p&gt;假设你已经写了一些数据包，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;header&lt;/li&gt;
&lt;li&gt;error&lt;/li&gt;
&lt;li&gt;hello&lt;/li&gt;
&lt;li&gt;features&lt;/li&gt;
&lt;li&gt;flow_mod&lt;/li&gt;
&lt;li&gt;packet_in&lt;/li&gt;
&lt;li&gt;packet_out&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么你可以进行下一步了。因为这些数据包是完成数据交换，即下发正确流表需要的最少的报文。&lt;/p&gt;
&lt;h3&gt;事件处理&lt;/h3&gt;
&lt;p&gt;可能很多高级的控制器都有自己定义的事件处理，我编程也是菜鸟水平，暂且以为这是对socket中收取的数据的处理吧，应该就是所谓的事件处理。&lt;/p&gt;
&lt;h4&gt;处理规则&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;OpenFlow1.0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们从socket中读取数据流，并使用scapy对数据进行封装和解封装，使用到的静态库就是上一小节提到的libopenflow。&lt;/p&gt;
&lt;p&gt;对socket数据的处理，需要在client_handler中去处理。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;client_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fd_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;connection dropped&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;not a openflow message&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;rmsg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;rmsg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;               &lt;span class="c1"&gt;# 判断header中类型。&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_HELLO&amp;quot;&lt;/span&gt;
                &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;#发送ofp_features_request&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_FEATURES_REQUEST&amp;quot;&lt;/span&gt;
                &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#hello放入发送队列&lt;/span&gt;
                &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;#ofp_features_request放入队列。&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE:&lt;/span&gt;
            &lt;span class="n"&gt;try:&lt;/span&gt;
                &lt;span class="n"&gt;next_msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_nowait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty:&lt;/span&gt;
                &lt;span class="c1"&gt;#print &amp;quot;%s queue empty&amp;quot; % str(address)&lt;/span&gt;
                &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;#print &amp;#39;sending &amp;quot;%s&amp;quot; to %s&amp;#39; % (of.ofp_header(next_msg).type, address)&lt;/span&gt;
                &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;#发送数据。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;我们需要将目光注意到这段代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;               &lt;span class="c1"&gt;# 判断header中类型。&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_HELLO&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;#发送ofp_features_request&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_FEATURES_REQUEST&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#hello放入发送队列&lt;/span&gt;
    &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;#ofp_features_request放入队列。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;首先，rmsg是取前8字节封装的header(),根据不一样的type触发事件，并对事件进行处理。&lt;/p&gt;
&lt;p&gt;下面的代码给出了一些type的处理逻辑：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_ERROR&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_error_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;#当报错的时候我们应该把错误打印出来，以便解决错误&lt;/span&gt;
&lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_ECHO_REQUEST&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_ECHO_REPLY&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_VENDOR&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_FEATURES_REQUEST&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;OFPT_FEATURES_REPLY的处理&lt;/h4&gt;
&lt;p&gt;接下来是一个非常重要的报文的处理：ofp_features_reply的封装与解析&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_FEATURES_REPLY&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_features_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;                     &lt;span class="c1"&gt;#length of reply msg&lt;/span&gt;
    &lt;span class="n"&gt;sock_dpid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath_id&lt;/span&gt;                          &lt;span class="c1"&gt;#sock_dpid[fd] comes from here.&lt;/span&gt;

    &lt;span class="n"&gt;port_info_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;                              &lt;span class="c1"&gt;#we change it into str so we can manipulate it.&lt;/span&gt;
    &lt;span class="n"&gt;port_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;port number:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_info_raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;total length:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_info_raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_info_raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_phy_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_info_raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt;
        &lt;span class="n"&gt;port_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;                           &lt;span class="c1"&gt;#save port_info by port_no&lt;/span&gt;

    &lt;span class="n"&gt;features_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c1"&gt;#features_info[dpid] = (sw_features, port_info{})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;首先我们需要将获取到的数据判断类型，将前8字节封装成header，通过查看header（）.type来决定如何处理。当type=6时，这个报文对应的类型是ofp_features_reply。通过协议中的数据结构定义，我们知道他的结构是由switch的features和port的features组成。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_features_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;body是data[8:]的字节流，即除去header部分的内容。body[0:24]的内容是switch_features的内容。将其使用我们自己定义的of.ofp_features_reply()去封装，将得到一个ofp_features_reply()的结构体。从而我们可以查看和修改相应属性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sock_dpid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath_id&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;同时，我们应该注意到一个很重要的参数：&lt;strong&gt;datapath_id&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;每一个交换机对应一个&lt;strong&gt;datapath_id&lt;/strong&gt;，我们需要通过datapath_id(以下简称:dpid)对交换机发送消息。当然每一个交换机跟控制器之间都有一个socket连接，每一个socket连接都会有一个fd标志。我们需要建立一个字典去存储这些对应关系：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sock_dpid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其key-value对应对如上所示。将其放在import之后即可，即作为全局变量存在。&lt;/p&gt;
&lt;p&gt;为什么需要建立这么一个字典呢？原因我总结如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;每一个交换机与控制器连接的时候都会建立一个socket连接，但不限于一个socket连接，所以fd并不是唯一一个，但是dpid是唯一的，所以更精确的说法是通过dpid去下发命令，而不是socket下发命令。所以我们需要得到dpid,最简单的存储就是使用fd去对应。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以后的若干报文需要使用到dpid字段，使用fd为key存储起来，使用时读取更加方便。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们先来了解一下features到底有什么字段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# No. 6&lt;/span&gt;
&lt;span class="c1"&gt;# [header|features_reply|port]&lt;/span&gt;
&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ofp_features_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OpenFlow Switch Features Reply&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;fields_desc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;datapath_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;n_buffers&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;XByteField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;n_tables&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;X3BytesField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pad&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="c1"&gt;#features&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NOT_DEFINED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_ARP_MATCH_IP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;7 Match IP address in ARP packets&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_QUEUE_STATS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;6 Queue statistics&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_IP_STREAM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;     &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;5 Can reassemble IP fragments&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_RESERVED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;      &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;4 Reserved, must be zero&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_STP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;           &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;3 802.1d spanning tree&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_PORT_STATS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;    &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;2 Port statistics&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_TABLE_STATS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;1 Table statistics&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_FLOW_STATS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;    &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;0 Flow statistics&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;actions&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="c1"&gt;#port info can be resoved at TCP server&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;bind_layers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp_features_reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从上面的数据结构中，我们可以知道，features部分有许多功能的使能位。这些都是&lt;strong&gt;极其重要的信息&lt;/strong&gt;。我们需要根据这些信息来确定到底使用什么动作，什么样的动作能起效。如OFPC_FLOW_STATS位如果没有使能，则在switch在交换数据的时候，并不会去记录流的统计信息。也就是说，我们如果想要读取统计信息，那么这个位必须为1！当然大概率下，switch默认的状态是统计各项数据的。如果发现得不到数据，你可以查看features的内容进行确认。如果没有使能，则需要通过OFPT_SET_CONFIG去配置。&lt;/p&gt;
&lt;p&gt;回到type=6的处理代码段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="n"&gt;port_info_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;                              &lt;span class="c1"&gt;#we change it into str so we can manipulate it.&lt;/span&gt;
        &lt;span class="n"&gt;port_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;port number:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_info_raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;total length:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_info_raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_info_raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_phy_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_info_raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt;
            &lt;span class="n"&gt;port_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;                           &lt;span class="c1"&gt;#save port_info by port_no&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其意义在于将后面的字节流按port信息长度48bytes去切割，并封装成of.ofp_phy_port。
同时将port保存在port_info字典中，key为port.port_no。&lt;/p&gt;
&lt;p&gt;最后我们需要将这些重要的信息存储起来：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;features_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datapath_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;features_info字典我们需要在主文件中去声明，将其放在import之后，作为全局变量存在。&lt;/p&gt;
&lt;p&gt;这些重要信息存储起来以便接下来的操作使用。&lt;/p&gt;
&lt;p&gt;type=7,8,9的类型在这里就不一一作介绍，如果你需要用到她们，你可以自己去写出相应的处理逻辑，其依据就是OpenFlow协议1.0。&lt;/p&gt;
&lt;h4&gt;OFPT_PACKET_IN的处理&lt;/h4&gt;
&lt;p&gt;跳过了7，8，9三个类型的处理，我们下面讲的是非常重要的type=10的处理。&lt;/p&gt;
&lt;p&gt;packet_in的type=10,其作用如果不清楚，请查看协议，或者查看本博客《OpenFlow协议通信流程解读》，相信读完之后，你会有一个清晰的认识。&lt;/p&gt;
&lt;p&gt;packet_in 报文上来之后，由于他本身携带的数据的类型的不确定性，所以处理起来也相对比较麻烦。&lt;/p&gt;
&lt;p&gt;首先我们需要将其分为两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;具有广播性质的数据如：ARP&lt;/li&gt;
&lt;li&gt;普通数据通信报文：如IP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这两者将触发不一样的处理机制，前者会触发packet_out,而后者会触发flow_mod。&lt;/p&gt;
&lt;h4&gt;OFPT_PACKET_OUT&lt;/h4&gt;
&lt;p&gt;当第一个数据包上来的时候，我们默认主机发送的是ARP包，这样我们可以省去很多不必要的逻辑，当然这些逻辑在进一步完善的时候需要添加。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;pkt_in_msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_packet_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#首先将其封装成packet_in数据格式&lt;/span&gt;
                &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pkt_in_msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;       
                &lt;span class="n"&gt;pkt_parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ether&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#将payload封装成Ether格式&lt;/span&gt;
                &lt;span class="n"&gt;pkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="sr"&gt;/pkt_in_msg/&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;  &lt;span class="c1"&gt;#将结构体重组&lt;/span&gt;
                &lt;span class="n"&gt;dpid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock_dpid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;#if there is not the key of sock_dpid[fd] ,it will be an error.&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

                    &lt;span class="n"&gt;pkt_out_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_pktout_header()/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_action_output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="n"&gt;pkt_out_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xfffb&lt;/span&gt;
                    &lt;span class="n"&gt;pkt_out_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pkt_in_msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;
                    &lt;span class="n"&gt;pkt_out_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pkt_in_msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;
                    &lt;span class="n"&gt;pkt_out_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;actions_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
                    &lt;span class="n"&gt;pkt_out_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;

                    &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkt_out_&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;首先我们需要的对数据封装，首先把整个body封装成packet_in报文，然后将packet_in的装载，此处为load,为什么不是payload呢？payloadd是净荷，下一级是有结构的数据。而load也是净荷，但是此处应是字节流。（不是很了解，求大神纠正）&lt;/p&gt;
&lt;p&gt;将packet_in的load封装成Ether()格式的报文，即pkt_parsed。Ether()是scapy提供的封装函数。同时，&lt;strong&gt;通过fd，读取出对应的dpid.&lt;/strong&gt;同时我们需要将rmsg,pkt_in_msg,pkt_parsed三者组合起来，组装成pkt。用于后面flow_mod的使用。&lt;/p&gt;
&lt;p&gt;若payload的类型是ARP,则会触发pkt_out。pkt_out的结构是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_pktout_header()/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_action_output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;然后我们再将必要的信息，如发送的端口：0xfffb，也就是FLOOD端口。这个数据包的意义在于：通知交换机可以对这个包进行广播。下一个交换机收到ARP之后，进行同样的操作，出发packet_in事件，然后下发packet_out指令。直到找到arp的回应。&lt;/p&gt;
&lt;p&gt;当处理完ARP之后，packet_in会触发ofp_flow_mod操作。&lt;/p&gt;
&lt;h4&gt;OFPT_FLOW_MOD的处理&lt;/h4&gt;
&lt;p&gt;这一小节是一个特别重要的小节，是整一个控制器通信部分最核心的部分！&lt;/p&gt;
&lt;p&gt;首先，packet_in报上来的报文可能有很多类型，可能是二层的，可能是三层的，可能是四层。有可能是纯IP的，有可能是带有VLAN tags的IP，也有可能是TCP等等。所以我们需要针对不同的类型的数据进行不同的操作。&lt;/p&gt;
&lt;p&gt;我们在这里只处理四种类型的数据：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;四层报文：0x8100带有vlan tags的TCP,UDP,SCTP&lt;/li&gt;
&lt;li&gt;四层报文：0x800纯IP的TCP,UDP,SCTP&lt;/li&gt;
&lt;li&gt;三层报文：0x8100带有vlan tags的IP&lt;/li&gt;
&lt;li&gt;三层报文：0x0800纯IP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于处理逻辑相对比较复杂，代码量也比较多，所以我们新建一个F_mod的文件，在文件中定义一个flow_mod(packet_in)的函数。用于处理flow_mod事件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pkt_parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="c1"&gt;#读取三层即以上数据。&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;########################TCP OR UDP OR SCTP(L4)#####################&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TCP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UDP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SCTP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;  &lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mh"&gt;0x8100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;#带有vlan_tags&lt;/span&gt;
                &lt;span class="n"&gt;flow_mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_wildcards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFPFW_NW_TOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_DL_VLAN_PCP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_NW_DST_MASK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_NW_SRC_MASK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_TP_DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_TP_SRC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_NW_PROTO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_DL_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_DL_VLAN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_IN_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_DL_DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;OFPFW_DL_SRC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
                           &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;dl_src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;dl_dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;dl_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;dl_vlan&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vlan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;nw_tos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;nw_proto&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;nw_src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;nw_dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;tp_src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;tp_dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
                           &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                            &lt;span class="n"&gt;idle_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                            &lt;span class="n"&gt;hard_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                            &lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;0xfffb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                            &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                            &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;flow_mod_msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/flow_mod/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_action_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_action_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;0xfffb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;flow_mod_msg&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;header&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首先我们需要注意到的是flow_mod的header里面的信息。没有任何action时的flow_mod长度为72。前8bytes是header,接下来4个bytes是wildcards，再接下来36bytes是match，最后的24字节是flow_mod的数据。这些长度值都是应该熟记于心的，如果你认真研究过协议的话。&lt;/p&gt;
&lt;p&gt;如果需要添加action，则每增加一个action,长度都会增加8，所以最后的长度必定是8的倍数。正常情况下，建议加上action_header()。如action_output()，则需要添加action_header(type=0)。注意：header中的length必须要填！如果不填，则会包长度错误。血的教训在这里！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;wildcards&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在OpenFlow1.0中，wildcards的性质与常规认知相反，并不是子网掩码性质的直接与，而是中断屏蔽向量形式的逻辑。即1为屏蔽，0为默认匹配。所以wildcards的填写将决定你最后的流能不能通。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;match&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;match域最重要，这是一个流的属性。我们使用packet_in的信息去填充即可。如in_port=pkt.payload.in_port。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;flow_mod&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;flow_mod域需要填的东西主要有以下几个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;command&lt;/li&gt;
&lt;li&gt;idle_timeout&lt;/li&gt;
&lt;li&gt;hard_timeout&lt;/li&gt;
&lt;li&gt;out_port&lt;/li&gt;
&lt;li&gt;buffer_id&lt;/li&gt;
&lt;li&gt;flags&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;让我们来仔细分析这些字段都有哪些用处。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;command 是flow_mod的动作类型。command=0-&amp;gt;add ......command =3-&amp;gt;action=del&lt;/li&gt;
&lt;li&gt;idle_timeout 流活跃匹配时间。可设置为0&lt;/li&gt;
&lt;li&gt;hard_timeout   流存在时间，为0时表示永久存在。&lt;/li&gt;
&lt;li&gt;out_port       目前我们还无法获取端口，所以取值为0xfffb，即泛洪。&lt;/li&gt;
&lt;li&gt;buffer_id      使用packet_in的buffer_id&lt;/li&gt;
&lt;li&gt;flags          填1，指明流删除时需要回报一个flow_removed信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;填写完这些关键信息之后，我们的flow_mod报文基本成型，此时报文长度72bytes。我已经记得很清楚这些长度了，再说一遍，header中的length一定要填对！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;action&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;接下来就是action的填写。每一条流表都需要携带action，若没有指定的action则默认将执行drop操作。&lt;/p&gt;
&lt;p&gt;action_header()中我们需要填type。如果是添指定out_port则type=0。其他的类型查看协议填写既可。添加完action_header()之后，紧跟其后的是动作实体：如ofp_action_output(type =0,port=port,len =8)。&lt;/p&gt;
&lt;p&gt;action有许多，如可以设置vlan,剔除vlan等操作。我们可以通过action实现需要功能，特别是在1.3版本中。&lt;/p&gt;
&lt;p&gt;至此，四层的带vlan_tags的flom_mod封装完成。&lt;/p&gt;
&lt;p&gt;同理，三层IP，或者不带四层端口的数据，我们在填充时，可以将四层的端口项设0，同时在wildcards中将四层端口屏蔽。&lt;/p&gt;
&lt;p&gt;match中&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;tp_src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;tp_dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;wildcards中&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;OFPFW_TP_DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;OFPFW_TP_SRC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;至此我们已经把三层到4层的带vlan_tags的flow_mod封装好。&lt;/p&gt;
&lt;p&gt;同理对于&lt;strong&gt;Ether中type=0x800&lt;/strong&gt;的不带vlan tags的数据，我们无法从packet_in中提取vlan。所以vlan字段我们可以不去填充，默认的会填充某一个默认值。当然我们需要把wildcards中的OFPFW_DL_VLAN置1。&lt;/p&gt;
&lt;p&gt;也就是说到目前为止，以上提到的四种类型的报文对应的flow_mod我们都已经有能力封装好。&lt;/p&gt;
&lt;p&gt;在rmsg.type==10:的逻辑下,添加如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;else:&lt;/span&gt;
    &lt;span class="err"&gt;msg&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;F_mod.flow_mod(pkt)&lt;/span&gt;
    &lt;span class="err"&gt;message_queue_map[sock].put(str(msg))&lt;/span&gt;
    &lt;span class="err"&gt;io_loop.update_handler(fd,&lt;/span&gt; &lt;span class="err"&gt;io_loop.WRITE)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;F_mod是你自己写的文件，文件中定义def flow_mod()函数。当然在文件头部，我们需要&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;_mod&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;至此packet_in触发的事件大体处理完成。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不出意外的话，这个时候如果打流，是可以通的！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;但是我们还需要注意到一点：&lt;strong&gt;我们还没有将下发的流表保存起来。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;所以马上建立一个列表：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;flow_cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;同时在将上面一段代码改为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;else:&lt;/span&gt;
    &lt;span class="err"&gt;msg&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;F_mod.flow_mod(pkt)&lt;/span&gt;
    &lt;span class="err"&gt;flow_cache[fd].append=(time.time(),msg)&lt;/span&gt;
    &lt;span class="err"&gt;message_queue_map[sock].put(str(msg))&lt;/span&gt;
    &lt;span class="err"&gt;io_loop.update_handler(fd,&lt;/span&gt; &lt;span class="err"&gt;io_loop.WRITE)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;OFPT_STATS_REQUEST的处理&lt;/h4&gt;
&lt;p&gt;当流表下发成功之后，我们可以通过OFPT_STATS_REQUEST去获取流的统计信息。这是许多业务的基础。没有流量统计信息，就没有操作的基础。所以这一小节是自编控制器的提升功能，也是必要功能。&lt;/p&gt;
&lt;p&gt;OFPT_STATS_REQUEST&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;type=16&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不同的请求对应不同的数据结构。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ofp_stats_types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPST_DESC&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPST_FLOW&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPST_AGGREGATE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPST_TABLE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPST_PORT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPST_QUEUE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mh"&gt;0xffff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPST_VENDOR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;好吧，我们努力把这6个都是实现吧。很明显，处理完这六个类型的操作，最好写成一个独立的小文件。&lt;/p&gt;
&lt;p&gt;我们可以写一个文件：stats_request，然后import 进来。&lt;/p&gt;
&lt;p&gt;在文件里面我们需要定义这样一个函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;libopenflow&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flow_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;flow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ofp_flow_wildcards&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_wildcards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ofp_match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ofp_flow_mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;action_header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_action_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;action_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_action_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="c1"&gt;#we need to send the stats request packets periodically&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;                            &lt;span class="c1"&gt;#Type of  OFPST_DESC (0) &lt;/span&gt;
            &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_stats_request(type =1)/o&lt;/span&gt;&lt;span class="n"&gt;fp_flow_wildcards&lt;/span&gt;&lt;span class="sr"&gt;/ofp_match/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_flow_mod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;                  &lt;span class="c1"&gt;#flow stats&lt;/span&gt;
            &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_stats_request(type = 2)/o&lt;/span&gt;&lt;span class="n"&gt;fp_flow_wildcards&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_match/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_aggregate_stats_request&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;                                  &lt;span class="c1"&gt;# aggregate stats request&lt;/span&gt;
            &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;                            &lt;span class="c1"&gt;#Type of  OFPST_TABLE (0) &lt;/span&gt;
            &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_stats_request(type = 4)/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_port_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c1"&gt;# port stats request    &lt;/span&gt;
            &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_stats_request(type =5)/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_queue_stats_request&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;#queue request&lt;/span&gt;
            &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xffff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                        &lt;span class="c1"&gt;#vendor request&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;首先我们可以看到函数有3个参数。Type,flow_1,port=None。Type是stats_request的类型，flow_1对应某条流表。这条流表，我们可以从之前的flow_cache中提取。也可以自己填充，这就需要自己在主文件中自己写一个逻辑了，使用raw_input()应该就可以设计出一个逻辑，用于手动发请求统计信息。我们这里选择最简单的，把flow_cache[fd]中所有的存在的流都用于填充stats_request()，即向所有活跃着的流都发送统计信息请求。&lt;/p&gt;
&lt;p&gt;在主文件的if events &amp;amp; io_loop.WRITE:之前，与之对齐写下如下代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ready&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pre_time&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;period:&lt;/span&gt;  
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;send stats_requests&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;flow&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;flow_cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stats_request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;

            &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;pre_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;pre_time,period和ready为全局变量，可以在features_reply逻辑之后添加代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;global&lt;/span&gt; &lt;span class="n"&gt;ready&lt;/span&gt;    
&lt;span class="n"&gt;ready&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;pre_time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;period可以任意设置，比如设置为3则为3秒发送一次stats_request。这样我们就可以实现循环发送stats_request了。&lt;/p&gt;
&lt;p&gt;回过来我们，我们关注一下我们发送的是什么东西。介绍一下type=1，到底发送了什么。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
        &lt;span class="sr"&gt;/ofp_flow_wildcards/o&lt;/span&gt;&lt;span class="n"&gt;fp_match&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
        &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_flow_mod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;header之后紧跟着ofp_stats_request(type=1)，代表这个request是请求flow的信息。紧接着是熟悉的wildcards和match。最后是消息实体ofp_flow_stats_request(out_port=port)&lt;/p&gt;
&lt;p&gt;在这里有一些信息我们并没有填出来，但是他们非常重要。比如ofp_flow_stats_request()中&lt;strong&gt;table_id 我们需要通过table对应的request去获取，如果没有获取，可以填0xff,即没有限制。对于out_port也是一样，如果无法获取port,则可以填0xffff,即None。同样表示无限制。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;其他的类型就不一一介绍了，细心去看协议都可以写出来。&lt;/p&gt;
&lt;h4&gt;OFPT_STATS_REPLY的处理&lt;/h4&gt;
&lt;p&gt;交换机收到stats_request之后，会按照匹配结果向控制器返回stats_reply。同样的，有多少种stats_request就会对应有多少种stats_reply。&lt;/p&gt;
&lt;p&gt;所以reply的处理也是一件很重要的事情。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPT_STATS_REPLY&amp;quot;&lt;/span&gt;
                &lt;span class="n"&gt;reply_header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_stats_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;reply_desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_desc_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
                    &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;reply_body_data1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                    &lt;span class="n"&gt;reply_body_wildcards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_wildcards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                    &lt;span class="n"&gt;reply_body_match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

                    &lt;span class="n"&gt;reply_body_data2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_stats_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

                    &lt;span class="n"&gt;reply_body_action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                         &lt;span class="c1"&gt;#it is very important!&lt;/span&gt;
                        &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;
                        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                            &lt;span class="n"&gt;reply_body_action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_action_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

                    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="sr"&gt;/reply_body_data1/&lt;/span&gt;&lt;span class="n"&gt;reply_body_wildcards&lt;/span&gt;&lt;span class="sr"&gt;/reply_body_match/&lt;/span&gt;&lt;span class="n"&gt;reply_body_data2&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;代码很长，我们先重点讲一下，我们刚才发送的type=1的flow_stats_request对应的reply应该如何解析。首先我们需要按照数据结构将其分割成对应的：&lt;/p&gt;
&lt;p&gt;ofp_flow_stats()，ofp_wildcards(),ofp_match()和ofp_flow_stats_data()4部分。&lt;/p&gt;
&lt;p&gt;在第四部分中我们能得到很多信息，如流表生存时间，匹配上的字节数，包数目等关键信息。这些可以在《OpenFlow通信流程解读》中清楚了解到。同理我们将其他类型的报文处理写在了下面。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;                &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;reply_aggregate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_aggregate_stats_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
                    &lt;span class="n"&gt;reply_aggregate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

                &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;#table_stats&lt;/span&gt;
                    &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
                    &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                        &lt;span class="n"&gt;table_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                        &lt;span class="n"&gt;reply_table_stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_table_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_body&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                        &lt;span class="n"&gt;table_wildcards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_wildcards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                        &lt;span class="n"&gt;reply_table_stats_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_table_stats_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                        &lt;span class="n"&gt;msg_tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="sr"&gt;/reply_table_stats/&lt;/span&gt;&lt;span class="n"&gt;table_wildcards&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;reply_table_stats_data&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;msg_tmp&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
                &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;#port stats reply&lt;/span&gt;
                    &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
                    &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;104&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                        &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;104&lt;/span&gt;
                        &lt;span class="n"&gt;reply_port_stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_port_stats_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;104&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
                        &lt;span class="n"&gt;msg_tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;reply_port_stats&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;msg_tmp&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;#queue reply&lt;/span&gt;
                    &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
                    &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num:&lt;/span&gt;                     &lt;span class="c1"&gt;#if the queue is empty ,you need to check it !&lt;/span&gt;
                        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
                            &lt;span class="n"&gt;queue_reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_queue_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset:offset&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                            &lt;span class="n"&gt;msg_tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;queue_reply&lt;/span&gt;
                        &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;msg_tmp&lt;/span&gt;
                        &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;reply_header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mh"&gt;0xffff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;#vendor reply&lt;/span&gt;
                    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rmsg&lt;/span&gt;&lt;span class="sr"&gt;/reply_header/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_vendor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;table request可以获取table的内容，如table0中有多少流等等。&lt;/p&gt;
&lt;p&gt;port request可以获取端口上的信息。再这里不再展开，读者可自行研究。&lt;/p&gt;
&lt;p&gt;至此我们已经顺利处理完stats_reply的所有类型的数据。我们可以很好地利用统计信息去做文章，比如利用流量统计去做负载均衡的实验等等。&lt;/p&gt;
&lt;h4&gt;其他的报文&lt;/h4&gt;
&lt;p&gt;其他的报文相对于以上的报文不是特别重要，当然如果你有精力，那就把整个OpenFlow整个都实现。相信以上的实现之后，后面的也会变得特别简单。以下就举例介绍两个相对比较重要的报文。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;barrier&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们无法获知流表下发是否已经写入成功。或者我们想确认某个指令下发到交换机，并已经执行成功，我们应该怎么去得到这个回执呢？&lt;/p&gt;
&lt;p&gt;这个时候你就需要使用到barrier。&lt;/p&gt;
&lt;p&gt;在你想确认的报文之后下发一条barrier_request，当交换机执行到barrier的时候，前面的指令都已经执行完。交换机会回复barrier_reply给控制器，通知已经执行完barrier，即前面的指令已经执行完。控制器默认前面的指令已经执行成功，因为错误的情况会报错。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;flow_removed&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是一条貌似可有可无的报文，但是事实上非常重要。只要你在下发flow的时候将flags置1，那么当流表失效或者被删除时，switch就会上报一个flow_removed。我们怎么才能利用这个消息呢？&lt;/p&gt;
&lt;p&gt;我们可以把这个消息打印出来，去查看他的内容，看看各个字段是不是想要的值。因为曾经我们就是从这个报文的打印信息中发现我们的流没有下发对的。最后将最麻烦的问题解决了，所以这个报文可以好好利用，可以查看流表在switch上的情况。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;上层应用&lt;/h2&gt;
&lt;p&gt;终于写完了底层通信部分。以上的部分已经可以保证一件事情，可以在非环形网中实现通信，因为环形网会存在网络风暴，而我们上面的代码并没有避免网络风暴的措施。所以说上面的控制器最好&lt;strong&gt;运行在一个树形的网络中，而不应该存在环路。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如何解决网络风暴？我们需要解决两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ARP泛洪时会引起的网络风暴&lt;/li&gt;
&lt;li&gt;正常通信时引起的环路风暴。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一个容易解决，有一个最简单的办法就是在控制器上写一个小小的判断逻辑：如果某ARP报文的入口不是记录在字典中的入端口，则丢弃。这样保证同一个ARP包不会再次进入交换机，从而解决网络风暴。&lt;/p&gt;
&lt;p&gt;第二个主要解决方法是编写路由算路算法，算出路径，从而在下发流表的时候将原有的port=0xfffb,替换成算路算出来的端口。这样就可以解决这两个问题。同时也可以解决3层路由问题。&lt;/p&gt;
&lt;p&gt;更多的上层应用，这里不再介绍，有兴趣的读者可以自己继续研究。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;后续&lt;/h2&gt;
&lt;p&gt;写了这么多，好累好累。但是感觉还不错，起码这四个月的成果算是写得差不多了。还有一些秘密不能写，也不该写，所以就没写。像以上的教程，耐心做下来其实还是很有趣的。其重点也许并不是做一个多么牛逼的控制器，而是通过这个过程，对OpenFlow的了解。SDNAP群里的一个群友说的挺对的：也许通过写一遍控制器代码是最好的学习方法。写完这个控制器之后，我可以从OpenFlow的事件处理，哪一个报文有多长，有多少字段，都有什么用，到底层通信的socket搭建说个大概，我很自信，我能完成这个工作！也许这个控制器很弱，很弱，他甚至没有把算路的功能给大家写出来！（当然已经实现了！哈哈！）也许相比于floodlight，opendaylight,contrial等牛逼的主流控制器都弱上不知道多少倍！甚至连比较的资格都没有！可是那又怎么样呢！我完成了他！一句一句写下来的不仅仅是代码，更是心血！&lt;/p&gt;
&lt;p&gt;从来没有这么认真地去完成一件事情！有时候人生就从某一件给你带来巨大成就感的事情开始有了转变！我始终相信，每一站，我都会努力做好着，而这一站，我收获了巨大的成功！我自己认为的巨大成功！没有什么嘉奖，没有什么的名誉！我只是很热爱，很兴奋地去做一件我很自豪的事情！&lt;strong&gt;没有什么事情比带着愉快的心情去做一件让自己充满自豪感的事情更幸福了！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;很高兴我在年轻的时候选择了一个我目前看来很喜欢的方向，并在这条道路上越走越远！很高兴我能在SDNAP这个大家庭里遇到很多好玩的朋友，很多比我大很多很多的大哥，大叔！这里有很多我的老师，比如地球-某某，KKBluE,盛科-卫峰，无厘头等！在完成这个控制器的道路上他们给了我许多指导，特别是地球-某某老师。&lt;/p&gt;
&lt;p&gt;最后，当年那两个年轻有为的学长，如今一个在美团，一个在美帝的那两个熟悉的人。带我走进OpenFlow世界，同时这个控制器也是他们首先开始编写的。后来才由我来完成这个小小的控制器！谢谢学长！！&lt;/p&gt;
&lt;p&gt;差点忘了，一起奋斗的小伙伴，老伙伴！工信部的adam可是给我很多机会，给我很多帮助的博士哥！一起加班的时候聊天感觉特别好！！能一起奋斗努力完成一件事情真的太幸福了！！还有完成上层建筑的同事兼好朋友yzp学长！一起合作完成一件东西的感觉让我学会了合作，如果天气好，一起骑自行车下班聊天真的是一件特别惬意的事情！！跟你合作很愉快，哈哈！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;谢谢一路上帮助我的人，感谢我们家小乖乖，一直很支持我！明天你会看到更好的我！&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Tue, 17 Dec 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-12-17:pages/2013/12/17/yuan-chuang-sdnkong-zhi-qi-kai-fa-jiao-cheng-da-zao-shu-yu-ni-zi-ji-de-kong-zhi-qi.html</guid><category>SDN</category><category>OpenFlow</category></item><item><title>【原创】OpenFlow通信流程解读</title><link>http://www.muzixing.com/pages/2013/12/12/yuan-chuang-openflowtong-xin-liu-cheng-jie-du.html</link><description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;接触了这么久的SDN，OpenFlow协议前前后后也读过好多遍，但是一直没有时间总结一下自己的一些见解。现在有时间了，就写一写自己对OpenFlow协议通信流程的一些理解。&lt;/p&gt;
&lt;h2&gt;SDN中Switch和controller&lt;/h2&gt;
&lt;p&gt;在SDN中很重要的两个实体是Switch跟Controller。Controller在网络中相当于上帝，可以知道网络中所有的消息，可以给交换机下发指令。Switch就是一个实现Controller指令的实体，只不过这个交换机跟传统的交换机不一样，他的转发规则由流表指定，而流表由控制器发送。&lt;/p&gt;
&lt;h3&gt;switch组成与传统交换机的差异&lt;/h3&gt;
&lt;h4&gt;switch组成&lt;/h4&gt;
&lt;p&gt;switch由一个Secure Channel和一个flow table组成，of1.3之后table变成多级流表，有256级。而of1.0中table只在table0中。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Secure Channel是与控制器通信的模块，switch和controller之间的连接时通过socket连接实现。&lt;/li&gt;
&lt;li&gt;Flow table里面存放这数据的转发规则，是switch的交换转发模块。数据进入switch之后，在table中寻找对应的flow进行匹配，并执行相应的action，若无匹配的flow则产生packet_in（后面有讲）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;of中sw与传统交换机的差异&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;匹配层次高达4层，可以匹配到端口，而传统交换机只是2层的设备。&lt;/li&gt;
&lt;li&gt;运行of协议，实现许多路由器的功能，比如组播。&lt;/li&gt;
&lt;li&gt;求补充！！（如果你知道，请告诉我，非常感谢！）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;OpenFlow的switch可以从以下方式获得&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;实体of交换机，目前市场上有一些厂商已经制造出of交换机，但是普遍反映价格较贵！性能最好。&lt;/li&gt;
&lt;li&gt;在实体机上安装OVS，OVS可以使计算机变成一个OpenFlow交换机。性能相对稳定。&lt;/li&gt;
&lt;li&gt;使用mininet模拟环境。可以搭建许多交换机，任意拓扑，搭建拓扑具体教程本博客有一篇。性能依赖虚拟机的性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;controller组成&lt;/h3&gt;
&lt;p&gt;控制器有许多种，不同的语言，如python写的pox,ryu，如java写的floodlight等等。从功能层面controller分为以下几个模块：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;底层通信模块：OpenFlow中目前controller与switch之间使用的是socket连接，所以控制器底层的通信是socket。&lt;/li&gt;
&lt;li&gt;OpenFlow协议。socket收到的数据的处理规则需按照OpenFlow协议去处理。&lt;/li&gt;
&lt;li&gt;上层应用：根据OpenFlow协议处理后的数据，开发上层应用，比如pox中就l2_learning,l3_learning等应用。更多的应用需要用户自己去开发。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;OpenFlow通信流程&lt;/h2&gt;
&lt;p&gt;以下教程环境为：mininet+自编简单控制器+scapy封装&lt;/p&gt;
&lt;h3&gt;建立连接&lt;/h3&gt;
&lt;p&gt;首先启动mininet，mininet会自行启动一个default拓扑，你也可以自己建立你的拓扑。sw建立完成之后，会像controllerIP:controllerport发送数据。&lt;/p&gt;
&lt;p&gt;controller启动之后，监听指定端口，默认6633，但是好像以后的都改了，因为该端口被其他协议占用。&lt;/p&gt;
&lt;p&gt;3次握手之后，建立连接，这个是底层的通信，是整一套系统的基础设施。&lt;/p&gt;
&lt;h3&gt;OFPT_HELLO&lt;/h3&gt;
&lt;p&gt;创建socket之后，sw跟controller会彼此发送hello数据包。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;目的：协议协商。&lt;/li&gt;
&lt;li&gt;内容：本方支持的最高版本的协议&lt;/li&gt;
&lt;li&gt;成果：使用双方都支持的最低版本协议。&lt;/li&gt;
&lt;li&gt;成功：建立连接&lt;/li&gt;
&lt;li&gt;失败：OFPT_ERROR  (TYPE:OFPT_HELLO_FAILED,CODE =0),终止连接。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;OFPT_ERROR&lt;/h3&gt;
&lt;p&gt;说到OFPT_ERROR,我们不妨先了解一下。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ofp_error_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_HELLO_FAILED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_BAD_REQUEST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_BAD_ACTION&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_FLOW_MOD_FAILED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_PORT_MOD_FAILED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_QUEUE_OP_FAILED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;错误类型如上所示。对应的type还会有对应的code.所以报错的格式为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;OFPT_ERROR&lt;/span&gt;
&lt;span class="n"&gt;TYPE:&lt;/span&gt; 
&lt;span class="n"&gt;CODE:&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PAYLOAD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;具体的错误信息。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;如 TYPE:0 CODE:0为：&lt;strong&gt;OFPHFC_INCOMPATIBLE&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;具体对应的关系，请自行查看OF协议。&lt;/p&gt;
&lt;h3&gt;OFPT_ECHO&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;分类：对称信息 OFPT_ECHO_REQUEST, OFPT_ECHO_REPLY&lt;/li&gt;
&lt;li&gt;作用：查询连接状态，确保通信通畅。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当没有其他的数据包进行交换时，controller会定期循环给sw发送OFPT_ECHO_REQUEST。&lt;/p&gt;
&lt;h3&gt;OFPT_FEATURES&lt;/h3&gt;
&lt;p&gt;当sw跟controller完成连接之后，控制器会向交换机下发OFPT_FEATYRES_REQUEST的数据包，目的是请求交换机的信息。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;发送时间：连接建立完成之后&lt;/li&gt;
&lt;li&gt;发送数据：OFPT_FEATURES_REQUEST&lt;/li&gt;
&lt;li&gt;对称数据：OFPT_FEATURES_REPLY&lt;/li&gt;
&lt;li&gt;目的：获取交换机的信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;OFPT_FEATURES_REQUEST&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;TYPE=5&lt;/li&gt;
&lt;li&gt;Without data&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;OFPT_FEATURES_REPLY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;TYPE =6&lt;/li&gt;
&lt;li&gt;[0:8]为header&lt;/li&gt;
&lt;li&gt;[8:32]长度24byte为sw的features&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[32:]长度与端口数成正比，存放port的信息。每一个port信息长度为48byte。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ofp_features_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OpenFlow Switch Features Reply&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;fields_desc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;BitFieldLenField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;datapath_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length_of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;varfield&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitFieldLenField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;n_buffers&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length_of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;varfield&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;XByteField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;n_tables&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;X3BytesField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pad&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="c1"&gt;#features&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NOT DEFINED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_ARP_MATCH_IP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;7 Match IP address in ARP packets&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_QUEUE_STATS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;6 Queue statistics&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_IP_STREAM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;     &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;5 Can reassemble IP fragments&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_RESERVED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;      &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;4 Reserved, must be zero&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_STP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;           &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;3 802.1d spanning tree&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_PORT_STATS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;    &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;2 Port statistics&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_TABLE_STATS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;1 Table statistics&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPC_FLOW_STATS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;    &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;0 Flow statistics&lt;/span&gt;
                  &lt;span class="n"&gt;BitFieldLenField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;actions&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length_of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;varfield&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;bind_layers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp_features_reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上的结构是交换机的features,紧跟在后面的是端口的结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ofp_phy_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OpenFlow Port&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;fields_desc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;ShortEnumField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;port_no&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp_port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;MACField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hw_addr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;00:00:00:00:00:00&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;StrFixedLenField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;port_name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not_defined&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_PACKET_IN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_FWD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_FLOOD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_RECV_STP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_RECV&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_NO_STP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPC_PORT_DOWN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for state&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;else&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPS_LINK_DOWN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for Current features&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not_defined&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_PAUSE_ASYM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_PAUSE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_AUTONEG&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_FIBER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_COPPER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_10GB_FD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_1GB_FD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_1GB_HD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_100MB_FD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_100MB_HD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_10MB_FD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OFPPF_10MB_HD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for features being advised by the port&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;advertised&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for features supported by the port&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;supported&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                  &lt;span class="c1"&gt;#uint32_t for features advertised by peer&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;peer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;交换机和端口的配置信息在整一个通信过程起着至关的作用，因为所有关于的操作都需要从features里面提取相关的信息，如&lt;strong&gt;dpid,port_no&lt;/strong&gt;，等在整个通信过程中多次被用到的重要数据。所以，对这两个数据结构了然于心，对于研究OpenFlow来说，至关重要。每一次交换机连到控制器，都会收到控制器的features_request,当sw将自己的features回复给控制器之后，控制器就对交换机有了一个全面的了解，从而为后面的控制提供的控制信息。&lt;/p&gt;
&lt;h3&gt;OFPT_PACKET_IN&lt;/h3&gt;
&lt;p&gt;在控制器获取完交换机的特性之后，交换机开始处理数据。&lt;/p&gt;
&lt;p&gt;对于进入交换机而没有匹配流表，不知道如何操作的数据包，交换机会将其封装在packet_in中发给controller。包含在packet_in中的数据可能是很多种类型，arp和icmp是最常见的类型。&lt;/p&gt;
&lt;p&gt;当然产生packet_in的原因不止一种，产生packet_in的原因主要有一下两种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OFPR_NO_MATCH&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OFPR_ACTION&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;无法匹配的数据包会产生packet_in,action也可以指定将数据包发给packet_in,也就是说我们可以利用这一点，将需要的数据包发给控制器。&lt;/p&gt;
&lt;p&gt;packet_in事件之后，一般会触发两类事件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;packet_out&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;flow_mod&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果是广播包，如arp，控制器一般会将其包装起来，封装成packet_out数据包，将其发给交换机，让其flood,flood操作是将数据包往除去in_port以外的所有端口发送数据包。&lt;/p&gt;
&lt;h3&gt;OFPT_PACKET_OUT&lt;/h3&gt;
&lt;p&gt;很多人不是特别了解packet_out的作用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;作用：通过控制器发送交换机希望发送的数据&lt;/li&gt;
&lt;li&gt;例子：当一个没有匹配上流表项的数据上报控制器时，控制器可以下发packet_out，指定交换机对该数据包做泛洪或丢弃动作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当packet_out中的buffer_id=-1时，指明该数据并不在交换机的buffer中，而在packet_out的data。当buffer_id不为-1时，指明要操作的数据包是交换机中该buffer_id的数据。&lt;/p&gt;
&lt;h3&gt;OFPT_FLOW_MOD&lt;/h3&gt;
&lt;p&gt;OFPT_FLOW_MOD是整一个OpenFlow协议中最重要的数据结构。&lt;/p&gt;
&lt;p&gt;OFPT_FLOW_MOD由&lt;strong&gt;header+match+flow_mod+action[]&lt;/strong&gt;组成。为了操作简单，以下的结构是将wildcards和match分开的形式，形成两个结构，在编程的时候能更方便一些。由于这个数据包很重要，所以，我将把这个数据包仔细拆分解读。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;flow_mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_wildcards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFPFW_NW_TOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_DL_VLAN_PCP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_NW_DST_MASK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_NW_SRC_MASK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_TP_DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_TP_SRC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_NW_PROTO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_DL_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_DL_VLAN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_IN_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_DL_DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;OFPFW_DL_SRC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
           &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;dl_src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;dl_dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;dl_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;dl_vlan&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vlan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;nw_tos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;nw_proto&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;nw_src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;nw_dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pkt_parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;tp_src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;tp_dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
           &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;idle_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;hard_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;buffer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;&lt;strong&gt;OFP_HEADER&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;header是所有数据包的报头，有三个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;type:类型&lt;/li&gt;
&lt;li&gt;length:整个数据包的长度&lt;/li&gt;
&lt;li&gt;xid：数据包的编号&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如ofp_flow_mod的type就是14，具体的哪一种数据的类型将在文章最后给出。length最基本长度为72，每一个action长度为8。所以长度必定为8的倍数才是一个正确的数据长度。&lt;/p&gt;
&lt;h4&gt;WILDCARDS&lt;/h4&gt;
&lt;p&gt;这是从match域提取出来的前32bit。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在of1.0中这里的0，1意义跟我们平时接触的如子网掩码等意义相反&lt;/strong&gt;，如OFPFW_NW_DST_MASK=0则表示全匹配目标IP。如果为63，则表示不匹配IP。为什么拿这个举例？原因就在于，他的长度是6bit，最大是63，需要将数值转变成对应2进制数值才是我们想要的匹配规则，且注意，1是忽略，0是匹配。如果wildcards全0，则表示由match精确指定，即所有12元组都匹配。&lt;/p&gt;
&lt;p&gt;当然高兴的是，在1.3的时候，这个逻辑改成了正常的与逻辑。即1为使能匹配，0为默认不匹配。&lt;/p&gt;
&lt;h4&gt;MATCH&lt;/h4&gt;
&lt;p&gt;这个数据结构会出现在机会所有重要的数据包中，因为他存的就是控制信息。&lt;/p&gt;
&lt;p&gt;如有packet_in引发的下发流表，则match部分应对应填上对应的数据，这样下发的流表才是正确的。&lt;/p&gt;
&lt;p&gt;但是在下发的时候还需要注意许多细节，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;并不是所有的数据包都有vlan_tag&lt;/strong&gt;。如0x0800就是纯IP，并没有携带vlan_tag，所以填充式应根据packet_in的具体情况填充。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并不是所有的数据都有四层端口&lt;/strong&gt;，所以四层的源端口，目的端口都不是任何时候都能由packet_in去填充的。不去管就好了，默认的会填充一个默认值，匹配的时候不去匹配4层端口就没有问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;FLOW_MOD&lt;/h4&gt;
&lt;p&gt;这里面的信息也是至关重要的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ofp_flow_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OpenFlow Flow Modify&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;fields_desc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cookie&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;#Opaque controller-issued identifier&lt;/span&gt;
                  &lt;span class="n"&gt;ShortEnumField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;command&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp_flow_mod_command&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ShortField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;idle_timeout&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ShortField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hard_timeout&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ShortField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;priority&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;IntField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;buffer_id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ShortField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;out_port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="c1"&gt;#flags are important, the 1&amp;lt;&amp;lt;0 bit is OFPFF_SEND_FLOW_REM, send OFPT_FLOW_REMOVED&lt;/span&gt;
                  &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;1 bit is OFPFF_CHECK_OVERLAP, checking if the entries&amp;#39; field overlaps(among same priority)  &lt;/span&gt;
                  &lt;span class="c1"&gt;#1&amp;lt;&amp;lt;2 bit is OFPFF_EMERG, used only switch disconnected with controller) &lt;/span&gt;
                  &lt;span class="n"&gt;ShortField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;flags&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;command里面的类型决定了flow_mod的操作是添加，修改还是删除等。类型如下&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ofp_flow_mod_command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFC_ADD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;            &lt;span class="c1"&gt;# New flow&lt;/span&gt;
                         &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFC_MODIFY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;# Modify all matching flows&lt;/span&gt;
                         &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFC_MODIFY_STRICT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Modify entry strictly matching wildcards&lt;/span&gt;
                         &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFC_DELETE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;# Delete all matching flows&lt;/span&gt;
                         &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFC_DELETE_STRICT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;# Strictly match wildcards and priority&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;例如：如果要添加一条新流，command=0。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;两个时间参数idle_timeout &amp;amp; idle_timeout：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;idle_timeout:如值为10，则某条流在10秒之内没有被匹配，则删除，可以称之为活跃时间吧。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hard_timeout:如值为30，则30秒到达的时候，一定删除这条流，即使他还活跃，即被匹配。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;priority&lt;/h4&gt;
&lt;p&gt;priority是流的优先级的字段，&lt;strong&gt;字数越大则优先级越高，存放在号数越小的table中&lt;/strong&gt;。&lt;/p&gt;
&lt;h4&gt;buffer_id&lt;/h4&gt;
&lt;p&gt;由交换机指定的buffei_id,准确的说是由dpid指定的。如果是手动下发的流，&lt;strong&gt;buffer_id应填-1&lt;/strong&gt;，即0xffff,告诉交换机这个数据包并没有缓存在队列中。&lt;/p&gt;
&lt;h4&gt;out_port&lt;/h4&gt;
&lt;p&gt;指定流的出口，但是这个出口并不是直接指导流转发的，至少我是这么觉得，指导流转发的出口会在action里面添加，这个端口是为了在flow_removed的时候查询，并返回控制器的作用。（求纠正！）&lt;/p&gt;
&lt;p&gt;有一些端口是很特殊的，如flood，local等。具体分类如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ofp_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mh"&gt;0xff00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPP_MAX&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="mh"&gt;0xfff8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPP_IN_PORT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="mh"&gt;0xfff9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPP_TABLE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="mh"&gt;0xfffa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPP_NORMAL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="mh"&gt;0xfffb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPP_FLOOD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="mh"&gt;0xfffc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPP_ALL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="mh"&gt;0xfffd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPP_CONTROLLER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="mh"&gt;0xfffe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPP_LOCAL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="mh"&gt;0xffff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPP_NONE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;如果你不知道端口是多少，最好填flood,也就是0xfffb。&lt;/p&gt;
&lt;h4&gt;flags&lt;/h4&gt;
&lt;p&gt;在上面的注释中也说得比较清楚了。如果没有特殊用处，&lt;strong&gt;请将他置1&lt;/strong&gt;，因为这样能让交换机在删除一条流的时候给交换机上报flow_removed信息。&lt;/p&gt;
&lt;h3&gt;ACTION&lt;/h3&gt;
&lt;p&gt;action是OpenFlow里面最重要的结构。对，他也是最重要的。每一条流都必须指定必要的action,不然匹配上之后，&lt;strong&gt;没有指定action，交换机会默认执行drop操作。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;action有2种类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;必备行动: Forward  and Drop&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择行动:FLOOD,NALMAL 等&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如添加output就是一个必须要添加的action.每一个action最好有一个action_header(),然后再接一个实体。如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ofp_action_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ofp_action_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;oxfffb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;具体的action类型如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ofp_action_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_OUTPUT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_SET_VLAN_VID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_SET_VLAN_PCP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_STRIP_VLAN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_SET_DL_SRC&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_SET_DL_DST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_SET_NW_SRC&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_SET_NW_DST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_SET_NW_TOS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_SET_TP_SRC&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_SET_TP_DST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPAT_ENQUEUE&amp;quot;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;action不仅仅会出现在flow_mod中，也会出现在如stats_reply中。&lt;/p&gt;
&lt;h3&gt;OFPT_BARRIER_REQUEST  &amp;amp;&amp;amp; REPLY&lt;/h3&gt;
&lt;p&gt;这个数据包可以的作用很简单，交换机在收到OFPT_BARRIER_REQUEST的时候，会回复控制器一个OFPT_BARRIER_REPLY。我们默认数据下发的顺序不会在传输中发生变化，在进入消息队列之后处理也是按照FIFO进行的，那么只要在flow_mod之后发送这个数据，当收到reply之后，交换机默认flow已经写成功。也许你会问他只是保证了flow_mod命令执行了，写入的结果如何并没有保证，如何确定确实写入流表了呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果非逻辑错误，那么交换机在处理flow_mod的时候会报错。所以我们会知道写入结果。&lt;/li&gt;
&lt;li&gt;如果是逻辑错误，那么会写进去，但是逻辑错误应该是人的问题，所以barrier还是有他的功能的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;OFPT_FLOW_REMOVED&lt;/h3&gt;
&lt;p&gt;如果flow_mod的flags填成1，则该流在失效之后会回复控制器一条OFPT_FLOW_REMOVED信息。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;结构：header()/wildcards()/match()/flow_removed()&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;作用：在流失效的时候回复控制器，并携带若干统计数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ofp_flow_removed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OpenFlow flow removed&amp;quot;&lt;/span&gt;
  &lt;span class="n"&gt;fields_desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cookie&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;priority&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ByteField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pad&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;duration_sec&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;duration_nsec&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;idle_timeout&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ByteField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pad&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ByteField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pad&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;packet_count&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;BitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;byte_count&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其实的duration_sec是流存在的时间，单位为秒，duration_nsec单位为纳秒。&lt;/p&gt;
&lt;h3&gt;OFPT_STATS_REQUEST &amp;amp;&amp;amp; REPLY&lt;/h3&gt;
&lt;p&gt;以上的数据都是通信过程中必须的部分。还有一些数据包是为了某些目的而设计的，如OFPT_STATS_REQUEST &amp;amp;&amp;amp; REPLY可以获得统计信息，我们可以利用统计信息做的事情就太多了。如：&lt;strong&gt;负载平衡&lt;/strong&gt;， 流量监控等基于流量的操作。&lt;/p&gt;
&lt;h4&gt;OFPT_STATS_REQUEST&lt;/h4&gt;
&lt;p&gt;OFPT_STATS_REQUEST类型有很多，回复的类型也很多。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ofp_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OpenFlow Stats Request&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;fields_desc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;ShortEnumField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofp_stats_types&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;ShortField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;flag&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Type&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;0:请求交换机版本信息，制造商家等信息。&lt;/li&gt;
&lt;li&gt;1:单流请求信息&lt;/li&gt;
&lt;li&gt;2:多流请求信息&lt;/li&gt;
&lt;li&gt;3:流表请求信息&lt;/li&gt;
&lt;li&gt;4:端口信息请求&lt;/li&gt;
&lt;li&gt;5:队列请求信息&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;6:vendor请求信息，有时候没有定义。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;   &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;                            &lt;span class="c1"&gt;#Type of  OFPST_DESC (0) &lt;/span&gt;
            &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_stats_request(type =1)/o&lt;/span&gt;&lt;span class="n"&gt;fp_flow_wildcards&lt;/span&gt;&lt;span class="sr"&gt;/ofp_match/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_flow_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ofp_flow_mod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;                  &lt;span class="c1"&gt;#flow stats&lt;/span&gt;
            &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_stats_request(type = 2)/o&lt;/span&gt;&lt;span class="n"&gt;fp_flow_wildcards&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_match/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_aggregate_stats_request&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;                                  &lt;span class="c1"&gt;# aggregate stats request&lt;/span&gt;
            &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;                            &lt;span class="c1"&gt;#Type of  OFPST_TABLE (0) &lt;/span&gt;
            &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_stats_request(type = 4)/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_port_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_no&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c1"&gt;# port stats request    &lt;/span&gt;
            &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/of.ofp_stats_request(type =5)/o&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_queue_stats_request&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;#queue request&lt;/span&gt;
            &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofp_stats_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xffff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                        &lt;span class="c1"&gt;#vendor request&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;OFPT_STATS_REPLY&lt;/h4&gt;
&lt;p&gt;每一种请求信息都会对应一种回复信息。我们只介绍最重要的&lt;strong&gt;flow_stats_reply&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;结构：&lt;strong&gt;header(type=17)/reply_header()/flow_stats/wildcards/match/
flow_stats_data&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;作用：携带流的统计信息，如通过的数据包个数，字节数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ofp_flow_stats(body[4:8])&lt;/strong&gt;里面会有的&lt;strong&gt;table_id&lt;/strong&gt;字段表明该流存放在哪一个流表里。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;flow_stats_data里面有packet_count和byte_count是最有价值的字段，流量统计就是由这两个字段提供的信息。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如想统计某条流的速率：&lt;strong&gt;前后两个reply的字节数相减除以duration_time只差就可以求得速率&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由速率我们可以做很多基于流量的app，如&lt;strong&gt;流量监控，负载均衡&lt;/strong&gt;等等。&lt;/p&gt;
&lt;p&gt;值得注意的是，在这些数据之后，其实还有一些&lt;strong&gt;action&lt;/strong&gt;,但是目前我还没有查看这些action到底是干什么用的。&lt;/p&gt;
&lt;h2&gt;后续&lt;/h2&gt;
&lt;p&gt;写到这里，我使用到的数据包都写了一遍，其他的报文其实道理也是一样的。如&lt;strong&gt;OFPT_GET_CONFIG_REQUEST和REPLY&lt;/strong&gt;，道理应该和stats一样，只是数据结构不一样罢了。不再多说。&lt;/p&gt;
&lt;p&gt;最后把我们用的一些比较多的信息帖出来让大家更好的学习。&lt;/p&gt;
&lt;h3&gt;ERROR&lt;/h3&gt;
&lt;p&gt;在调试的过程中遇到错误是再所难免的，前面也提到了error的结构。这里就贴一下type跟code吧。&lt;/p&gt;
&lt;h4&gt;Type&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ofp_error_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_HELLO_FAILED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_BAD_REQUEST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_BAD_ACTION&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_FLOW_MOD_FAILED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_PORT_MOD_FAILED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPET_QUEUE_OP_FAILED&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;相关的code：&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ofp_hello_failed_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPHFC_INCOMPATIBLE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPHFC_EPERM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ofp_bad_request_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBRC_BAD_VERSION&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBRC_BAD_TYPE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBRC_BAD_STAT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBRC_BAD_VENDOR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBRC_BAD_SUBTYPE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBRC_EPERM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBRC_BAD_LEN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBRC_BUFFER_EMPTY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBRC_BUFFER_UNKNOWN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ofp_bad_action_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBAC_BAD_TYPE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBAC_BAD_LEN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBAC_BAD_VENDOR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBAC_BAD_VENDOR_TYPE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBAC_BAD_OUT_PORT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBAC_BAD_ARGUMENT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBAC_EPERM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;#permissions error&lt;/span&gt;
                        &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBAC_TOOMANY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPBAC_BAD_QUEUE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ofp_flow_mod_failed_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFMFC_ALL_TABLES_FULL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFMFC_OVERLAP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFMFC_EPERM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFMFC_BAD_EMERG_TIMEOUT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFMFC_BAD_COMMAND&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPFMFC_UNSUPPORT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ofp_port_mod_failed_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPPMFC_BAD_PORT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPPFMC_BAD_HW_ADDR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ofp_queue_op_failed_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPQOFC_BAD_PORT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;OFPQOFC_BAD_QUEUE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;谢谢我的两个师傅richardzhao,kimi带我走进OpenFlow的世界。&lt;/p&gt;
&lt;h4&gt;整篇文档均为牧紫星原创，转载请声明告知。希望能给你带来一些帮助。&lt;/h4&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 12 Dec 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-12-12:pages/2013/12/12/yuan-chuang-openflowtong-xin-liu-cheng-jie-du.html</guid><category>SDN</category><category>OpenFlow</category></item><item><title>【原创】SDN下的分布式广播风暴解决方案</title><link>http://www.muzixing.com/pages/2013/12/07/yuan-chuang-sdnxia-de-fen-bu-shi-yan-bo-feng-bao-jie-jue-fang-an.html</link><description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;这是很久以前的成果了，那时候我才大三上。为了学习sdn,openflow等知识，北邮科研楼628的一群哥们儿，想着各种新奇的东西去解决已有的问题。&lt;/p&gt;
&lt;p&gt;有一天，我们遇到了网络风暴，但是我们觉得STP有点复杂，而且，确实也不愿意去学。那么，就自己写一个解决方案吧。于是，下面的小代码产生了。&lt;/p&gt;
&lt;h3&gt;核心思想&lt;/h3&gt;
&lt;p&gt;其实特别简单，一句话：&lt;strong&gt;不让同一个数据包从第二个端口进入，即仅允许数据包从第一个进来的端口进入。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;也就是说，我确保了，同一个数据包，不会从别的交换机从非第一次的in_port进入本交换机，那就不会有环路，也就解决了风暴，而且，同一个端口允许进入，不影响主机继续发送广播包。&lt;/p&gt;
&lt;h3&gt;具体实现&lt;/h3&gt;
&lt;p&gt;这个就需要我们建立一个macToport的表，在python里面数据结构字典来实现。使用src_mac作为key，记录值为[dstip,port,time]&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;macToPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;srcMAC:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dst_ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;in_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个字典记录了用数据包的mac地址记录了数据包的目标ip,入口端口，到达时间三个信息，其实如果为了更好的对应，我们应该使用上xid,让&lt;strong&gt;（src_mac,xid）&lt;/strong&gt;去唯一确定一个数据包。&lt;/p&gt;
&lt;p&gt;相应的处理逻辑如下，我们可以把他写成一个函数去调用，调用位置应处于packet_in的处理逻辑里面。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;anti_brocast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isMulticast&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;如果是广播性质，则处理&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opcode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REQUEST&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;假设所有的通信之前都有&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="err"&gt;，即广播风暴只能由&lt;/span&gt;&lt;span class="n"&gt;ARP&lt;/span&gt;&lt;span class="err"&gt;引起，已经&lt;/span&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="err"&gt;之后是不会出现&lt;/span&gt;&lt;span class="n"&gt;storm&lt;/span&gt;&lt;span class="err"&gt;的。&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hwsrc&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packetToPort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;protodst&lt;/span&gt;   &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packetToPort&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;如果&lt;/span&gt;&lt;span class="n"&gt;src_mac&lt;/span&gt;&lt;span class="err"&gt;在表内，且&lt;/span&gt;&lt;span class="n"&gt;dst_ip&lt;/span&gt;&lt;span class="err"&gt;相同&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;我们默认这是会产生风暴的同一个流的广播包。&lt;/span&gt;
        &lt;span class="c1"&gt;#如果如端口不是原先的记录中端口，即第一次端口，则丢弃，否则flood.&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inport&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packetToPort&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
            &lt;span class="n"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="c1"&gt;#if not the specially inport,then drop it.&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
          &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;flood&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Another Arp_Request from %s -- flooding,we set limit_time to drop it&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Another muticast packet form %s at %i port in %i &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;inport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;#如果没有在字典中，那么记住它！&lt;/span&gt;
          &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packetToPort&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;protodst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;inport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TimeToArrive&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="c1"&gt;#record and lock the port&lt;/span&gt;
          &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;macToPort&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;inport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TimeToArrive&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="c1"&gt;#update the L2 table.&lt;/span&gt;
          &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;update the table entry of %s at %i in %i ,&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;packet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;inport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="n"&gt;flood&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这是一个极其简单的逻辑，但是可以解决ARP的风暴，也就是说解决了很大程度上的广播风暴。相比于STP，这个小逻辑是不是更清爽呢？&lt;/p&gt;
&lt;h3&gt;后续&lt;/h3&gt;
&lt;p&gt;SDN也许还没有明确的定义，明确的方向，但是不可否认的是，SDN的诞生，openflow的诞生，给解决某些问题提供了新的方案，我想这也是一种创新吧。希望读完这篇博文能给你一些小启发。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Sat, 07 Dec 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-12-07:pages/2013/12/07/yuan-chuang-sdnxia-de-fen-bu-shi-yan-bo-feng-bao-jie-jue-fang-an.html</guid><category>SDN</category><category>Openflow</category></item><item><title>【原创】mininet搭建自定义网络拓扑 by muzi</title><link>http://www.muzixing.com/pages/2013/12/06/yuan-chuang-mininetda-jian-zi-ding-yi-wang-luo-tuo-bu-by-muzi.html</link><description>&lt;h3&gt;你知道的mininet&lt;/h3&gt;
&lt;p&gt;相信很多研究SDN的朋友都知道mininet，也是用过mininet。但是恐怕大多数人都只是局限于workthough的水平.链接：http://mininet.org/walkthrough/&lt;/p&gt;
&lt;p&gt;搭建更多的，灵活的拓扑还是有一定的难度。&lt;/p&gt;
&lt;p&gt;上一次实验的时候，看了一下spirent testceter的一套测试拓扑，从中受益，学了一点。现在写出来分享一下。&lt;/p&gt;
&lt;p&gt;如果你想快速建立拓扑，请直接拉到最后一个标题&lt;/p&gt;
&lt;h3&gt;教你搭建你自己的任意拓扑&lt;/h3&gt;
&lt;p&gt;首先把需要用到的相关模块import进来。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;/#!/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="sr"&gt;/bin/&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;

&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cli&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CLI&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;setLogLevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mininet&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;link&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Intf&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;topolib&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TreeTopo&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;quietRun&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RemoteController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OVSKernelSwitch&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;re模块提供python正则表达式的支持，我们会看到我们定义的checkIntf()函数会使用到正则表达式。&lt;/p&gt;
&lt;p&gt;接着要从mininet中import进来很多文件，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CLI是命令行服务的文件。&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;log是一些记录&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;net里面包含了最重要的类，Mininet类，这是定义一个网络的类&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Mininet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;Network emulation with hosts spawned in network    namespaces.&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OVSKernelSwitch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Intf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xterms&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cleanup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ipBase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;10.0.0.0/8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;inNamespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;autoSetMacs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;autoStaticArp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;autoPinCpus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;listenPort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上的参数是基本的参数，也是最重要的参数。除了这些数据成员，Mininet类还有一些重要函数如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;addHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;addController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;c0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hosts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;以上的函数已经足够你构建一个足够复杂的，足够灵活的网络了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;link里面的Intf是一个接口函数&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Intf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="s"&gt;&amp;quot;Basic interface object that can configure itself.&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这个类可以用于定义一个网络接口，如：定义虚拟机某个网卡与mininet中某交换机的某网卡相连，这样我们就可以使用一些打流工具，如&lt;strong&gt;spirent的testcenter&lt;/strong&gt;给虚拟机的网卡打流，从而引导到mininet构建的网络中，达到打流的目的。&lt;/p&gt;
&lt;p&gt;默认情况下，port可以不填，mininet会自动分配。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TreeTopo是支持快速生成一个网络树的函数&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;TreeTopo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;Topo&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;Topology for a tree network with a given depth and fanout.&amp;quot;&lt;/span&gt;    
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fanout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;depth 定义的是树的深度，fanout是每一层的分支数。
mininet中便捷使用是， --tree(n,m),可以生成n层的m叉树。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;node里面的RemoteConTroller类定义远程连接的控制器&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;RemoteController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;Controller running outside of Mininet&amp;#39;s control.&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6633&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;默认的控制器是本地控制器。ip =127.0.0.1。注意，你可以自己定义你的控制器的名字，这一点是很有趣的，比如我的控制器就叫做：muziController，搞技术的时候，也要考虑技术的感受，不要老搞，要轻松一下嘛。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;node里面的OVSKernelSwitch定义OVS交换机的类，至关重要。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;OVSLegacyKernelSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;Switch&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;实际上它直接集继承了Switch类，Switch类是一个更加简单的基类，提供了交换机所需要的相关功能。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;OVSSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;Switch&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;OVSSwitch（)也继承Switch基类。而superclass:Switch继承的是Node，可以在他的init函数中看出他可以使用哪些参数。你可以设置dpid，很重要的一个属性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;A Switch is a Node that is running (or has execed?)&lt;/span&gt;
&lt;span class="s"&gt;    an OpenFlow switch.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;portBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;# Switches start with port 1 in OpenFlow&lt;/span&gt;
    &lt;span class="n"&gt;dpidLen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;  &lt;span class="c1"&gt;# digits in dpid passed to switch&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listenPort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;了解完这些重要的代码，我们就是可以开始构建我们的拓扑了。&lt;/p&gt;
&lt;h3&gt;创建接口检查函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;checkIntf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;#make sure intface exists and is not configured.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39; %s:&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;quietRun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ip link show&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Error:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;does not exist!\n&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;\d+\.\d+\.\d+\.\d+&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quietRun&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;ifconfig &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ips:&lt;/span&gt;
        &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;has an IP address,&amp;#39;&lt;/span&gt;
            &lt;span class="s"&gt;&amp;#39;and is probably in use!\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在创建拓扑前，我们必须要做的第一件事情就是了解那些接口是存在的，且没有被定义初始化，也就是，没有被使用的，这些资源是可调用资源。具体代码如上。&lt;/p&gt;
&lt;h3&gt;创建拓扑&lt;/h3&gt;
&lt;p&gt;为了不打破思维的连续性，以下内容由注释先生解说。谢谢收看本期内容，再见。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;setLogLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;info&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;OVSKernelSwitch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;开启一个网络&lt;/span&gt;
    &lt;span class="n"&gt;intfName_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;eth2&amp;quot;&lt;/span&gt;     &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;将虚拟机&lt;/span&gt;&lt;span class="n"&gt;eth2&lt;/span&gt;&lt;span class="err"&gt;赋值给为变量&lt;/span&gt;&lt;span class="n"&gt;intfName_1&lt;/span&gt;
    &lt;span class="n"&gt;intfName_3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;eth3&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;****checking****&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intfName_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;checkIntf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intfName_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;检查是否可用&lt;/span&gt;
    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;****checking****&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intfName_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;checkIntf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intfName_3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;****creating network****\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Mininet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listenPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6633&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;创建一个&lt;/span&gt;&lt;span class="n"&gt;Mininet&lt;/span&gt;&lt;span class="err"&gt;的实例，端口为&lt;/span&gt;&lt;span class="mi"&gt;6633&lt;/span&gt;

    &lt;span class="n"&gt;mycontroller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RemoteController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;muziController&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;192.168.0.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;创建远程控制器，&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;192.168.0.1&lt;/span&gt;&lt;span class="err"&gt;，端口是&lt;/span&gt;&lt;span class="mi"&gt;6633&lt;/span&gt;&lt;span class="err"&gt;。&lt;/span&gt;

    &lt;span class="n"&gt;switch_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;s1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;在&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="err"&gt;里添加交换机&lt;/span&gt;&lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="err"&gt;中规则为：如果不填充&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="err"&gt;参数，则&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="err"&gt;参数默认取&lt;/span&gt;&lt;span class="n"&gt;sn&lt;/span&gt;&lt;span class="err"&gt;的&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;即&lt;/span&gt;&lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="err"&gt;的&lt;/span&gt;&lt;span class="n"&gt;dpid&lt;/span&gt;&lt;span class="err"&gt;为&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;。&lt;/span&gt; 
    &lt;span class="n"&gt;switch_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;s2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;switch_3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;s3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;switch_4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;s4&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controllers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mycontroller&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;将远程控制器添加到网络中&lt;/span&gt;


    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;# node1,   node2, port1, port2&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;将&lt;/span&gt;&lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="err"&gt;的&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;端口跟&lt;/span&gt;&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="err"&gt;的&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;端口连接起来。（物理连接）&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch_4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;需要注意的是，以上连接的链路是一个环形的链路，在没有解决风暴的情况下，会出问题。&lt;/span&gt;  
    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;*****Adding hardware interface &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="n"&gt;intfName_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;to switch:&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;switch_1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;*****Adding hardware interface &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="n"&gt;intfName_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;to switch:&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;switch_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_intf_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Intf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intfName_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;switch_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;将&lt;/span&gt;&lt;span class="n"&gt;intfName_1&lt;/span&gt;&lt;span class="err"&gt;和&lt;/span&gt;&lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="err"&gt;的端口&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;相连，形成一个接口&lt;/span&gt;&lt;span class="n"&gt;_intf_1&lt;/span&gt;
    &lt;span class="n"&gt;_intf_3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Intf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intfName_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;switch_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switch_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;为什么放在这里呢？因为&lt;/span&gt;&lt;span class="n"&gt;mininet&lt;/span&gt;&lt;span class="err"&gt;中允许的端口分配方式是从小到大分配，所以，&lt;/span&gt;&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="err"&gt;的&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;端口的配置应该放在&lt;/span&gt;&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="err"&gt;的&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;端口之后，虽然难看，但是必须这么做，当然你也可以从新分配端口，只要保证端口是从小到大分配就好了。&lt;/span&gt;

    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Node: you may need to reconfigure the     interfaces for the Mininet hosts:\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;启动&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;
    &lt;span class="n"&gt;CLI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;等待键入命令&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;关闭&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 06 Dec 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-12-06:pages/2013/12/06/yuan-chuang-mininetda-jian-zi-ding-yi-wang-luo-tuo-bu-by-muzi.html</guid><category>mininet</category></item><item><title>基于tornado的简单socket通信建立</title><link>http://www.muzixing.com/pages/2013/11/29/ji-yu-tornadode-jian-dan-sockettong-xin-jian-li.html</link><description>&lt;p&gt;配图版请查看：http://user.qzone.qq.com/350959853/blog/1375093527&lt;/p&gt;
&lt;h3&gt;安装tornado&lt;/h3&gt;
&lt;p&gt;这里有比较全的介绍，写得非常好。http://sebug.net/paper/books/tornado/&lt;/p&gt;
&lt;h3&gt;hello world&lt;/h3&gt;
&lt;p&gt;首先，下载安装好tornado之后，我们就可以去使用tornado里面的库了。
照着官网的简单的例子抄了一遍，写了一个hello world!&lt;/p&gt;
&lt;p&gt;&lt;img alt="hello" src="http://e.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=1382f91cba99a9013f355b332dae7b46/e824b899a9014c0862b40dad087b02087bf4f42e.jpg?referer=77791a7ef01fbe094549f72434e4&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;显示效果如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="res" src="http://e.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=0683c331b1de9c82a265f98a5cbaf137/d009b3de9c82d15858647eb9820a19d8bd3e42d7.jpg?referer=68d8807dd488d43fa9bea5c2aecd&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;h3&gt;基于tornado的简单的socket连接通信实现&lt;/h3&gt;
&lt;p&gt;代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;errno&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tornado&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ioloop&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;IOLoop&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;

&lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;#sock.setsockopt    (socket.SOL_SOCKET,socket.SO_REUSEADDR,1)&lt;/span&gt;
&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setblocking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;server_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12346&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;fd_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;message_queue_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;fd_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;

&lt;span class="n"&gt;ioloop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cli_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fd_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ:&lt;/span&gt; &lt;span class="c1"&gt;#receive the data&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;receive %s from %s&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;cli_addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
            &lt;span class="n"&gt;ioloop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;closing %s  &amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%cli_addr&lt;/span&gt;
            &lt;span class="n"&gt;ioloop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;del&lt;/span&gt; &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WRITE:&lt;/span&gt;
        &lt;span class="n"&gt;try:&lt;/span&gt;
            &lt;span class="n"&gt;next_msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_nowait&lt;/span&gt;   &lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s Queue Empty&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;cli_addr&lt;/span&gt;
            &lt;span class="n"&gt;ioloop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;#CHANGE THE SITUATION&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;sending %s to %s &amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;next_msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="n"&gt;cli_addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ioloop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ERROR:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s EXCEPTION ON&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;%cli_addr&lt;/span&gt;
        &lt;span class="n"&gt;ioloop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;del&lt;/span&gt; &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fd_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ:&lt;/span&gt;
        &lt;span class="n"&gt;get_connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;cli_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;connection %s &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;%cli_addr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;get_connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setblocking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;get_connection_fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;fd_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_connection_fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_connection&lt;/span&gt;
        &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;cli_addr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;ioloop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handler&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_connection_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;message_queue_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_connection&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IOLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;handle_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;try:&lt;/span&gt;
    &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;KeyboardInterrupt:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;exit&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;io_loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;首先，我们的目的是利用tornado的库函数，去实现简单的也是很重要的socket通信。&lt;/p&gt;
&lt;h4&gt;第一步：&lt;/h4&gt;
&lt;p&gt;我们需要建立一个半连接的socket，也就是，本机开了一个socket，等待对方来匹配，连接通信。这一点是非常必要的！&lt;/p&gt;
&lt;h4&gt;第二步：&lt;/h4&gt;
&lt;p&gt;我们需要定义两个函数，一个是作为tcpserver的函数，另一个是作为client的函数。相对来说，server的要简单一些，因为只需要接受即可。在图中为handle_serve（）函数。比较困难的是handle_client（）函数，因为需要考虑的问题比较多！第一个需要考虑的是收到的数据是否为空的问题，非空之后，需要将其打印出来，并将源数据发送回去。当然，具体的操作可以由编程者决定，原样返还是比较简单的操作。同时，我们还需要关注的是，这些处理的过程中，需要关注的socket的读写状态！当数据包到来时，我们应该为可读状态，讲数据读出之后，要记得把socket的状态改为可写，等待数据的写入。&lt;/p&gt;
&lt;h4&gt;第三步：&lt;/h4&gt;
&lt;p&gt;资源的释放。当程序执行完毕时，我们需要对系统调用的程序进行释放。&lt;strong&gt;32&lt;/strong&gt;行的else就是其中一个操作。最后的ioloop.stop()也是必须的！&lt;/p&gt;
&lt;p&gt;实验结果如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="result" src="http://a.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=2fcd8e17050828386c0ddc1188a2d83c/9f2f070828381f30e196a8a1ab014c086e06f02e.jpg?referer=909062360ef3d7ca55e10b4630e4&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;基于这个简单的通信，我们可以去创建更大规模的通信，实现更为复杂的传输。如SDN中controller与交换机之间的通信。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 29 Nov 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-11-29:pages/2013/11/29/ji-yu-tornadode-jian-dan-sockettong-xin-jian-li.html</guid><category>tornado</category></item><item><title>N个整数，求其中任意N-1个数的乘积中的最大的一个(禁用除法)</title><link>http://www.muzixing.com/pages/2013/11/29/nge-zheng-shu-qiu-qi-zhong-ren-yi-n-1ge-shu-de-cheng-ji-zhong-de-zui-da-de-ge-jin-yong-chu-fa.html</link><description>&lt;p&gt;刚才看程序员面试宝典的时候看到这个有趣的题目，也是google2007年的笔试题目。&lt;strong&gt;只能用乘法，不能用除法。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;看了网上一些扯到不行算法之后，我决定把我自己的想法写一下，不一定对。&lt;/p&gt;
&lt;p&gt;PS：好久没写C++,语法都忘了，跟python语法混乱了……哎。。&lt;/p&gt;
&lt;h3&gt;整个问题只会有一下3种情况&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;有两个0，最大必为0。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数组全非负，最好办，在没有两个及以上的0的情况下，把最小的剔除即可。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数组有正有负，有0，最困难。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;数组&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;——————————————————————————————————————————————&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;min1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;65534&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;min2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;65535&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;No&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;No_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;No_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;z_num&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;初始化参数；&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;   
     &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;z_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;保留第一个&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;的位置，，如果两个零，第二个零&lt;/span&gt; &lt;span class="err"&gt;的位置也没有必要存储了。&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;记录最小的项，并跳过&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="err"&gt;；&lt;/span&gt; 
        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;跳过这个最小项。&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;正数记最小的&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;min2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;min2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;No_2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;记录下最小的正数据&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;负数记最大的，绝对值最小&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;min1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;min1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;No_1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;记录下最小的正数据&lt;/span&gt;    
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;   
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="err"&gt;（&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;超过&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;个零&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;elif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;只有一个零&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;求乘积，结果可能就是这个结果。&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;初始化&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="n"&gt;z_num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;跳过&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;_____________________________________________________________&lt;/span&gt;    
&lt;span class="n"&gt;elif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;无零情况&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;这个&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="err"&gt;是第一次循环算出来的。大于&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;则必为最大。&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;    
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="err"&gt;小于&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;最小为负数，则使用最小的正数与之交换，最小的正数为&lt;/span&gt;&lt;span class="n"&gt;min2&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="err"&gt;（&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="err"&gt;；&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="err"&gt;）&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;求乘积&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;   
                &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="n"&gt;No_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                     &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="err"&gt;：&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;            
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;//mi&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;需要把最小的负数拿来交换&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;最小的复数为&lt;/span&gt;&lt;span class="n"&gt;min1&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;   
        &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="err"&gt;（&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="err"&gt;；&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="err"&gt;）&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="err"&gt;求乘积&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;   
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="n"&gt;No_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="err"&gt;：&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;   
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;_________________________________________________finished&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;But&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;so&lt;/span&gt; &lt;span class="n"&gt;comlplicated&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;按道理说应该是没有错的。但是不可能这么长，所以，应该有更快，更好的方法。如果你知道的话，告诉我一下。谢谢！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 29 Nov 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-11-29:pages/2013/11/29/nge-zheng-shu-qiu-qi-zhong-ren-yi-n-1ge-shu-de-cheng-ji-zhong-de-zui-da-de-ge-jin-yong-chu-fa.html</guid><category>算法</category></item><item><title>【原创】scapy简单教程</title><link>http://www.muzixing.com/pages/2013/11/29/yuan-chuang-scapyjian-dan-jiao-cheng.html</link><description>&lt;p&gt;如果你是网络研究的爱好者，有一个工具是对你很有用的，那就是scapy!&lt;/p&gt;
&lt;p&gt;scapy能够封装出目前网络上绝大多数（不确定是不是全部）的数据包，如IP，ARP,ICMP。有了这些数据包，你再也不需要为如何产生某些数据包而烦恼了。&lt;/p&gt;
&lt;h3&gt;首先我们需要先安装scapy&lt;/h3&gt;
&lt;p&gt;具体可以自行google,baidu,或者查看：http://www.secdev.org/projects/scapy/doc/installation.html&lt;/p&gt;
&lt;h3&gt;构建一个简单的IP包&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ip_paket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;10.0.0.1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;这样你就可以构造出一个IP包了。括弧里面填写的内容就是相关字段的内容。&lt;/p&gt;
&lt;h3&gt;查看字段&lt;/h3&gt;
&lt;p&gt;如果你想知道有那些字段，那么你就需要用到ls()命令。如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="err"&gt;（&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="err"&gt;）&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;运行结果：&lt;/p&gt;
&lt;p&gt;&lt;img alt="ls" src="http://e.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=a1592a2c0cf41bd5de53e8f161e1f0f6/d31b0ef41bd5ad6e0183a9ed83cb39dbb6fd3cbb.jpg?referer=d6124b2ee9c4b7456d8382267c5a&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;ls在scapy中可以直接对任何结构体进行解析。可以把数据包的内容展现在你面前。&lt;/p&gt;
&lt;h5&gt;我们还可以直接查看某一个字段&lt;/h5&gt;
&lt;p&gt;&lt;img alt="view" src="http://c.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=2b5a4b2cb251f819f525034fea8f3bd0/b21bb051f81986182432228348ed2e738bd4e644.jpg?referer=1ab2a90a249759ee134755fb425a&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Payload为数据包的净荷，可以由以下的代码可以查看payload。&lt;/p&gt;
&lt;p&gt;&lt;img alt="PAYLOAD" src="http://a.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=ee699c54f4246b607f0eb271dbc36b71/6a63f6246b600c33d7241ccf184c510fd9f9a15c.jpg?referer=fd54aeb5b0b7d0a222de31ad0f32&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;我们继续感受一下scapy的便捷。&lt;/p&gt;
&lt;h5&gt;我们也可以看看scapy的封装解封装能力！&lt;/h5&gt;
&lt;p&gt;&lt;img alt="packet" src="http://h.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=fc0780c7f536afc30a0c3f6083229af9/79f0f736afc37931f51d4b2ee9c4b74543a91144.jpg?referer=5649b43f6c061d95245102085f5b&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;h5&gt;数据包的发送与接收：&lt;/h5&gt;
&lt;p&gt;&lt;img alt="send" src="http://d.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=7f8a8529d01b0ef468e8985bedff20e7/7c1ed21b0ef41bd5762625f353da81cb39db3d44.jpg?referer=a279f262b119ebc4996f43a97b5b&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;我们可以发现第一次发送的时候，在选路过程中，收到了27个数据包回复。接下来就越来越少，最后只剩下一个了。
 &lt;img alt="type" src="http://e.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=15a850b1cb177f3e1434fc0840f44afa/a686c9177f3e67090d5d87f839c79f3df8dc555c.jpg?referer=1067c2cde4cd7b89b07b0fb39332&amp;amp;x=.jpg" /&gt;
我们可以看到是echo_reply的类型。&lt;/p&gt;
&lt;p&gt;原创作品，转载请说明。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 29 Nov 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-11-29:pages/2013/11/29/yuan-chuang-scapyjian-dan-jiao-cheng.html</guid><category>scapy</category></item><item><title>［原］poxdesk实现拓扑显示</title><link>http://www.muzixing.com/pages/2013/11/29/yuan-poxdeskshi-xian-tuo-bu-xian-shi.html</link><description>&lt;h3&gt;POXDESK实现拓扑的显示&lt;/h3&gt;
&lt;p&gt;今天实习第二天，开始深入逐渐玩POX跟mininet！之前只是会基本的操作，慢慢的要更加了解！今天早上就实现了一下poxdesk的功能！&lt;/p&gt;
&lt;h4&gt;操作步骤如下：&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;https:&lt;/span&gt;&lt;span class="sr"&gt;//gi&lt;/span&gt;&lt;span class="n"&gt;thub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/noxrepo/&lt;/span&gt;&lt;span class="n"&gt;pox&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;pox&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="n"&gt;betta&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;https:&lt;/span&gt;&lt;span class="sr"&gt;//gi&lt;/span&gt;&lt;span class="n"&gt;thub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/MurphyMc/&lt;/span&gt;&lt;span class="n"&gt;poxdesk&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;poxdesk&lt;/span&gt;
&lt;span class="n"&gt;wget&lt;/span&gt; &lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;downloads&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sourceforge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="sr"&gt;/qooxdoo/&lt;/span&gt;&lt;span class="n"&gt;qooxdoo&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.0.2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;
&lt;span class="n"&gt;unzip&lt;/span&gt; &lt;span class="n"&gt;qooxdoo&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.0.2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;
&lt;span class="n"&gt;mv&lt;/span&gt; &lt;span class="n"&gt;qooxdoo&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.0.2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sdk&lt;/span&gt; &lt;span class="sx"&gt;qx&lt;/span&gt;
&lt;span class="sx"&gt;cd poxdesk&lt;/span&gt;
&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="sr"&gt;/../&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;pox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pretty_log&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt; &lt;span class="n"&gt;messenger&lt;/span&gt; &lt;span class="n"&gt;messenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_service&lt;/span&gt; &lt;span class="n"&gt;messenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ajax_transport&lt;/span&gt; &lt;span class="n"&gt;openflow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;of_service&lt;/span&gt; &lt;span class="n"&gt;poxdesk&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;按照步骤去操作就可以安装poxdesk了！但是还需要注意的是：&lt;/p&gt;
&lt;h5&gt;1：打开POX的时候需要打开discovery.py所以最后一句应该为：&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;pox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pretty_log&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt; &lt;span class="n"&gt;messenger&lt;/span&gt; &lt;span class="n"&gt;messenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_service&lt;/span&gt; &lt;span class="n"&gt;messenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ajax_transport&lt;/span&gt; &lt;span class="n"&gt;openflow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;of_service&lt;/span&gt; &lt;span class="n"&gt;poxdesk&lt;/span&gt; &lt;span class="n"&gt;poxdesk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discovery&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Samples.pretty.log是一个组件，可以让pox开启的时候有字体有颜色，不添加也可以，但是界面比较难看。&lt;/p&gt;
&lt;h5&gt;2:mininet需要打开，并与pox 连接：&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Sudo&lt;/span&gt; &lt;span class="n"&gt;mn&lt;/span&gt; &lt;span class="err"&gt;–&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6633&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;127.0.0.1是本机的IP，端口号默认6633，可不写
为了画出跟更好看，更复杂的拓扑，我们需要在命令之后加上这样一句话：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;即为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Sudo&lt;/span&gt; &lt;span class="n"&gt;mn&lt;/span&gt; &lt;span class="err"&gt;–&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6633&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;topo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;n为层级，m为每一个层级下面有几个孩子&lt;/p&gt;
&lt;h5&gt;3：建立完连接之后，在浏览器中登录http://127.0.0.1:8000/poxdesk .&lt;/h5&gt;
&lt;p&gt;&lt;img alt="poxdesk" src="http://h.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=146a5049c88065387feaa416a7e6d079/b17eca8065380cd7165a77eaa344ad3459828175.jpg?referer=49627d21fffaaf51ddf4b48fef2b&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;点击网页左下角的图标pox,可以打开许多小框。&lt;/p&gt;
&lt;p&gt;&lt;img alt="poxdesk_1" src="http://a.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=29f290f839c79f3d8be1e4358a9abc2c/71cf3bc79f3df8dc31cf5a96cf11728b461028c3.jpg?referer=ef7cef1340a7d933e6bfd04388c1&amp;amp;x=.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="topo" src="http://f.hiphotos.bdimg.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=d527662f347adab439d01b46bbefc221/8718367adab44aed034d6be3b11c8701a18bfbb2.jpg?referer=74d0dd5a57fbb2fb6d3c6d224550&amp;amp;x=.jpg" /&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Fri, 29 Nov 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-11-29:pages/2013/11/29/yuan-poxdeskshi-xian-tuo-bu-xian-shi.html</guid><category>SDN</category><category>Openflow</category></item><item><title>【原创】POX运行机制 by李呈</title><link>http://www.muzixing.com/pages/2013/11/28/yuan-chuang-poxyun-xing-ji-zhi-byli-cheng.html</link><description>&lt;h3&gt;Pox以及组件的启动&lt;/h3&gt;
&lt;p&gt;配图版请浏览：http://user.qzone.qq.com/350959853/blog/1376471361&lt;/p&gt;
&lt;p&gt;SDNAP链接： http://www.sdnap.com/sdnap-post/2058.html &lt;/p&gt;
&lt;h5&gt;1：启动pox.py。&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;pox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Pox.py 里面除了一堆的注释以外，真正有用的只有几句会运行的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;boot&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boot&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;boot()函数在pox.boot里，有什么内容呢？&lt;/p&gt;
&lt;h6&gt;1：把pox和ext两个文件夹的路径加入系统path中。&lt;/h6&gt;
&lt;h6&gt;2：由_do_ import添加各个模块&lt;/h6&gt;
&lt;h6&gt;3：_do_launch去启动各个模块，启动pox&lt;/h6&gt;
&lt;h6&gt;4：定义Options和POXoptions两个类，用于定义选项&lt;/h6&gt;
&lt;h6&gt;5：定义了其他预启动项，如写日记等等。&lt;/h6&gt;
&lt;p&gt;核心的启动代码是以下的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;boot&lt;/span&gt; &lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  Start up POX.&lt;/span&gt;
&lt;span class="s"&gt;  &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

  &lt;span class="c1"&gt;# Add pox directory to path&lt;/span&gt;
  &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pox&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;ext&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

  &lt;span class="n"&gt;try:&lt;/span&gt;
    &lt;span class="n"&gt;argv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;

    &lt;span class="c1"&gt;# Always load cli (first!)&lt;/span&gt;
    &lt;span class="c1"&gt;#TODO: Can we just get rid of the normal options yet?&lt;/span&gt;
    &lt;span class="n"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;break&lt;/span&gt;
    &lt;span class="n"&gt;argv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;py --disable&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_do_launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="n"&gt;_post_startup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;

  &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;SystemExit:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="n"&gt;except:&lt;/span&gt;
    &lt;span class="n"&gt;traceback&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print_exc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_main_thread_function:&lt;/span&gt;
    &lt;span class="n"&gt;_main_thread_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;#core.acquire()&lt;/span&gt;
    &lt;span class="n"&gt;try:&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running:&lt;/span&gt;
        &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;except:&lt;/span&gt;
      &lt;span class="n"&gt;pass&lt;/span&gt;
    &lt;span class="c1"&gt;#core.scheduler._thread.join() # Sleazy&lt;/span&gt;

 &lt;span class="n"&gt;try:&lt;/span&gt;
    &lt;span class="n"&gt;pox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="n"&gt;except:&lt;/span&gt;
    &lt;span class="n"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;_do_launch()启动了pox及相关组件。之后通过_post_startup()启动openflow.of_01。core.goUp则启动了core里面的登记Debug信息和事件机制。
core.py里面最后一句：core=POXCore(),使得整个类有了实例化，在外部调用时，直接使用core。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;组件加载&lt;/h3&gt;
&lt;p&gt;在启动pox的时候，相应会启动pox的许多组件，而不是单一的仅仅启动一个pox的主程序。启动了相关组件之后，才能去管理各个组件，并通过handler去管理消息队列中的不同的事件，实现事件的管理。组件的加载与初始化在boot()文件里的_do_launch()函数里，代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_do_launch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;component_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
  &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="n"&gt;curargs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="n"&gt;pox_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;curargs&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;argv:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;components:&lt;/span&gt;
        &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
      &lt;span class="n"&gt;curargs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
      &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;curargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;component_order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lstrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;curargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="n"&gt;_options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pox_options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;_pre_startup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;inst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;component_order:&lt;/span&gt;
    &lt;span class="n"&gt;cname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;launch&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_do_import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;False:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;
    &lt;span class="c1"&gt;#print(&amp;quot;&amp;gt;&amp;gt;&amp;quot;,name)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;首先创建component_order的列表，用于存放组件的名称。然后再逐个启动，初始化。&lt;/p&gt;
&lt;p&gt;第&lt;strong&gt;162&lt;/strong&gt;行，讲名字分为两部分。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;163&lt;/strong&gt;行则决定了启动的默认顺序。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;launch&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;使用_do_import()函数将相关组件模块引入。&lt;/p&gt;
&lt;p&gt;第&lt;strong&gt;171&lt;/strong&gt;行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;launch&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;检查launch是否属于sys.modules这个字典。而__dict__是python里面的特性字典，，用于存放类的实例的所有特性。&lt;/p&gt;
&lt;p&gt;第&lt;strong&gt;172&lt;/strong&gt;行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;从模块中，实例化函数。&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;第&lt;strong&gt;199&lt;/strong&gt;行 初始化函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;try:&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;举例：&lt;/h3&gt;
&lt;p&gt;L2_learning作为pox里面最重要的一个二层组件之一，再适合不过了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transparent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hold_down&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_flood_delay&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Starts an L2 learning switch.&lt;/span&gt;
&lt;span class="s"&gt;  &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;try:&lt;/span&gt;
        &lt;span class="n"&gt;global&lt;/span&gt; &lt;span class="n"&gt;_flood_delay&lt;/span&gt;
        &lt;span class="n"&gt;_flood_delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hold_down&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;_flood_delay&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;except:&lt;/span&gt;
        &lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected hold-down to be a number&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;registerNew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l2_learning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;str_to_bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;可以看到launch()函数里面仅有一句话是可执行的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;registerNew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;_learning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;_bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;让我们去看一看core.registerNew()这个函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;registerNew&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__componentClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Give it a class (and optional __init__ arguments), and it will&lt;/span&gt;
&lt;span class="s"&gt;    create an instance and register it using the class name.  If the&lt;/span&gt;
&lt;span class="s"&gt;    instance has a _core_name property, it will use that instead.&lt;/span&gt;
&lt;span class="s"&gt;    It returns the new instance.&lt;/span&gt;
&lt;span class="s"&gt;    core.registerNew(FooClass, arg) is roughly equivalent to&lt;/span&gt;
&lt;span class="s"&gt;    core.register(&amp;quot;&lt;/span&gt;&lt;span class="n"&gt;FooClass&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;, FooClass(arg)).&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;__componentClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;
    &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;__componentClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;_core_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="c1"&gt;# Default overridden&lt;/span&gt;
      &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_core_name&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;可执行语句很少，基本上注释已经完全涵盖了这个函数的作用。主要是在pox注册一个新的线程，如果已存在名字则重载，返回新的实例。同时我们看到在这个函数里面使用到了register()函数，函数定义如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Makes the object &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; available as pox.core.core.name.&lt;/span&gt;

&lt;span class="s"&gt;    If only one argument is specified, the given argument is registered&lt;/span&gt;
&lt;span class="s"&gt;    using its class name as the name.&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="c1"&gt;#TODO: weak references?&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt;
      &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
      &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;_core_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Default overridden&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_core_name&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;components:&lt;/span&gt;
      &lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Warning: Registered &amp;#39;%s&amp;#39; multipled times&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raiseEventNoErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ComponentRegistered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_try_waiters&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Register()实现了在初始化的时候，将相关组件加入到了pox.core.core之中。Core raise了一个ComponentRegistered事件，componentRegistered类定义如下，接着进入等待阶段。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ComponentRegistered&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  This is raised by core whenever a new component is registered.&lt;/span&gt;
&lt;span class="s"&gt;  By watching this, a component can monitor whether other components it&lt;/span&gt;
&lt;span class="s"&gt;  depends on are available.&lt;/span&gt;
&lt;span class="s"&gt;  &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
  &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;进行到这里，我们需要做的还有一件事，就是将组件的event_handler与相应的events绑定到一起。
那么在哪里实现了这一个绑定关系呢？&lt;/p&gt;
&lt;h3&gt;事件绑定&lt;/h3&gt;
&lt;p&gt;在每一个组件里面都会有初始函数，而每一个初始函数里面多包含事件绑定的开始们那就是listenTo()函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listenTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openflow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transparent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transparent&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;listenTo()函数在哪里出现呢？寻找之后，你会发现他出现在一个非常重要的文件——revent.py里面。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;listenTo&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Automatically subscribe to events on source.&lt;/span&gt;

&lt;span class="s"&gt;    This method tries to bind all _handle_ methods on self to events&lt;/span&gt;
&lt;span class="s"&gt;    on source.  Kind of the opposite of addListeners().&lt;/span&gt;

&lt;span class="s"&gt;    See also: addListeners(), autoBindEvents()&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;autoBindEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;继续调用autoBindEvents()函数实现绑定。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;autoBindEvents&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  Automatically set up listeners on sink for events raised by source.&lt;/span&gt;

&lt;span class="s"&gt;  Often you have a &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; object that is interested in multiple events&lt;/span&gt;
&lt;span class="s"&gt;  raised by some other &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; object.  This method makes setting that&lt;/span&gt;
&lt;span class="s"&gt;  up easy.&lt;/span&gt;
&lt;span class="s"&gt;  You name handler methods on the sink object in a special way.  For&lt;/span&gt;
&lt;span class="s"&gt;  example, lets say you have an object mySource which raises events of&lt;/span&gt;
&lt;span class="s"&gt;  types FooEvent and BarEvent.  You have an object mySink which wants to&lt;/span&gt;
&lt;span class="s"&gt;  listen to these events.  To do so, it names its handler methods&lt;/span&gt;
&lt;span class="s"&gt;  &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;_handle_FooEvent&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; and &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;_handle_BarEvent&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.  It can then simply call&lt;/span&gt;
&lt;span class="s"&gt;  autoBindEvents(mySink, mySource), and the handlers are set up.&lt;/span&gt;

&lt;span class="s"&gt;  You can also set a prefix which changes how the handlers are to be named.&lt;/span&gt;
&lt;span class="s"&gt;  For example, autoBindEvents(mySink, mySource, &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;source1&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;) would use a&lt;/span&gt;
&lt;span class="s"&gt;  handler named &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;_handle_source1_FooEvent&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&lt;/span&gt;

&lt;span class="s"&gt;  &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; has the same meaning as with addListener().&lt;/span&gt;

&lt;span class="s"&gt;  Returns the added listener IDs (so that you can remove them later).&lt;/span&gt;
&lt;span class="s"&gt;  &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;_eventMixin_events&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;False:&lt;/span&gt;
    &lt;span class="c1"&gt;# If source does not declare that it raises any events, do nothing&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Warning: source class %s doesn&amp;#39;t specify any events!&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;
          &lt;span class="nv"&gt;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;

  &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_events:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;str:&lt;/span&gt;
      &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;

  &lt;span class="n"&gt;listeners&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
  &lt;span class="c1"&gt;# for each method in sink&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# get the method object&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="c1"&gt;# if it has the revent prefix signature, &lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_handle&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;m[8+len(prefix):]&lt;/span&gt;
        &lt;span class="c1"&gt;# and it is one of the events our source triggers&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;events:&lt;/span&gt;
          &lt;span class="c1"&gt;# append the listener&lt;/span&gt;
          &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                              &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="c1"&gt;#print(&amp;quot;autoBind: &amp;quot;,source,m,&amp;quot;to&amp;quot;,sink)&lt;/span&gt;
        &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event:&lt;/span&gt;
          &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Warning: %s found in %s, but %s not raised by %s&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt;
                &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从注释中我们可以看出这个函数的作用:
无非就是讲handler端的sink和event的source连接起来，方式为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                          &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;其中用到的addListener()是这个连接的关键，代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;addListener&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;once&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Add an event handler for an event triggered by this object (subscribe).&lt;/span&gt;

&lt;span class="s"&gt;    eventType : event class object (e.g. ConnectionUp). If byName is True,&lt;/span&gt;
&lt;span class="s"&gt;                should be a string (e.g. &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;ConnectionUp&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;) &lt;/span&gt;
&lt;span class="s"&gt;    handler : function/method to be invoked when event is raised &lt;/span&gt;
&lt;span class="s"&gt;    once : if True, this handler is removed after being fired once&lt;/span&gt;
&lt;span class="s"&gt;    weak : If handler is a method on object A, then listening to an event&lt;/span&gt;
&lt;span class="s"&gt;           on object B will normally make B have a reference to A, so A&lt;/span&gt;
&lt;span class="s"&gt;           can not be released until after B is released or the listener&lt;/span&gt;
&lt;span class="s"&gt;           is removed.&lt;/span&gt;
&lt;span class="s"&gt;           If weak is True, there is no relationship between the lifetimes&lt;/span&gt;
&lt;span class="s"&gt;           of the publisher and subscriber.&lt;/span&gt;
&lt;span class="s"&gt;    priority : The order in which to call event handlers if there are&lt;/span&gt;
&lt;span class="s"&gt;               multiple for an event type.  Should probably be an integer,&lt;/span&gt;
&lt;span class="s"&gt;               where higher means to call it earlier.  Do not specify if&lt;/span&gt;
&lt;span class="s"&gt;               you don&amp;#39;t care.&lt;/span&gt;
&lt;span class="s"&gt;    byName : True if eventType is a string name, else an Event subclass&lt;/span&gt;

&lt;span class="s"&gt;    Raises an exception unless eventType is in the source&amp;#39;s&lt;/span&gt;
&lt;span class="s"&gt;    _eventMixin_events set (or, alternately, _eventMixin_events must&lt;/span&gt;
&lt;span class="s"&gt;    be True).&lt;/span&gt;

&lt;span class="s"&gt;    The return value can be used for removing the listener.&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_events&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
        &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;eventType&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_events&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="c1"&gt;# eventType wasn&amp;#39;t found&lt;/span&gt;
      &lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;byName:&lt;/span&gt;
        &lt;span class="c1"&gt;# if we were supposed to find the event by name, see if one of the&lt;/span&gt;
        &lt;span class="c1"&gt;# event names matches&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_events:&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;issubclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;eventType:&lt;/span&gt;
              &lt;span class="n"&gt;eventType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
              &lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
              &lt;span class="n"&gt;break&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fail:&lt;/span&gt;
        &lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Event %s not defined on object of type %s&amp;quot;&lt;/span&gt;
                           &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eventType&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers:&lt;/span&gt;
      &lt;span class="c1"&gt;# if no handlers are already registered, initialize&lt;/span&gt;
      &lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;eid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_generateEventID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;weak:&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CallProxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;once&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt;
      &lt;span class="c1"&gt;# If priority is specified, sort the event handlers&lt;/span&gt;
      &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;itemgetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;第400行的if建立一个与eventType对应的handlers：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eventType&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers:&lt;/span&gt;
  &lt;span class="c1"&gt;# if no handlers are already registered, initialize&lt;/span&gt;
  &lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
  &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;第413行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt;
  &lt;span class="c1"&gt;# If priority is specified, sort the event handlers&lt;/span&gt;
  &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;itemgetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;将带有handler和eid等信息的entry添加到handlers队列中，priority决定这个handlers在处理时的优先级，若无特殊优先级，则按正常顺序放在队尾。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;_eventMixin_init&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_eventMixin_events&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_eventMixin_events&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_eventMixin_handlers&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;_eventMixin_handlers&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;在_eventMixin_init()函数里，我们发现在这里我们setattr()了一个_eventMixin_events的特性和_eventMixin_handlers的列表。&lt;/p&gt;
&lt;p&gt;这些数据在autoBindEvents()里面有使用到：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;_eventMixin_events&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;False:&lt;/span&gt;
    &lt;span class="c1"&gt;# If source does not declare that it raises any events, do nothing&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Warning: source class %s doesn&amp;#39;t specify any events!&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;
          &lt;span class="nv"&gt;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;一个很重要的问题是，handlers在哪里？没有handlers就无法就行连接，更不用说接下来的事件处理了。我们来再看一次autoBindEvents()函数，我们观察到source.我们去查看source这个类就会发现问题的答案在哪里了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventMixin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="c1"&gt;# Defining this variable tells the revent library what kind of events&lt;/span&gt;
  &lt;span class="c1"&gt;# this source can raise.&lt;/span&gt;
  &lt;span class="n"&gt;_eventMixin_events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;ComponentRegistered&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# We can raise events as follows:&lt;/span&gt;
    &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;fake_pox_component&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raiseEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ComponentRegistered&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# In the above invocation, the argument is an instance of&lt;/span&gt;
    &lt;span class="c1"&gt;# ComponentRegistered (which is a subclass of Event).  The following is&lt;/span&gt;
    &lt;span class="c1"&gt;# functionally equivalent, but has the nice property that &lt;/span&gt;
    &lt;span class="c1"&gt;# ComponentRegistered is never instantiated if there are no listeners.&lt;/span&gt;
    &lt;span class="c1"&gt;#self.raiseEvent(ComponentRegistered, component)&lt;/span&gt;
    &lt;span class="c1"&gt;# In both cases, &amp;quot;component&amp;quot; is passed to the __init__ method for the&lt;/span&gt;
    &lt;span class="c1"&gt;# ComponentRegistered class.&lt;/span&gt;

    &lt;span class="c1"&gt;# The above method invocation will raise an exception if an event&lt;/span&gt;
    &lt;span class="c1"&gt;# handler rauses an exception.  To project yourself from exceptions in&lt;/span&gt;
    &lt;span class="c1"&gt;# handlers, see raiseEventNoErrors().&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Source类中调用了raiseEvent()函数，我们再去查看raiseEvent()函数。
在这个函数里面我们找到了handlers的赋值（提取）语句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# Create a copy so that it can be modified freely during event&lt;/span&gt;
&lt;span class="c1"&gt;# processing.  It might make sense to change this.&lt;/span&gt;
&lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;整个事件绑定的过程大概可以总结如下：
在事件发生段，即源端在产生事件的时候要raise一个event, 监听端使用监听函数如：ListenTo()不断监听端口，有消息进来，则建立连接，存于对应字典，同时将handler注册到_eventMixin_handlers这个列表中。&lt;/p&gt;
&lt;h3&gt;事件处理：&lt;/h3&gt;
&lt;p&gt;事件处理的函数主要有：raiseEventsNoErrors()和raiseEvents()函数。
但是raiseEventsNoErrors() 函数里面其主要的语句一样是使得最终的条件满足从而调用raiseEvents()函数，所以让我们来看一看raiseEvents()函数的注释：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;raiseEvent&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    Raises an event.&lt;/span&gt;
&lt;span class="s"&gt;    If &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; is an Event type, it will be initialized with args and kw,&lt;/span&gt;
&lt;span class="s"&gt;    but only if there are actually listeners.&lt;/span&gt;
&lt;span class="s"&gt;    Returns the event object, unless it was never created (because there&lt;/span&gt;
&lt;span class="s"&gt;    were no listeners) in which case returns None.&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;主要的作用是raise一个event，这个显而易见。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# Create a copy so that it can be modified freely during event&lt;/span&gt;
&lt;span class="c1"&gt;# processing.  It might make sense to change this.&lt;/span&gt;
&lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;once&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;handlers:&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;classCall:&lt;/span&gt;
    &lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;once:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removeListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;None:&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;False:&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removeListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;True:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;classCall:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;halt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;break&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tuple:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;rv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;True:&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removeListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;rv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;classCall:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;halt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
      &lt;span class="n"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;classCall:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;halt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
      &lt;span class="n"&gt;break&lt;/span&gt;
  &lt;span class="c1"&gt;#if classCall and hasattr(event, &amp;quot;halt&amp;quot;) and event.halt:&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;classCall&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;halt:&lt;/span&gt;
    &lt;span class="n"&gt;break&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;L278:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eventMixin_handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;从handlers中按照eventType提取出handler,然后对handler遍历。如果once =true(L284)则把监听器去除，即将handler移除。最后入伙遭遇停止标记event.halt则退出循环。事件处理队列终止。&lt;/p&gt;
&lt;h3&gt;后续&lt;/h3&gt;
&lt;p&gt;之后再读了北邮泛网无线教育部重点实验室李德民学长的一篇关于pox的文章（Ref: http://lidemin.pw/190）之后再写了一点东西如下：
在启动pox以及各个组件的时候，core=POXCore()的实例化中有提到：&lt;/p&gt;
&lt;p&gt;这个scheduler是上文一直都没有提到的。
Core.scheduler线程的动作如下：
第一次连接时，建立socket连接，实例化一个connection的类。
接下来的通信过程就需要进一步的学习才能写出来了。&lt;/p&gt;
&lt;h3&gt;感想:&lt;/h3&gt;
&lt;p&gt;自己还是太年轻，太浮夸，从来没有好好看过代码，好好研究过POX的运行机制，还好有实验室的学长写过的一些文章可以读，然后自己照着做一遍，做完之后会有深刻的理解，但是目前，整一个Openflow协议在动态过程中的通信流程并不是特别了解。下一阶段的学习目标是把Openflow协议的通信过程学习一遍，结合之前画过的静态的数据结果，我相信效果应该会很好。Openflow协议的扩展也在很努力地做，有了这些基础之后，如何求改协议，比以前已经变得轻松多了。在此感谢两位学长留下的财富。&lt;/p&gt;
&lt;p&gt;参考文献：&lt;/p&gt;
&lt;p&gt;李德民学长主页:http://lidemin.pw/190&lt;/p&gt;
&lt;p&gt;赵伟辰学长主页:http://richardzhao.me/?p=594&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">muzi</dc:creator><pubDate>Thu, 28 Nov 2013 00:00:00 +0800</pubDate><guid>tag:www.muzixing.com,2013-11-28:pages/2013/11/28/yuan-chuang-poxyun-xing-ji-zhi-byli-cheng.html</guid><category>SDN</category><category>Openflow</category></item></channel></rss>