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

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