SDN学习之Opendaylight浅析(二)

 上一篇讲了ODL的基本认识和安装,这一篇主要讲讲ODL内部的使用,ODL控制器是MD-SAL机制,MD代表服务是以模型驱动,的,这个模型简单来说就是yang模型,早在2003年,IETF成立了一个NETCONF工作组,提出一种基于XML的网络配置管理协议,也就是NETCONF(Network Configuration Protocol),因为该协议的配置功能非常强大,同时兼顾监控和故障管理,安全验证和访问控制,所以得到业界的一致认可,所以广泛采用netconfig来配置网络。NETCONF协议分为传输层、RPC层、操作层和内容层。其中,内容层是唯一没有标准化的层,于是一种新的建模语言YANG产生了,它的目标是对NETCONF数据模型、操作进行建模,覆盖NETCONF协议的操作层和内容层,yang模型据我的理解可以看作是定义一个数据对象的,对象中包含各种结构的属性,这一部分篇幅所限,我不对yang模型进行讲解,以后可以专门写一个文章进行讲解。

  要学习ODL的MD-SAL,有三个方面的内容需要掌握:

1.RPC

2.notification

3.datastore

其实这三点都与yang模型有一定的联系,下面结合代码进行分析和讲解。

1.RPC

RPC代表一个输入输出的函数调用过程,是有一个请求和返回的消息对,RPC首先要在yang文件中定义,例如:

 rpc connect-device {
        input {
            leaf device-id {
                description "the ip to execute mtr";
                type string;
            }
            leaf device-ip {
                description "the url of dst";
                type string;
            }
            leaf username {
                description "the url of dst";
                type string;
            }
            leaf password {
                description "the url of dst";
                type string;
            }
            leaf device-port {
                description "the uuid of device";
                type string;
            }
            leaf connection-type {
                description "Type of connection, true for tcp only";
                type string;
                default "false";
            }
            leaf protocol {
                description "the uuid of device";
                type string;
                default "ssh";
            }
            leaf schemaless {
                description "the uuid of device";
                type string;
                default "false";
            }
            leaf excluded-tls-versions {
                description "the uuid of device";
                type string;
                default "";
            }
            
        }

        output {
             leaf result {
                 description "total result";
                 type string;
            }
        }
    }

     列如上面就定义了一个连接设备的RPC调用,这个yang模型会在编译之后会生成binding接口,可以供我们提供实现。

对每个RPC Method解析Input入参,实现RPC Method的业务逻辑,构造RPC Output,封装成future返回。我们可以自己书写代码实现接口

@Override
	public ListenableFuture<RpcResult<ConnectDeviceOutput>> connectDevice(ConnectDeviceInput input) {
		// TODO Auto-generated method stub

		String deviceIp = input.getDeviceIp();
		String devicePort = input.getDevicePort();
		String connectionType = input.getConnectionType();
		String schemaless = input.getSchemaless();
		String protocol = input.getProtocol();
		String username = input.getUsername();
		String password = input.getPassword();
		String excludedTlsVersions = input.getExcludedTlsVersions();
		String deviceId = input.getDeviceId();

		if (!NetconfCommandUtils.isIpValid(deviceIp) || !NetconfCommandUtils.isPortValid(devicePort)) {
			return RpcResultBuilder.<ConnectDeviceOutput>failed().withResult(new ConnectDeviceOutputBuilder().setResult(
					"\"Invalid IP:\" + deviceIp + \" or Port:\" + devicePort + \"Please enter a valid entry to proceed.\""))
					.buildFuture();
		}

		final boolean isTcpOnly = connectionType.equals("true");
		final boolean isSchemaless = schemaless.equals("true");

		final NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder();
		netconfNodeBuilder.setHost(new Host(new IpAddress(new Ipv4Address(deviceIp))))
				.setPort(new PortNumber(Integer.decode(devicePort))).setTcpOnly(isTcpOnly).setSchemaless(isSchemaless);

		if (isTcpOnly || protocol.equalsIgnoreCase("ssh")) {
			if (Strings.isNullOrEmpty(username) || Strings.isNullOrEmpty(password)) {
				return RpcResultBuilder.<ConnectDeviceOutput>failed()
						.withResult(new ConnectDeviceOutputBuilder()
								.setResult("Empty Username:" + username + " or Password:" + password
										+ ". In TCP or SSH mode, you must provide valid username and password."))
						.buildFuture();

			}
			final Credentials credentials = new LoginPasswordBuilder().setPassword(password).setUsername(username)
					.build();
			netconfNodeBuilder.setCredentials(credentials);
			if (!isTcpOnly) {
				netconfNodeBuilder.setProtocol(new ProtocolBuilder().setName(Name.SSH).build());
			}
		} else if (protocol.equalsIgnoreCase("tls")) {
			TlsCase tlsCase = null;
			if (!Strings.isNullOrEmpty(excludedTlsVersions)) {
				tlsCase = new TlsCaseBuilder().setTls(
						new TlsBuilder().setExcludedVersions(Arrays.asList(excludedTlsVersions.split(","))).build())
						.build();
			}
			netconfNodeBuilder.setProtocol(new ProtocolBuilder().setName(Name.TLS).setSpecification(tlsCase).build());
		} else {
			return RpcResultBuilder.<ConnectDeviceOutput>failed()
					.withResult(new ConnectDeviceOutputBuilder()
							.setResult("Invalid protocol: " + protocol + ". Only SSH and TLS are supported."))
					.buildFuture();
		}

		try {
			FluentFuture<? extends @NonNull CommitInfo> future = service.connectDeviceSync(netconfNodeBuilder.build(),
					deviceId);
			future.get(DELAYTIME, TimeUnit.MILLISECONDS);
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			return RpcResultBuilder.<ConnectDeviceOutput>failed()
					.withResult(new ConnectDeviceOutputBuilder().setResult(e.getMessage())).buildFuture();
		} catch (Exception e) {
			return RpcResultBuilder.<ConnectDeviceOutput>failed()
					.withResult(new ConnectDeviceOutputBuilder().setResult(e.getMessage())).buildFuture();
		}

		final String message = "Netconf connector added succesfully";
		return RpcResultBuilder.success(new ConnectDeviceOutputBuilder().setResult(message)).buildFuture();

	}

      同时在blueprint上注册RPC实现。

  <bean id="devicemanagementImpl"
    class="com.ctg.netcontrol.impl.DevicemanagementImpl">
    <argument ref="commanders" />
    <argument ref="mountPointService" />
    <argument ref="dataBroker" />
  </bean>
<odl:rpc-implementation ref="devicemanagementImpl" />

  这样就可以提供RPC服务,假如要调用RPC服务,也可以在blueprint里面上注册RPC调用。

<odl:rpc-service id="virtdevmanagerService" interface="org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.virtdevmanager.rev190225.VirtdevmanagerService"/>

  RPC调用还有一定的讲究,例如采用同步,异步调用,这个以后有时间再分析。

2.Notifications

      notifications是ODL另一种信息传递形式,采用发布和订阅的方式,其实还有另一种对datachange的订阅监听,这种使用到data broker传递给订阅者。

    首先依然是yang模型的定义,例如:

同样经过编译后会生成接口,主要是一个listener接口和notification的builder接口,用于监听和构建notification:

例如,作为发布者的时候,需要构建出notification,利用notificationpublishservice的publish方法发布出去

publishservice具有两个方法,putNotification:将消息投递到队列后才返回。表明消息已经投递成功了。这个是同步的方式。如果消息队列满了,则会一直阻塞直到消息队列有空闲将消息投递后才返回。

offerNotification:立即返回。后台线程负责将消息投递到消息队列。投递成功则返回设置成功。如果消息队列满,则会一直阻塞,直到投递成功为止。这个方法会立即返回ListenableFuture,可以通过callBack方式检测其是否成功还是失败。

offerNotifiation(xxx,int var2,…):这个方法也是立即返回。不同于第二个的是,如果消息队列满,不会一直阻塞,在超时时间到达后如果还没投递消息,则设置失败。

而假如作为订阅者,则需要在blueprint里面注册listener:

然后在listener里面实现监听到通知后的处理逻辑:

订阅者在处理消息时,如果处理消息时间过长,尽量开辟一个新的线程来处理消息。否则会卡住消息的发布者,因为消息发布者是将消息投递到一个消息队列的。如果处理消息时间长,消息队列容易满,进而造成消息发布者阻塞住。

消息投递也是有顺序的。不会因为前一个消息没投递出去,后面的消息投递出去了。而datastore的datachange notify则是没有顺序的。它会并发地发出多个消息,无任何顺序。

 

3.DataStore

      datastore是一个树状结构保存在内存中的数据,可以看作ODL的数据库,计算变化集并且维护commit handlers,notification listeners和实际数据之间的关系。要获取服务的话首先需要在blueprint里面定义。

 <reference id="dataBroker"
    interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"
    odl:type="default" />

   datastore是以事务进行操作,因为其本身就相当于数据库,所以进行事务操作很好理解,简要说明一下。事务(transaction)在资料里面说是整体数据树的一致性快照,相当于将要应用于数据树的一系列原子操作集,也就是这个事务同样具有原子性,

例如创建事务

                                  

事务中可以存在多个子操作,最后利用submit操作一并提交。

                                 

 

Put操作:全新的操作。如果数据不存在,则会创建。如果数据已经存在了,则会完全替换掉。

Merge操作:如果之前没有数据则会写进去。如果之前有数据,新的也有数据,则会更新。如果之前有数据,新的没有数据,则不会发生任何变化。

      LogicalDatastoreType是区分操作的数据树类型,主要分为operational和configuration两种数据树,InstanceIdentifier是用来标识数据树上面的要操作的数据,可以看作树节点,而dataobject是节点的返回数据类型,一般事务操作后可以返回Optional类型的对象,利用get()方法获取到返回数据。

                                           

  可以利用get获取dataobject,当然也能利用future来构建回调函数。

                                                                          

                                                                           

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值