ODL netconf挂载点操作设备
来源:互联网 发布:centos 开启snmp 编辑:程序博客网 时间:2024/05/25 16:40
学习Netconf协议中,在与设备交互中,存在挂载点概念,操作该挂载点即操作设备。下面分析下这里的实现机制:
为实现设备挂载,首先需要启动一个设备,使用ODL提供的设备模拟器
java -jar netconf-testtool-1.0.5-2.00.10R1B05-executable.jar
如果启动正确,则最后打印:
All simulated devices started successfully from port 17830 to 17830
启动ODL控制,安装feature
feature:install oscp-netconf-mdsal oscp-netconf-connector-all oscp-restconf-all oscp-netconf-topology
由于碳版本才有CallHome功能,所以这里需要通过控制器配置设备的相关信息,包括ip、port、userName、password等
http://X.X.X.X:8080/restconf/config/network-topology:network-topology/topology/topology-netconf/node/teste
<node xmlns="urn:TBD:params:xml:ns:yang:network-topology"> <node-id>teste</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> <reconnect-on-changed-schema xmlns="urn:opendaylight:netconf-node-topology">true</reconnect-on-changed-schema> </node>
通过PUT请求,往Config库中topology-netconf中写入teste节点
一旦写入完成后,后序一系统动作则开始执行(通过数据库变更通知触发),包括连接设备及交互、创建挂载点、写Operational库。
NetconfTopologyImpl对应topology-netconf路径数据库监听器触发,开始执行设备连接
@Override public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Node>> collection) { for (DataTreeModification<Node> change : collection) { final DataObjectModification<Node> rootNode = change.getRootNode(); LOG.info("SQ BUG LOCATION4: size:{},node modification type:{},id{}",collection.size(),rootNode.getModificationType(),getNodeId(rootNode.getIdentifier())); switch (rootNode.getModificationType()) { case SUBTREE_MODIFIED: LOG.info("Config for node {} updated", getNodeId(rootNode.getIdentifier())); disconnectNode(getNodeId(rootNode.getIdentifier())); connectNode(getNodeId(rootNode.getIdentifier()), rootNode.getDataAfter()); break; case WRITE: LOG.info("Config for node {} created", getNodeId(rootNode.getIdentifier())); if (activeConnectors.containsKey(getNodeId(rootNode.getIdentifier()))) { LOG.warn("RemoteDevice{{}} was already configured, reconfiguring..", getNodeId(rootNode.getIdentifier())); disconnectNode(getNodeId(rootNode.getIdentifier())); } connectNode(getNodeId(rootNode.getIdentifier()), rootNode.getDataAfter()); break; case DELETE: LOG.info("Config for node {} deleted", getNodeId(rootNode.getIdentifier())); disconnectNode(getNodeId(rootNode.getIdentifier())); break; } } }
真正连接在AbstractNetconfTopology.java steupConnection中
final ListenableFuture<NetconfDeviceCapabilities> future = deviceCommunicator.initializeRemoteConnection(clientDispatcher, clientConfig);
其中clientConfi配置,则包含上面写入Config库的节点信息
方法最终来到NetconfClientDispatcherImpl中createSshClient,开始真正连接节点
一量连接成功,监听连接建立的监听器,则开始触发
private Future<NetconfClientSession> createSshClient(final NetconfClientConfiguration currentConfiguration) { LOG.debug("Creating SSH client with configuration: {}", currentConfiguration); return super.createClient(currentConfiguration.getAddress(), currentConfiguration.getReconnectStrategy(), new PipelineInitializer<NetconfClientSession>() { @Override public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> sessionPromise) { new SshClientChannelInitializer(currentConfiguration.getAuthHandler(), getNegotiatorFactory(currentConfiguration), currentConfiguration.getSessionListener()) .initialize(ch, sessionPromise); } }); }
这里的监听器存在于currentConfiguration中,创建于AbstractNetconfTopology的steupConnection,getClientConfig,
且由已经准备好了createDeviceCommunicator传入listener
NetconfDeviceCommunicator communicator = userCapabilities.isPresent() ? new NetconfDeviceCommunicator( remoteDeviceId, device, new UserPreferences(userCapabilities.get(), node.getYangModuleCapabilities().isOverride())): new NetconfDeviceCommunicator(remoteDeviceId, device);
NetconfDeviceCommunicator继承了SessionListener,其中onSessionUp在连接成功后回调触发 ,同理onSessionDown则在设备下线时,进行设备下线逻辑的处理,包括置当前设备的状态为connecting以及消除设备capabilities以及去除挂载点的信息等。但设备重新上线时,是如何监听到并触发onSessinUp的呢?
进入NetconfDevice的onRemoteSessionUp,在这其中包装NetconfDeviceRpc,并进行Schema的build,成功后
调用setUpSchema,执行RecursiveSchemaSetup,进行其run方法中
之后 进入handleSalInitializationSuccess
protected void handleSalInitializationSuccess(final SchemaContext result, final NetconfSessionPreferences remoteSessionCapabilities, final DOMRpcService deviceRpc) { NetconfMessageTransformer.BaseSchema baseSchema = remoteSessionCapabilities.isNotificationsSupported() ? NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS : NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX; messageTransformer = new NetconfMessageTransformer(result, true, baseSchema); updateTransformer(messageTransformer); // salFacade.onDeviceConnected has to be called before the notification handler is initialized salFacade.onDeviceConnected(result, remoteSessionCapabilities, deviceRpc); notificationHandler.onRemoteSchemaUp(messageTransformer); LOG.info("{}: Netconf connector initialized successfully", id); }
salFacade.onDeviceConnected,并在之后创建的mountpoint中保存NetconfDeviceSalFacade onDeviceConnected
在该方法内部,则进行了moutpoint的创建与设置
在请求到达时,再根据id取对应的mountponit,然后就能找到那个session进行发送数据了
至此所谓的mountpoint是真实设备的挂载点,实现逻辑就正确 了。如下:
在接受请求时,查看入口
@Override public NormalizedNodeContext readConfigurationData(final String identifier, final UriInfo uriInfo) { final InstanceIdentifierContext<?> iiWithData = controllerContext.toInstanceIdentifier(identifier); final DOMMountPoint mountPoint = iiWithData.getMountPoint(); NormalizedNode<?, ?> data = null; final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier(); if (mountPoint != null) { data = broker.readConfigurationData(mountPoint, normalizedII); } else { data = broker.readConfigurationData(normalizedII); } if(data == null) { final String errMsg = "Request could not be completed because the relevant data model content does not exist "; LOG.debug(errMsg + identifier); throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.DATA_MISSING); } return new NormalizedNodeContext(iiWithData, data, QueryParametersParser.parseWriterParameters(uriInfo)); }
作为对比,无MountPoint的调用为:
public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) { checkPreconditions(); return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path); }使用的是domDataBroker,而这个broker是配置子系统加载的
根据是否能查到mountPoint处理逻辑是不一样的
public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(@Nonnull final SchemaPath type, @Nullable final NormalizedNode<?, ?> input) { final NetconfMessage message = transformer.toRpcRequest(type, input); final ListenableFuture<RpcResult<NetconfMessage>> delegateFutureWithPureResult = listener.sendRequest(message, type.getLastComponent()); final ListenableFuture<DOMRpcResult> transformed = Futures.transform(delegateFutureWithPureResult, new Function<RpcResult<NetconfMessage>, DOMRpcResult>() { @Override public DOMRpcResult apply(final RpcResult<NetconfMessage> input) { if (input.isSuccessful()) { return transformer.toRpcResult(input.getResult(), type); } else { // TODO check whether the listener sets errors properly return new DefaultDOMRpcResult(input.getErrors()); } } }); return Futures.makeChecked(transformed, new Function<Exception, DOMRpcException>() { @Nullable @Override public DOMRpcException apply(@Nullable final Exception e) { // FIXME what other possible exceptions are there ? return new DOMRpcImplementationNotAvailableException(e, "Unable to invoke rpc %s", type); } }); }
最终的RPC调用,会使用其listener进行远程节点(设备)报文发送。实现设备的直接控制。- ODL netconf挂载点操作设备
- Netopeer代替netconf真实交换机设备
- netconf学习
- 开源netconf
- ODL参考手册
- NetConf协议说明
- NETCONF模块设计介绍
- netconf vs openflow
- NETCONF协议详解
- ODL融合OpenStack
- ODL编译问题记录
- odl开发toaster
- ONOS 以及 ODL
- ODL AAA认证加密
- NETCONF--从NETCONF/YANG看网络配置自动化
- NETCONF模块设计(简)
- 网络配置协议NetConf概述
- 字符设备驱动--- 设备操作
- Android Application的生命周期
- 安卓学习第三天
- 一个完整Android项目所需要用到的gradle配置技巧
- 【数据格式】-XML
- QT控件大全 三十九 QVCursorQCircularBar
- ODL netconf挂载点操作设备
- spring中@ResponseBody的使用
- mongoose踩坑记
- 如何将Eclipse中Web项目打成war包
- FPGA串口发送代码分享
- JAVA多线程编程实战视频-第三阶段(共80节)
- JS中给数组对象排序
- Spring Cloud 之 基础学习资料
- 如何用AndroidStudio编译jar并用cmd执行