深入OpenFlowPlugin源码分析OpenFlow握手过程(二)
source link: https://www.tuicool.com/articles/uemmumI
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
【编者的话】本文为OpenFlowPlugin(0.6.2)源码分析第二篇,也是OpenFlowPlugin为上层北向应用提供服务的关键逻辑的开篇!
回顾第一篇笔记,在Switch连上控制器Handshake完成后,会调用 ContextChainHolderImpl.deviceConnected
方法,会为Switch创建其对应的 ContextChain
对象则创建。
createContextChain(connectionContext);
先给出总结:在OpenFlowPlugin中,每个Switch都有唯一的 ContextChain
对象,管理其在OpenFlowPlugin的生命周期。
创建生命周期管理对象ContextChain
为连上的Switch创建 contextChain
对象,通过调用 ContextChainHolderImpl.createContextChain
方法。在创建ContextChain前,会先为Switch创建四个对象DeviceContext、RpcContext、StatisticsContext、RoleContext,四个对象封装了Switch的四种类型操作:Device基本信息、RPC请求、Statistics数据收集、Master/Slava角色调用。最后,将四个Context对象都传入ContextChain中管理。在下面会详细展开,每个步骤。
ContextChainHolderImpl.createContextChain
方法是Switch连上控制器Handshake完成后的核心调用,这个方法主要逻辑:
创建DeviceContext
创建deviceContext,且传入自身对象(ContextChainHolderImpl)引用:
final DeviceContext deviceContext = deviceManager.createContext(connectionContext); deviceContext.registerMastershipWatcher(this);
创建 deviceContext
处理:
- 设置
ConnectionAdapterImpl
对象中设置packetIn filter为true,目的是为了过滤后续过程中收到底层Switch的packetIn message- 注:可以看到在
ContextChainHolderImpl.createContextChain
方法后面会将packetIn filter恢复为false。
- 注:可以看到在
- 创建
OutboundQueueHandler
对象并传入对象引用到connectionAdapterImpl
和connectionContext
-
OutboundQueueHandler
对象用于Packet output先到Queue,再到ConnectionAdapterImpl
对象。另外一篇:《OpenFlowPlugin outbound机制》会展开,在此不深入。
-
- 创建
DeviceContextImpl
对象 - 创建
OpenflowProtocolListenerFullImpl
对象,并传入引用到connectionAdapterImpl
对象(setMessageListener
和setAlienMessageListener
),用于处理底层Switch传递给控制器的所有message。- 注意:在上两篇笔记中,当Switch连上控制器时调用
ConnectionManagerImpl.onSwitchConnected()
方法,会同样会传入一个MessageListener对象OpenflowProtocolListenerInitialImpl
,此对象仅能出来Hello message,在Handshake阶段使用。而此时Handshake已经结束,重新传入OpenflowProtocolListenerFullImpl
用于处理所有message。
- 注意:在上两篇笔记中,当Switch连上控制器时调用
创建RpcContext
创建RpcContext,且传入自身对象(ContextChainHolderImpl)引用:
final RpcContext rpcContext = rpcManager.createContext(deviceContext); rpcContext.registerMastershipWatcher(this);
创建rpcContext处理:
- 创建
RpcContextImpl
对象
创建StatisticsContext
创建StatisticsContext,且传入自身对象(ContextChainHolderImpl)引用:
final StatisticsContext statisticsContext = statisticsManager.createContext(deviceContext, ownershipChangeListener.isReconciliationFrameworkRegistered()); statisticsContext.registerMastershipWatcher(this);
创建StatisticsContext处理:
- 创建
MultipartWriterProvider
对象- 注意这里传入了deviceContext,是为了write到device的operational yang。
deviceContextImpl
中有写入device对应yang需要的TransactionChain
- 注意这里传入了deviceContext,是为了write到device的operational yang。
- 创建
StatisticsContextImpl
对象- 传入了
MultipartWriterProvider
对象,目的是StatisticsContextImpl
收集的数据可以写入device operational yang节点
- 传入了
创建RoleContext
创建RoleContext,且传入自身对象(ContextChainHolderImpl)引用:
final RoleContext roleContext = roleManager.createContext(deviceContext); roleContext.registerMastershipWatcher(this);
创建RoleContext处理:
- 创建
RoleContextImpl
对象; - 创建
SalRoleServiceImpl
对象,传入RoleContextImpl
。用于后续步骤,设置Switch的Master/Slave role。
创建ContextChain
在创建4个Context后,创建 ContextChainImpl
对象。然后向 ContextChainImpl
对象注册/加入各个对象:
- 给
ContextChainImpl
对象注册registerDeviceRemovedHandler,用于后续Switch下线过程清除Manger中各个Context的索引。 - 给
ContextChainImpl
对象添加Context(addContext
)。 - 最后将
ContextChainImpl
对象保存到ContextChainHolderImpl.contextChainMap
中,相当于一个索引。ContextChainHolderImpl
维护了各个Switch的ContextChain对象。
注意 addContext
是把传入的deviceContext/rpcContext/statisticsContext/roleContext封装到 GuardedContextImpl
对象。 GuardedContextImpl
对象仅做多一层封装,会记录具体Context的状态等。
@Override public <T extends OFPContext> void addContext(@Nonnull final T context) { contexts.add(new GuardedContextImpl(context)); }
最后,完成创建 ContextChainImpl
对象后,将设备从 connectingDevices
索引中删除。表示已经在控制器connected。
开始选举Master/Slave
上文基本展开了 ContextChainHolderImpl.createContextChain
方法详细讲解,唯独缺少最后一行代码,这也是最关键一行!调用ContextChain的registerServices方法:
contextChain.registerServices(singletonServiceProvider);
在展开这一行代码的逻辑之前,我们先回顾一下全文!可以看到,在Switch完成Handshake后,OpenFlowPlugin会为Switch创建ContextChain对象(包括各个Context)。考虑到多个控制器情况下,当Switch设置多个控制器(比如OVS:set-controller),那么哪个控制器能够对Switch操作,比如下发流表。因为在每个控制器,OpenFlowPlugin都会为Switch创建ContextChain对象。
OpenFlow协议,支持多个控制器,且控制器有角色有三类Master、Master、Equal。为了控制层高可用使用Master/Slave模式;为了控制器负载均衡使用equal模式。
在此,我们不讨论Equal模式,我们讨论Master/Slave模型。OpenFlowPlugin默认是以集群模型实现的,假设存在三个控制器节点,那么就会选举出一个节点作为某一个Switch的Master(不同Switch,Master不一定相同);如果OpenFlowPlugin作为单点控制器运行,那么它就是所有连上的Switch的Master。
假设在三节点的集群情况下,Switch连上所有控制节点,此时每个控制节点都有Switch的ContextChain对象,那么哪个节点是该Switch的Master?关键就是上面的这一行代码!由于篇幅问题,我们在下篇展开!
总结
在Switch完成Handshake后,OpenFlowPlugin会为Switch创建各个Context对象(Device/RPC/Statistics/Role),以及ContextChain对象。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK