ODL之Netconf重连

2024-02-19 18:58
文章标签 重连 netconf odl

本文主要是介绍ODL之Netconf重连,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ODL中Netconf支持设备异常下线后定时重连。其相关功能介绍如下:

在节点添加成功后,会创建该设备的Communicator,负责控制器与该设备节点的连接沟通处理逻辑。


AbstractNetconfTopology.java

protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId,final NetconfNode node) {//setup default values since default value is not supported yet in mdsal// TODO remove this when mdsal starts supporting default values 节点配置参数获取final Long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null ? DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis();final Long keepaliveDelay = node.getKeepaliveDelay() == null ? DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay();//保活心跳间隔 120sfinal Boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null ? DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();IpAddress ipAddress = node.getHost().getIpAddress();InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null ?ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),node.getPort().getValue());RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);RemoteDeviceHandler<NetconfSessionPreferences> salFacade =createSalFacade(remoteDeviceId, node, domBroker, bindingAwareBroker);//这里根据传入节点的keepaliveDelay配置,在设置为0时,会使用NetconfDevicesSalFacade,即无保活心跳机制if (keepaliveDelay > 0) {LOG.warn("Adding keepalive facade, for device {}", nodeId);salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(), keepaliveDelay, defaultRequestTimeoutMillis);}final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);final NetconfDevice device = new NetconfDevice(schemaResourcesDTO, remoteDeviceId, salFacade,processingExecutor.getExecutor(), reconnectOnChangedSchema);final Optional<NetconfSessionPreferences> userCapabilities = getUserCapabilities(node);NetconfDeviceCommunicator communicator = userCapabilities.isPresent() ?new NetconfDeviceCommunicator(remoteDeviceId, device, new UserPreferences(userCapabilities.get(), node.getYangModuleCapabilities().isOverride())):new NetconfDeviceCommunicator(remoteDeviceId, device);final NetconfConnectorDTO netconfConnectorDTO = new NetconfConnectorDTO(communicator, salFacade);salFacade.setListener(communicator);setCommunicator(nodeId, netconfConnectorDTO.getCommunicator());return netconfConnectorDTO;}
            leaf connection-timeout-millis {description "Specifies timeout in milliseconds after which connection must be established.";type uint32;default 20000;}leaf default-request-timeout-millis {description "Timeout for blocking operations within transactions.";type uint32;default 60000;}leaf max-connection-attempts {description "Maximum number of connection retries. Non positive value or null is interpreted as infinity.";type uint32;default 0; // retry forever}leaf between-attempts-timeout-millis {description "Initial timeout in milliseconds to wait between connection attempts. Will be multiplied by sleep-factor with every additional attempt";type uint16;default 2000;}leaf sleep-factor {type decimal64 {fraction-digits 1;}default 1.5;}

在session创建成功后,AbstractSessionNegotiator中channelActive,执行startNegotiation,发送Hello报文,NetconfClientSessionNegotiator handleMessage中处理设备返回Hello报文

getSessionForHelloMessage中将session状态修改为ESTABLISHED

connection-timeout-millis:是指发起negotiation时,session从OPEN_WAIT变为ESTABLISHED状态的超时时间,当时间到,并且promise没有完成且没有取消,则协商失败,关闭channel

default-request-timeout-millis:在KeepaliveSalFacade类中KeepaliveDOMRpcService的invokeRpc,在RPC调用超时后,取消

maxConnectionAttempts, betweenAttemptsTimeoutMillis, sleepFactor:用于重连逻辑中重连时机的计算


保活心跳机制:

顾名思义是建立在节点已经连接上的基础上(如当session状态ideal),KeepaliveSalFacade.java

sessionCreated(IoSession session) 当有新的连接建立的时候,该方法被调用。
sessionOpened(IoSession session) 当有新的连接打开的时候,该方法被调用。该方法在 sessionCreated之后被调用。
sessionClosed(IoSession session) 当连接被关闭的时候,此方法被调用。
sessionIdle(IoSession session, IdleStatus status) 当连接变成闲置状态的时候,此方法被调用。
exceptionCaught(IoSession session, Throwable cause)当 I/O 处理器的实现,此方法被调用。


说明:

sessionCreated 和 sessionOpened 的区别。sessionCreated方法是由 I/O 处理线程来调用的,而 sessionOpened是由其它线程来调用的。

因此从性能方面考虑,不要在 sessionCreated 方法中执行过多的操作。

对于sessionIdle,默认情况下,闲置时间设置是禁用的,也就是说sessionIdle 并不会被调用。可以通过 IoSessionConfig.setIdleTime(IdleStatus, int) 来进行设置。

KeepaliveSalFacade.java

    @Overridepublic void onDeviceConnected(final SchemaContext remoteSchemaContext, final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {this.currentDeviceRpc = deviceRpc;final DOMRpcService deviceRpc1 = new KeepaliveDOMRpcService(deviceRpc, resetKeepaliveTask, defaultRequestTimeoutMillis, executor);salFacade.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc1);LOG.debug("{}: Netconf session initiated, starting keepalives", id);scheduleKeepalive();}

连接成功后,调用scheduleKeepalive启动保活心跳机制


    private void scheduleKeepalive() {Preconditions.checkState(currentDeviceRpc != null);LOG.trace("{}: Scheduling next keepalive in {} {}", id, keepaliveDelaySeconds, TimeUnit.SECONDS);currentKeepalive = executor.schedule(new Keepalive(currentKeepalive), keepaliveDelaySeconds, TimeUnit.SECONDS);}

KeepaliveSalFacade.java中Keepalive实现了Runnable和FutureCallBack,其调用了rpc(get-config),其回调函数中,除成功返回响应外,都触发重连。

        @Overridepublic void onSuccess(final DOMRpcResult result) {if (result != null && result.getResult() != null) {LOG.debug("{}: Keepalive RPC successful with response: {}", id, result.getResult());scheduleKeepalive();} else {LOG.warn("{} Keepalive RPC returned null with response: {}. Reconnecting netconf session", id, result);reconnect();}}@Overridepublic void onFailure(@Nonnull final Throwable t) {LOG.warn("{}: Keepalive RPC failed. Reconnecting netconf session.", id, t);reconnect();}

考虑到除了getConfig请求,业务的其它RPC也能返回节点的数据,亦能证明节点Session存在,所以KeepaliveDOMRpcService的invokeRpc调用回调成功函数中会重置keepalive定时器。借助业务的RPC降低keepalive的心跳压力。
<node xmlns="urn:TBD:params:xml:ns:yang:network-topology"><node-id>testa</node-id><host xmlns="urn:opendaylight:netconf-node-topology">10.42.94.233</host><port xmlns="urn:opendaylight:netconf-node-topology">17830</port><username xmlns="urn:opendaylight:netconf-node-topology">admin</username><password xmlns="urn:opendaylight:netconf-node-topology">admin</password><tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only><keepalive-delay xmlns="urn:opendaylight:netconf-node-topology">0</keepalive-delay><sleep-factor xmlns="urn:opendaylight:netconf-node-topology">1</sleep-factor><reconnect-on-changed-schema xmlns="urn:opendaylight:netconf-node-topology">true</reconnect-on-changed-schema></node>
可以通过节点参数配置,可以参考YANG文件netconf-node-topology.yang
 
断链重连:
断链,则之前已经创建链接,Netconf要创建链接,首先进行了设备节点的添加(写config库)
ProtocolSessionPromise.java
synchronized void connect() {final Object lock = this;try {final int timeout = this.strategy.getConnectTimeout();LOG.debug("Promise {} attempting connect for {}ms", lock, timeout);if(this.address.isUnresolved()) {this.address = new InetSocketAddress(this.address.getHostName(), this.address.getPort());}this.b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout);final ChannelFuture connectFuture = this.b.connect(this.address);// Add listener that attempts reconnect by invoking this method again.connectFuture.addListener(new BootstrapConnectListener(lock));this.pending = connectFuture;} catch (final Exception e) {LOG.info("Failed to connect to {}", address, e);setFailure(e);}}
timeout默认为2秒,即示2秒连接不上(其后退避策略计算),则超时(信号灯超时时间)
BootstrapConnectListener.java这个监听器的关键是在于连接不成功的逻辑(重连)
 
   LOG.debug("Attempt to connect to {} failed", ProtocolSessionPromise.this.address, cf.cause());final Future<Void> rf = ProtocolSessionPromise.this.strategy.scheduleReconnect(cf.cause());rf.addListener(new ReconnectingStrategyListener());ProtocolSessionPromise.this.pending = rf;

超时连接不成功,则开始重连逻辑,使用的策略为TimedReconnectStrategy.java

        leaf between-attempts-timeout-millis {description "Initial timeout in milliseconds to wait between connection attempts. Will be multiplied by sleep-factor with every additional attempt";config true;type uint16;default 2000;}

这里的重连等待时间采用的是退避算法(借助sleep-factor)

ReconnectingStrategyListener则比较简单,在重连时间计算feature到达后,连接即可。
connect的流程又回到了起始地方,形成一个循环。


当连接断开后,又是如何进行重连的。


在设备掉线后,一系列的channelInactive会触发,进入ClosedChannelHandler.channelInactive从而会触发ReconnectPromise的connect

@Override
public void channelInactive(final ChannelHandlerContext ctx) throws Exception {// This is the ultimate channel inactive handler, not forwardingif (promise.isCancelled()) {return;}if (promise.isInitialConnectFinished() == false) {LOG.debug("Connection to {} was dropped during negotiation, reattempting", promise.address);}LOG.debug("Reconnecting after connection to {} was dropped", promise.address);promise.connect();
}

最后的打印,表明重连

针对于后序的Ssh连接:

在进行重连后,进入AbstractChannelHandlerContext.java

 
    private void invokeConnect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {if (isAdded()) {try {((ChannelOutboundHandler) handler()).connect(this, remoteAddress, localAddress, promise);} catch (Throwable t) {notifyOutboundHandlerException(t, promise);}} else {connect(remoteAddress, localAddress, promise);}}

其中handle()方法会依次调用返回: 

DefaultChannelPipeline.java connect

NetconfHelloMessageToXMLEncoder

EOMFramingMechanismEncoder

AsynSshHandler.java

 
 
 
 
 

这篇关于ODL之Netconf重连的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/725627

相关文章

Peewee+Postgresql+PooledPostgresqlDatabase重连机制

需求: Postgresql数据库服务重启后,需要业务代码正常读写数据库 方案: 通过继承playhouse.shortcuts.ReconnectMixin和playhouse.pool.PooledPostgresqlDatabase来创建一个新的ReconnectPooledPostgresqlDatabase类修改reconnect_errors属性来适配Postgresql

简单实现能够断线重连的TCP客户端

代码  主要是借助了状态机来实现断线重连 client.hpp #include <iostream>#include <string>#include <cstring>#include <cstdlib>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h

面试官问:服务的心跳机制与断线重连,Netty底层是怎么实现的?懵了

点击上方“朱小厮的博客”,选择“设为星标” 后台回复"书",获取 后台回复“k8s”,可领取k8s资料 心跳机制 何为心跳 所谓心跳, 即在 TCP 长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性. 注:心跳包还有另一个作用,经常被忽略,即:一个连接如果长时间不用,防火墙或者路由器就会断开该连接。 如何实现 核心Handler

Android客户端TCP传输数据、重连、心跳检测

1.Tcp连接、发送数据、接收数据工具类 public class TcpUtil {public static final int PORT = 9000;public static final String HOST = "192.168.2.127";public static Socket socket;private static TcpUtil utils = null;public

WebSocket封装成工具类,实现心跳监测、断开重连

1. 工具类代码 import { Message } from 'element-ui';export class WebSocketManager {constructor(url, reconnectInterval = 5000, onMessageCallback) {this.url = url;this.reconnectInterval = reconnectInterval;

使用netty进行客户端网络编程及断线重连功能实现

不管做哪个方向开发,都会有那么一两个牛B闪闪的库,可以极大的方便开发,比如java网络编程中的netty库。无论客户端还是服务端网络编程,netty基本都是首选网络库,健壮、高效、稳定,并且已经得到很多商业项目验证。        当用netty进行客户端网络编程时,与服务端建立连接并完成数据编码、解码、通信是最基础功能,考虑程序的健壮性,则断线重连是必不可少的一个功能点。n

Flash和Arduino进行交互时不断重连

Flash和Arduino进行交互时不断重连 解决办法:在Flash的mc后面加一句gotoAndPlay(2); 即播放结束循环时不能返回到第一帧进行播放

车载通信框架--- 以太网重连Port口相关思考

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节能减排。 无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事.而不是让内心的烦躁、焦虑、毁掉你本就不多的热情和定力。

简易的 Websocket + 心跳机制 + 尝试重连

文章目录 演示大纲基础 WebSocket前端: 添加心跳机制前端: 尝试重新连接历史代码 还没有写完,bug 是有的,我在想解决办法了… 演示 大纲 基础的 webSocket 连接前后端:添加心跳机制后端无心跳反应,前端尝试重新连接设置重新连接次数,超过最大尝试次数之后,不再尝试重新连接 基础 WebSocket 前端的基础就是这些,大概的效果是这样的

ffmpeg解封装rtsp并录制视频-(1)解封装rtsp断网或摄像机重启后自动重连处理

头文件: xtools.h #pragma once#include <thread>#include <iostream>#include <mutex>//日志级别 DEBUG INFO ERROR FATALenum XLogLevel{XLOG_TYPE_DEBUG,XLOG_TYPE_INFO,XLOG_TPYE_ERROR,XLOG_TYPE_FATAL};#