63

深入OpenFlowPlugin源码分析OpenFlow握手过程(二)

 4 years ago
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中管理。在下面会详细展开,每个步骤。

VRfi6zj.jpg!web

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 对象并传入对象引用到 connectionAdapterImplconnectionContext
    • OutboundQueueHandler 对象用于Packet output先到Queue,再到 ConnectionAdapterImpl 对象。另外一篇:《OpenFlowPlugin outbound机制》会展开,在此不深入。
  • 创建 DeviceContextImpl 对象
  • 创建 OpenflowProtocolListenerFullImpl 对象,并传入引用到 connectionAdapterImpl 对象( setMessageListenersetAlienMessageListener ),用于处理底层Switch传递给控制器的所有message。
    • 注意:在上两篇笔记中,当Switch连上控制器时调用 ConnectionManagerImpl.onSwitchConnected() 方法,会同样会传入一个MessageListener对象 OpenflowProtocolListenerInitialImpl ,此对象仅能出来Hello message,在Handshake阶段使用。而此时Handshake已经结束,重新传入 OpenflowProtocolListenerFullImpl 用于处理所有message。

qm63EjB.jpg!web

创建RpcContext

创建RpcContext,且传入自身对象(ContextChainHolderImpl)引用:

final RpcContext rpcContext = rpcManager.createContext(deviceContext);

rpcContext.registerMastershipWatcher(this);

创建rpcContext处理:

  • 创建 RpcContextImpl 对象

bQbyU36.jpg!web

创建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
  • 创建 StatisticsContextImpl 对象
    • 传入了 MultipartWriterProvider 对象,目的是 StatisticsContextImpl 收集的数据可以写入device operational yang节点

miimQbz.jpg!web

创建RoleContext

创建RoleContext,且传入自身对象(ContextChainHolderImpl)引用:

final RoleContext roleContext = roleManager.createContext(deviceContext);

roleContext.registerMastershipWatcher(this);

创建RoleContext处理:

  • 创建 RoleContextImpl 对象;
  • 创建 SalRoleServiceImpl 对象,传入 RoleContextImpl 。用于后续步骤,设置Switch的Master/Slave role。

rmYf22E.jpg!web

创建ContextChain

在创建4个Context后,创建 ContextChainImpl 对象。然后向 ContextChainImpl 对象注册/加入各个对象:

  1. ContextChainImpl 对象注册registerDeviceRemovedHandler,用于后续Switch下线过程清除Manger中各个Context的索引。
  2. ContextChainImpl 对象添加Context( addContext )。
  3. 最后将 ContextChainImpl 对象保存到 ContextChainHolderImpl.contextChainMap 中,相当于一个索引。 ContextChainHolderImpl 维护了各个Switch的ContextChain对象。

MBjM3aR.jpg!web

注意 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对象。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK