SDN学习之Opendaylight浅析(五)

    这一节主要讲下odl的netconf应用,其实odl比较多的是利用openflow对交换机下流表,实现真正的控制与转发的分离,然而有时候并不能如愿。很多实际真正使用的交换机不能实现真正的控制分离,如果能那么设备商会少很多利润,所以一个折衷对交换机的控制方案就是利用netconf对交换机进行控制,netconf可以看作一个通信协议,交换机一般在830端口起一个服务器,接受客户端的请求调用,通信数据是xml格式的,客户端可以是python脚本,如果要利用odl,就相当于将odl的南向plugin作为客户端,与交换机进行通信。

    首先介绍一下netconf,netconf是一种基于XML的网络配置管理协议 。用户可以使用这套机制增加、修改、删除网络设备的配置,获取网络设备的配置和状态信息。NETCONF面向连接,以远程过程调用的方式实现操作和控制。采用XML作为配置数据和协议消息内容的编码方式;扩展性好,厂商可以定义自己的协议操作,以实现独特功能,netconf在最底层是建立ssh连接,在最上层是利用数据交互来获取配置,或者修改机器配置,或者完成nofication通知等操作。

         netconf使用简单的基于RPC(Remote Procedure Call)机制实现客户端和服务器之间通信。客户端可以是脚本或者网管上运行的一个应用程序。服务器是一个典型的网络设备。NETCONF提供了一种通过运行网络管理软件的中心计算机(即网络管理工作站)来远程管理和监控设备的方法。

       NETCONF协议将数据区分为配置数据和状态数据,并分别提供不同的操作进行数据的增删改查。 配置数据(configuration data)是对网络设备进行配置的数据,例如创建VLAN的数据。配置数据一般是可读写的。 状态数据(state data)是反映设备状态的数据,例如端口的up/down状态,报文统计等。状态数据一般是只读的。会存在多个数据库,例如用于正在运行的,或者启动时加载的。

             客户端与服务器调用rpc的时候存在一个交互过程,首先需要发hello message,确认能力

        netconf调用操作层仅承载在仅<rpc>和<rpc-reply>消息上,<hello>和<notification>消息无操作层。 NETCONF协议规定了9种简单的rpc操作,同时也支持用户自定义rpc操作。有关自定义操作的内容放到内容层来讲。 开放但规范的内容层是netconf协议的精髓所在。其开放体现在netconf协议本身没有对内容层的数据结构做任何的限定。而其规范则体现在其内容层需要使用Yang语言对其数据进行建模。内容层未指定具体的模型结构,而是指定了一套建模语言–yang。也就是说使用yang定义的数据模型,均可以作为netconf的内容层。所以扩展对netconf来说就是不断的增加和修改yang文件而已。在上面将操作的时候提到netcon支持用户自定义操作。也就是说我们不必纠结标准制定的9个操作类型是否够用,完全可以根据实际的需求在yang文件中定义相应的rpc操作。

        再说说odl里面的netconf应用开发,第一步就是获取交换机的yang文件,yang文件就等同于交换机内的树形数据,在odl里面是在挂载节点下面的datastore里面保存,如图交换机vlan的yang模型

 container vlan {
    description
      "VLAN management.";
    container vlans {
      description
        "VLAN list.";
      list vlan {
        key "vlanId";
        max-elements  "4094";
        description
          "VLAN information.";
        leaf vlanId {
          type vlanId {
            range "1..4094";
          }
          description
            "VLAN ID.";
        }
        leaf vlanName {
          type string {
            length "1..31";
          }
          must "not(../vlanType='carrier' or ../vlanType='fcoe')";
          description
            "VLAN name.";
          ext:allowDelete "true";
        }
        leaf vlanDesc {
          type string {
            length "1..80";
          }
          must "not(../vlanType='carrier' or ../vlanType='fcoe')";
          description
            "VLAN description.";
          ext:allowDelete "true";
        }
        leaf vlanType {
          type vlanType;
          must "((../vlanType='common' or ../vlanType='super' or ../vlanType='principal') ) or (../vlanType='common' and (../vlanType='common' or ../vlanType='super' or ../vlanType='principal') ) or (../vlanType='group' and (../vlanType='common' or ../vlanType='group') ) or (../vlanType='principal' and (../vlanType='common' or ../vlanType='principal') ) or (../vlanType='seperate' and (../vlanType='common' or ../vlanType='seperate') ) or (../vlanType='sub' and (../vlanType='common' or ../vlanType='sub') ) or (../vlanType='super' and (../vlanType='common' or ../vlanType='super') ) or not(../vlanType!='common' and ../vlanType!='super' and ../vlanType!='sub' and ../vlanType!='principal' and ../vlanType!='group' and ../vlanType!='seperate' or ../vlanType='common' or ../vlanType='group' or ../vlanType='principal' or ../vlanType='seperate' or ../vlanType='sub' or ../vlanType='super')";
          default "common";
          description
            "VLAN type, such as common VLANs, super VLANs, and sub-VLANs. ";
        }

          利用yang文件通过yangtools生成数据节点的java文件,由此构造设备节点下的datasore数据,首先就是在连接设备情况下,拿到mountPoint:

 final Optional<MountPoint> deviceNodeOptional=mountService.getMountPoint(NetconfIidFactory.netconfNodeIid(deviceId));

        deviceId是connect device设置的device id,然后利用mountPoint 拿到datastore:

Preconditions.checkArgument(deviceNodeOptional.isPresent(),
                "Unable to locate mountpoint: %s, not mounted yet or not configured", deviceId);
        final MountPoint deviceNode = deviceNodeOptional.get();

        // Get the DataBroker for the mounted node
        final DataBroker deviceNodeBroker = deviceNode.getService(DataBroker.class).get();

         接下来就是操作datastore里面的数据,例如要获取交换机中所有vlan的配置,就是读datastore节点中的数据

 final ReadOnlyTransaction deviceNodeReadTx = deviceNodeBroker.newReadOnlyTransaction();
        InstanceIdentifier<Vlans> idn = InstanceIdentifier.create(
                org.opendaylight.yang.gen.v1.http.www.huawei.com.netconf.vrp.huawei.vlan.rev181123.Vlan.class)
               .child(Vlans.class);
        Optional<Vlans> ldn;
        try {
            ldn=deviceNodeReadTx.read(LogicalDatastoreType.OPERATIONAL,idn).checkedGet();
        } catch (ReadFailedException e) {
            throw new IllegalStateException("Unexpected error reading data from " + deviceId, e);
        }

      反之,配置vlan数据是利用写datastore来实现的:

 final WriteTransaction deviceNodeWriteTx = deviceNodeBroker.newWriteOnlyTransaction();
        try {
            deviceNodeWriteTx.put(LogicalDatastoreType.CONFIGURATION, idn, data);
            FluentFuture<? extends @NonNull CommitInfo> future = deviceNodeWriteTx.commit();
            future.get(5000, TimeUnit.MILLISECONDS);
        }catch (TimeoutException e){
            return RpcResultBuilder.<ConfigVlanOutput>failed()
                    .withResult(new ConfigVlanOutputBuilder().setResult(e.getMessage())).buildFuture();

        } catch (Exception e) {
            return RpcResultBuilder.<ConfigVlanOutput>failed()
                    .withResult(new ConfigVlanOutputBuilder().setResult(e.getMessage())).buildFuture();
        }

        至于odl内部的实现原理,可以理解为内部设置了datastore的监听器,当数据变化时,发起对mount node的netconf通信,还有对odl netconf的解读可以参考如下:

ODL Netconf MountPoint及其集群模式实现

https://www.sdnlab.com/22981.html

 

ODL Netconf底层连接机制实现

https://www.sdnlab.com/22997.html

 

使用Docker容器构建ODL集群

https://www.sdnlab.com/22554.html

 

ODL Netconf底层连接机制实现

https://www.sdnlab.com/22997.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章