(七)ODL Openflowplugin Switch断开控制器下线源码分析

作者简介:陈卓文,国内某游戏公司私有云团队开发者,主要从事SDN/NFV开发。

由于篇幅问题,我们将“Openflowplugin中Switch生命周期”这个大问题拆分为几个篇章:Switch生命周期对象ContextChain创建;控制节点的Master选举及ContextChain/Context服务实例化;MastershipChangeService以ReconciliationFramework;控制节点成为Slave;Switch下线过程。
本文为Openflowplugin(0.6.2)源码分析第七篇,分析当Switch与控制器连接断开,OFP会怎么处理

附:
第一篇:(一)ODL OpenflowPlugin启动流程源码分析
第二篇:(二)ODL Openflowplugin Switch连上控制器Handshake过程源码分析
第三篇:(三)ODL Openflowplugin Switch生命周期对象ContextChain创建源码分析
第四篇:(四)ODL Openflowplugin Master选举及Context服务实例化源码分析
第五篇:(五)ODL Openflowplugin Mastership及ReconciliationFramework源码分析
第六篇:(六)ODL Openflowplugin 控制器成为SLAVE过程源码分析

读者约定:基本掌握Opendaylight的思想/有一定实践经验,想要深入理解openflowplugin源码/想对openflowplugin源码修改。

之前笔记深入探讨了Switch上线Handshake、初始化、选举Master/Slave,触发北向应用,那么Switch与控制器连接断开下线过程是怎样的?在集群环境下,Switch与Master节点断连,会自动切换Master节点并重新初始化、选举Master/Slave,触发北向应用,其中是怎么实现的?

Switch下线过程

1.ConnectionAdapterImpl处理消息/事件

在第二篇笔记提及,在Switch连上控制器就会为每个Switch创建ConnectionAdapterImpl对象,在Handshake过程就会为ConnectionAdapterImpl对象传入对象引用SystemNotificationsListenerImpl

SystemNotificationsListenerImpl用于处理底层Switch是否与控制器连接相关的事件。在ConnectionAdapterImpl中可以看到:底层Switch事件DisconnectEventSwitchIdleEvent会调用SystemNotificationsListener的方法。而针对这两个事件的处理,DisconnectEvent会触发控制器回收Switch ContextChain等对象,而SwitchIdleEvent有可能触发控制器回收switch ContextChain等对象(即控制器主动掉与Switch连接)。

2.DisconnectEvent和SwitchIdleEvent事件触发

首先我们先来看看DisconnectEventSwitchIdleEvent事件是怎么触发的?

2.1 SwitchIdleEvent事件

首先回到TcpChannelInitializer.initChannel方法(Switch连上控制器最早触发的逻辑),会给channel加入IdleHandler,用于当IdleTimeout时间内没收到switch消息,就会触发IdleHandler.readTimedOut方法。

IdleHandler.readTimedOut方法,会build一个SwitchIdleEvent事件,并调用ctx.fireChannelRead(builder.build())将事件传递给下一个Netty pipeline的Handler。

ctx.fireChannelRead(builder.build())方法最终会调用ConnectionAdapterImpl.consumeDeviceMessage方法,即如上述所说调用SystemNotificationsListenerImpl的方法(onSwitchIdleEvent

2.2 DisconnectEvent事件

可以看到idle事件调用过程中,DelegatingInboundHandler对象用于从channel读取消息/数据。而当DelegatingInboundHandler实现的是ChannelInboundHandlerAdapter接口,根据netty底层,当channel非active时会调用channelInactive方法,发出DisconnectEvent

IdleEvent类似的,最终调用ConnectionAdapterImpl.consumeDeviceMessage方法。如上述所说调用SystemNotificationsListenerImpl的方法(onDisconnectEvent

3.SystemNotificationsListener处理事件

3.1 处理SwitchIdleEvent事件

调用SystemNotificationsListenerImpl.onSwitchIdleEvent方法,说明底层switch在idleTimeout时间内没响应,在SystemNotificationsListenerImpl对象中处理。

而处理idle事件是调用executeOnSwitchIdleEvent方法,该方法控制器会尝试发出echo消息:
(1)如果底层switch回应了,那么控制器认为Switch还在线,不作处理。
(2)如果底层switch没回应,那么控制器任务Switch已经断开连接了,调用ConnectionContextImpl.closeConnection(true);方法来清除switch在控制器的连接及相关对象:

调用ConnectionContextImpl.closeConnection(true);方法,最终调用disconnectDevice(true, true)方法。(onDisconnectEvent最终也会调用此方法,下面展开)

3.2 处理DisconnectEvent事件

SystemNotificationsListenerImpl.onDisconnectEvent说明channel已经断开,会直接调用ConnectionContextImpl.onConnectionClosed();

ConnectionContextImpl.onConnectionClosed();方法,最终也是调用disconnectDevice(true, false)(与idleEvent不同的是传入第二个参数为false)。

4.Switch与控制器真正断连

ConnectionContextImpl.disconnectDevice的调用会分别被:IdleEvent引起以及DisconnectEvent引起。两个事件分别调用方法时,传入参数不同:

  • IdleEvent:disconnectDevice(true, true);
  • DisconnectEvent:disconnectDevice(true, false);

可以看到第二个参数传入不同,第二个参数的意思是disconnect device这个动作是控制器(ofp)主动发起还是device发起。IdleEvent是控制器监听不到心跳,是控制器主动发起断开,所以第二参数为true

我们深入ConnectionContextImpl.disconnectDevice逻辑:

ConnectionContextImpl.disconnectDevice方法,执行以下逻辑:
(1)unregisterOutboundQueue、关闭handshakeContext、修改状态等。
(2)如果是IdleEvent引起,且connection还是active,会主动disconnect关闭TCP连接(channel)。
(3)无论是IdleEvent还是DisconnectEvent引起,最终均会调用propagateDeviceDisconnectedEvent()方法:

propagateDeviceDisconnectedEvent方法,实际上就是调用deviceDisconnectedHandler.onDeviceDisconnected(this)方法。即调用ContextChainHolderImpl.onDeviceDisconnected方法。

此时,开始回收Switch在OFP中的生命周期相关对象及资源。从ContextChainHolderImpl中找到此需要disconnect的switch(device)的ContextChainImpl对象,如果此connection时辅助连接那仅仅需要删掉辅助连接的context;如果connection是与switch建立的主连接,调用destroyContextChain(deviceInfo);方法。

5.销毁ContextChain

destroyContextChain(deviceInfo)方法逻辑:
(1)通知注册到MastershipService的上层应用(原生/ReconciliationFramework),在前面几篇笔记有详细介绍。
(2)发送Device删除inventory的notification,实际上并不会删除YANG中node节点,此方法其实已被官方弃用,但为了向前兼容保持,实际删除node节点在下面步骤。
(3)调用contextChain.close()方法,会回收/删除ContextChain相关的一些列对象,包括Switch的各个Context(Device/Rpc/Role/Statistics)。此为最关键一步!

调用ContextChain.close清理对象/资源

ContextChain.close方法作为回收Switch在控制器节点中的所有对象/资源的入口。

用于关闭switch的ConnectionContextImpl的大入口,具体处理了:

  • 1.设置状态CLOSED,设置相关标志位false(在初始化过程设置)
  • 2.关闭所有辅助连接
  • 3.registration.close();,关闭ConnectionContextImpl singleton service,会触发执行ConnectionContextImpl.closeServiceInstance方法,最终会调用各个contect的closeServiceInstance方法
    • registration是registerClusterSingletonService(this)的返回,调用此.close()会关闭singleton service
  • 4.调用各个context的close方法
  • 5.清除各个context manager中switch对应的context索引
  • 6.primaryConnection.closeConnection(false);最终会调用ConnectionContextImpl.disconnectDevice(false, true)保证关闭ConnectionContextImpl会回收handshakeContext等connection资源
    • ConnectionContextImpl.disconnectDevice方法在上面IdleEvent/DisconnectedEvent过程中调用了

这里,我们额外关注一个调用:registration.close(),其会导致contextChain作为singleton运行的service关闭(回顾前文:ContextChain为作为singleton service在Switch的Master节点运行并实例化服务)。而这里则是关闭服务实例!

6.Master控制节点改变(Singleton迁移)

注意,在Switch连上多个控制器情况下,如果Switch与其Master节点断开,会触发上述过程。那么Switch与另外两个控制器仍然保持连接,此时会怎样呢?

答案是:会在另外某个控制节点重新选举出Master,然后重新经历第四篇笔记过程,ODL Openflowplugin Master选举及Context服务实例化。

在上一步我们可以看到,执行了registration.close()方法,如果是Master节点上执行,那么Singleton service就会关闭,触发其他控制器节点上Master重新选举,然后重复Context服务实例化过程。

这恰恰就是OFP实现高可用的设计:控制器集群,每个Switch在Master节点上映射一个Singleton service!

7.删除YANG(Inventory)中的Node节点

如果Switch完全从所有控制器节点下线后,除了上述资源/对象的回收,控制器还会处理什么?换一个问题,在上述资源/对象的回收过程中,没有看到Switch(Node)在Inventory的Yang树被清理,那么YANG是怎么清理的呢?

Switch(Node)在Inventory Yang树被清理是在ContextChainHolderImpl中的ownershipChanged方法!

后续涉及ODL中另一个集群关键服务:EntityOwnershipService,是ODL集群下的一个实现。Singleton Service就是基于EntityOwnershipService实现的!如果读者不熟悉,可以在我后续Singleton Service笔记后再回顾。

根据ContextChainHolderImpl的实现,我们发现其实现了接口EntityOwnershipListener。在创建ContextChainHolderImpl的构造器中监听了EOS:

并有如下方法实现:

ContextChainHolderImpl监听了类型是org.opendaylight.mdsal.AsyncServiceCloseEntityType的Entity ownership变化事件,作出动作。

这里给一些上下文供读者理解,每个Switch在控制器上都有一个ContextChain,其作为Singleton service运行,而Singleton service的底层实现是EntityOwnershipService。Singleton service会将每个Switch作为Entity往底层EOS注册,并且通过EOS在控制器集群中选举出Entity的Master节点,最终反映出来就是Singleton service的Master节点!

而这里我们监听的是org.opendaylight.mdsal.AsyncServiceCloseEntityType类型的Entity。在Singleton service中,为会Switch创建此类型的Entity并注册到EOS。这个类型的Entity是当Singleton service关闭时会改变其Ownership。当此类型entity没有owner,证明Singleton service在各个节点都关闭了(registration.close())!

所以,当监听到到此类型的Entity变化,且状态是没有owner情况下,即代表Switch与各个控制器节点都断开连接!所以,需要删除Inventory Yang的node节点!这样,yang完成了删除!

总结

从Switch断开控制器过程来看,触发Switch与控制器断开有两种类型:Switch主动断开(DisconnectEvent)、控制器主动断开(SwitchIdleEvent)。而断开有可能是真正网络连通性问题或者Switch挂了,导致控制器没有收到Switch回复心跳包,从而触发控制器主动断开连接。也有可能网络正常然而Switch数量太多控制器性能不足,导致控制器无法回复心跳,底层Switch主动断开连接!

Switch下线过程关键是理解DisconnectEvent和SwitchIdleEvent,而后续过程更多是回收消耗资源。同时,在这个过程中我们看到了Singleton service和EOS的身影,这两个是ODL提供集群的核心,除了在OFP使用之外,很多ODL南向插件都也是使用两者来构建集群应用!我们下回分解。


  • 本站原创文章仅代表作者观点,不代表SDNLAB立场。所有原创内容版权均属SDNLAB,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用,转载须注明来自 SDNLAB并附上本文链接。 本站中所有编译类文章仅用于学习和交流目的,编译工作遵照 CC 协议,如果有侵犯到您权益的地方,请及时联系我们。
  • 本文链接https://www.sdnlab.com/22484.html
分享到:
相关文章
条评论

登录后才可以评论

陈卓文 发表于18-10-12
1