欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SDN学习之Opendaylight浅析(五)

程序员文章站 2022-07-06 18:07:01
...

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

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

SDN学习之Opendaylight浅析(五)

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

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

SDN学习之Opendaylight浅析(五)

             客户端与服务器调用rpc的时候存在一个交互过程,首先需要发hello message,确认能力SDN学习之Opendaylight浅析(五)

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

SDN学习之Opendaylight浅析(五)

        再说说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

相关标签: SDN