SH-Renderer API code to handle OTN Step 2 16/90616/5
authorBalagangadhar Bathula <bb4341@att.com>
Wed, 19 Feb 2020 22:04:55 +0000 (17:04 -0500)
committerGilles Thouenon <gilles.thouenon@orange.com>
Fri, 26 Jun 2020 06:59:12 +0000 (08:59 +0200)
- improve ODU4 support
- Fixing connection-type issue for roadmline

JIRA: TRNSPRTPCE-194
Signed-off-by: Balagangadhar Bathula <bb4341@att.com>
Change-Id: I78afa16ed4706b1e5f74eeec5259d56e58eae181

renderer/src/main/java/org/opendaylight/transportpce/renderer/ModelMappingUtils.java
renderer/src/main/java/org/opendaylight/transportpce/renderer/openroadminterface/OpenRoadmInterface221.java
renderer/src/main/java/org/opendaylight/transportpce/renderer/openroadminterface/OpenRoadmInterfaceFactory.java
renderer/src/main/java/org/opendaylight/transportpce/renderer/openroadminterface/OpenRoadmOtnInterface221.java
renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/DeviceRendererServiceImpl.java
renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/OtnDeviceRendererServiceImpl.java
renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/RendererServiceOperationsImpl.java
tests/transportpce_tests/2.2.1/test_otn_renderer.py

index 9ad44e48f3d32c4ae4bd3f25314df118f1358afe..f2fec566b35e1b802ab26227757ddf26b931339c 100644 (file)
@@ -119,11 +119,15 @@ public final class ModelMappingUtils {
         // If atoZ is set true use A-to-Z direction otherwise use Z-to-A
         List<org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev200615.otn.renderer.input.Nodes> nodes =
             new ArrayList<>();
-        NodeLists nodeLists = getNodesListAToZ(pathDescription.getAToZDirection().getAToZ().iterator());
-        if (!asideToZside) {
+        NodeLists nodeLists = null;
+        if (asideToZside) {
+            nodeLists = getNodesListAToZ(pathDescription.getAToZDirection().getAToZ().iterator());
+        } else {
             nodeLists = getNodesListZtoA(pathDescription.getZToADirection().getZToA().iterator());
         }
-        for (Nodes node: nodeLists.getList()) {
+        LOG.info("These are node-lists {}, {}", nodeLists.getList(), nodeLists.getOlmList());
+        for (int i = 0; i < nodeLists.getList().size(); i++) {
+            Nodes node = nodeLists.getList().get(i);
             if (serviceRate.equals("100G")) {
                 nodes.add(
                     new org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev200615.otn.renderer.input
@@ -133,13 +137,25 @@ public final class ModelMappingUtils {
                         .build());
             }
             else { // For any other service rate (1G or 10G)
-                nodes.add(
-                    new org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev200615.otn.renderer.input
-                        .NodesBuilder()
-                        .setNodeId(node.getNodeId())
-                        .setClientTp(node.getSrcTp())
-                        .setNetworkTp(node.getDestTp())
-                        .build());
+                // For the last node in the list, clientTp and NetworkTp has to be reversed
+                if (i == nodeLists.getList().size() - 1) {
+                    nodes.add(
+                        new org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev200615.otn.renderer.input
+                            .NodesBuilder()
+                            .setNodeId(node.getNodeId())
+                            .setClientTp(node.getDestTp())
+                            .setNetworkTp(node.getSrcTp())
+                            .build());
+
+                } else {
+                    nodes.add(
+                        new org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev200615.otn.renderer.input
+                            .NodesBuilder()
+                            .setNodeId(node.getNodeId())
+                            .setClientTp(node.getSrcTp())
+                            .setNetworkTp(node.getDestTp())
+                            .build());
+                }
             }
         }
         OtnServicePathInputBuilder otnServicePathInputBuilder = new OtnServicePathInputBuilder()
@@ -203,7 +219,7 @@ public final class ModelMappingUtils {
                 } else if ("Link".equals(resourceType)) {
                     LOG.info("The type is link");
                 } else {
-                    LOG.info("The type is not indentified: {}", resourceType);
+                    LOG.info("The type is not identified: {}", resourceType);
                 }
             } catch (IllegalArgumentException | SecurityException e) {
                 LOG.error("Dont find the getResource method", e);
@@ -230,7 +246,7 @@ public final class ModelMappingUtils {
             try {
                 if (TERMINATION_POINT.equals(resourceType)) {
                     tp = (TerminationPoint) pathDesObj.getResource().getResource();
-                    LOG.info(" TP is {} {}", tp.getTpId(),
+                    LOG.info("TP is {} {}", tp.getTpId(),
                             tp.getTpNodeId());
                     tpID = tp.getTpId();
                     nodeID = tp.getTpNodeId();
@@ -256,11 +272,11 @@ public final class ModelMappingUtils {
                 } else if ("Link".equals(resourceType)) {
                     LOG.info("The type is link");
                 } else {
-                    LOG.info("The type is not indentified: {}", resourceType);
+                    LOG.info("The type is not identified: {}", resourceType);
                 }
             } catch (IllegalArgumentException | SecurityException e) {
                 //TODO: Auto-generated catch block
-                LOG.error("Dont find the getResource method", e);
+                LOG.error("Did not find the getResource method", e);
             }
         }
         populateNodeLists(treeMap, list, olmList);
index 5c0656cefef7f511eafb43b80e461b569512dda6..e6b7f4ad25a3b7ebf7ee6d66f8b95f2f33935a78 100644 (file)
@@ -570,4 +570,58 @@ public class OpenRoadmInterface221 {
         return oduInterfaceBldr.getName();
     }
 
+    public String createOpenRoadmOtnOdu4Interface(String anodeId, String alogicalConnPoint,
+        String asupportingOtuInterface, String znodeId, String zlogicalConnPoint)
+        throws OpenRoadmInterfaceException {
+        Mapping portMapA = portMapping.getMapping(anodeId, alogicalConnPoint);
+        if (portMapA == null) {
+            throw new OpenRoadmInterfaceException(
+                String.format("Unable to get mapping from PortMapping for node % and logical connection port %s",
+                    anodeId, alogicalConnPoint));
+        }
+        Mapping portMapZ = portMapping.getMapping(znodeId, zlogicalConnPoint);
+        if (portMapZ == null) {
+            throw new OpenRoadmInterfaceException(
+                String.format("Unable to get mapping from PortMapping for node % and logical connection port %s",
+                    znodeId, zlogicalConnPoint));
+        }
+        InterfaceBuilder oduInterfaceBldr = createGenericInterfaceBuilder(portMapA, OtnOdu.class,
+            alogicalConnPoint + "-ODU4");
+        oduInterfaceBldr.setSupportingInterface(asupportingOtuInterface);
+
+        // ODU interface specific data
+        OduBuilder oduIfBuilder = new OduBuilder()
+            .setRate(ODU4.class)
+            .setMonitoringMode(OduAttributes.MonitoringMode.Terminated)
+            .setTxSapi(portMapA.getLcpHashVal())
+            .setTxDapi(portMapZ.getLcpHashVal())
+            .setExpectedSapi(portMapZ.getLcpHashVal())
+            .setExpectedDapi(portMapA.getLcpHashVal());
+
+
+        // Set Opu attributes
+        OpuBuilder opuBldr = new OpuBuilder()
+            .setPayloadType(PayloadTypeDef.getDefaultInstance("21"))
+            .setExpPayloadType(PayloadTypeDef.getDefaultInstance("21"));
+        oduIfBuilder.setOduFunction(ODUTTP.class)
+            .setOpu(opuBldr.build());
+
+        // Create Interface1 type object required for adding as augmentation
+        // TODO look at imports of different versions of class
+        org.opendaylight.yang.gen.v1.http.org.openroadm.otn.odu.interfaces.rev181019.Interface1Builder oduIf1Builder =
+            new org.opendaylight.yang.gen.v1.http.org.openroadm.otn.odu.interfaces.rev181019.Interface1Builder();
+        oduInterfaceBldr.addAugmentation(
+            org.opendaylight.yang.gen.v1.http.org.openroadm.otn.odu.interfaces.rev181019.Interface1.class,
+            oduIf1Builder.setOdu(oduIfBuilder.build()).build());
+
+        // Post interface on the device
+        openRoadmInterfaces.postInterface(anodeId, oduInterfaceBldr);
+        try {
+            Thread.sleep(3000);
+        } catch (InterruptedException e) {
+            LOG.error("Error waiting post interface on device", e);
+        }
+        this.portMapping.updateMapping(anodeId, portMapA);
+        return oduInterfaceBldr.getName();
+    }
 }
index 9f85cc8d64c278093671175d22152b990ba84d32..50319bbad50a2de7882fdc68317234d0ddc13243 100644 (file)
@@ -325,4 +325,17 @@ public class OpenRoadmInterfaceFactory {
                 return null;
         }
     }
+
+    public String createOpenRoadmOtnOdu4Interface(String anodeId, String alogicalConnPoint,
+        String asupportingOtuInterface, String znodeId, String zlogicalConnPoint)
+        throws OpenRoadmInterfaceException {
+        switch (mappingUtils.getOpenRoadmVersion(anodeId)) {
+            case StringConstants.OPENROADM_DEVICE_VERSION_2_2_1:
+                return openRoadmInterface221
+                    .createOpenRoadmOtnOdu4Interface(anodeId, alogicalConnPoint, asupportingOtuInterface,
+                        znodeId, zlogicalConnPoint);
+            default:
+                return null;
+        }
+    }
 }
index e6ad5ada3bd4f2f37ece37ac0bb49db2ad2d67e4..49570714535854b1b7f552e544e47ee19816cf2a 100644 (file)
@@ -146,7 +146,7 @@ public class OpenRoadmOtnInterface221 {
         if (supportingInterface == null) {
             throw new OpenRoadmInterfaceException(
                     "Interface Creation failed because of missing supported "
-                    + "ODU4 on network end or Eth iface on client");
+                    + "ODU4 on network end or Ethernet on client");
         }
 
         InterfaceBuilder oduInterfaceBldr = createGenericInterfaceBuilder(
index 40a2a20ff4f0da824881deba319b706f4492b9d9..0f6c87a5beb328582806c8b7289e490b8cac87a9 100644 (file)
@@ -98,11 +98,6 @@ public class DeviceRendererServiceImpl implements DeviceRendererService {
     @Override
     public ServicePathOutput setupServicePath(ServicePathInput input, ServicePathDirection direction) {
         List<Nodes> nodes = input.getNodes();
-        Nodes srcNode = nodes.get(0);
-        // If the Node list size is one, then src and tgt are same;
-        // sapi/dapi all have the same value
-        Nodes tgtNode = nodes.get(nodes.size() - 1);
-
 
         // Register node for suppressing alarms
         if (!alarmSuppressionNodeRegistration(input)) {
@@ -115,8 +110,11 @@ public class DeviceRendererServiceImpl implements DeviceRendererService {
         ServiceListTopology topology = new ServiceListTopology();
         AtomicBoolean success = new AtomicBoolean(true);
         ForkJoinPool forkJoinPool = new ForkJoinPool();
+
         ForkJoinTask forkJoinTask = forkJoinPool.submit(() -> nodes.parallelStream().forEach(node -> {
             String nodeId = node.getNodeId();
+            // take the index of the node
+            int nodeIndex = nodes.indexOf(node);
             LOG.info("Starting provisioning for node : {}", nodeId);
             List<String> createdEthInterfaces = new ArrayList<>();
             List<String> createdOtuInterfaces = new ArrayList<>();
@@ -136,15 +134,17 @@ public class DeviceRendererServiceImpl implements DeviceRendererService {
                                 nodeId, destTp, waveNumber, ModulationFormat.DpQpsk);
                         createdOchInterfaces.add(supportingOchInterface);
                         // Here we pass logical connection-point of z-end to set SAPI and DAPI
-                        String znodeId = tgtNode.getNodeId();
-                        String zlogicalConnection = tgtNode.getDestTp();
-                        if (nodeId.equals(tgtNode.getNodeId())) {
-                            znodeId = srcNode.getNodeId(); // if it is final node, then set zSide as source side
-                            zlogicalConnection = srcNode.getDestTp();
+                        Nodes tgtNode = null;
+                        if (nodeIndex + 1 == nodes.size()) {
+                            // For the end node, tgtNode becomes the first node in the list
+                            tgtNode = nodes.get(0);
+                        } else {
+                            tgtNode = nodes.get(nodeIndex + 1);
                         }
+                        // tgtNode srcTp is null in this if cond
                         String supportingOtuInterface = this.openRoadmInterfaceFactory
                                 .createOpenRoadmOtu4Interface(nodeId, destTp, supportingOchInterface,
-                                    znodeId, zlogicalConnection);
+                                    tgtNode.getNodeId(), tgtNode.getDestTp());
                         createdOtuInterfaces.add(supportingOtuInterface);
                         if (srcTp == null) {
                             otnNodesProvisioned.add(node);
index 800f762526716b2f9fe7f37edc3c8e25477f4be5..3328dc124f69b4863e9ea16ac900b7157902b796 100644 (file)
@@ -363,11 +363,21 @@ public class OtnDeviceRendererServiceImpl implements OtnDeviceRendererService {
 
     private void createODU4TtpInterface(OtnServicePathInput input, List<NodeInterface> nodeInterfaces,
         CopyOnWriteArrayList<Nodes> otnNodesProvisioned) throws OpenRoadmInterfaceException {
-        for (Nodes node : input.getNodes()) {
+
+        for (int i = 0; i < input.getNodes().size(); i++) {
+            Nodes node = input.getNodes().get(i);
             String supportingOtuInterface = node.getNetworkTp() + "-OTU";
             List<String> createdOdu4Interfaces = new ArrayList<>();
+            // Adding SAPI/DAPI information to the
+            Nodes tgtNode = null;
+            if (i + 1 == input.getNodes().size()) {
+                // For the end node, tgtNode becomes the first node in the list
+                tgtNode = input.getNodes().get(0);
+            } else {
+                tgtNode = input.getNodes().get(i + 1);
+            }
             createdOdu4Interfaces.add(openRoadmInterfaceFactory.createOpenRoadmOtnOdu4Interface(node.getNodeId(),
-                node.getNetworkTp(), supportingOtuInterface));
+                node.getNetworkTp(), supportingOtuInterface, tgtNode.getNodeId(), tgtNode.getNetworkTp()));
             NodeInterfaceBuilder nodeInterfaceBuilder = new NodeInterfaceBuilder()
                 .withKey(new NodeInterfaceKey(node.getNodeId()))
                 .setNodeId(node.getNodeId())
index 4e38ea7546fb8eea5369c476a2f54b98bcb734ca..66bca1cf021b72677107bea3f34984b8ea65ab84 100644 (file)
@@ -134,11 +134,12 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                 // Here is the switch statement that distinguishes on the connection-type
                 LOG.info("Connection-type is {} for {}", input.getConnectionType(), input.getServiceName());
                 switch (input.getConnectionType()) {
-                    case Service: // This takes into account of Ethernet 100G, 1G, 10G and ODU4
+                    case Service: case RoadmLine: // This takes into account of Ethernet 100G, 1G, 10G and ODU4
                         LOG.info("RPC implementation for {}", input.getConnectionType());
-                        if ((input.getServiceAEnd().getServiceRate() != null) // Since service-rate could be null
-                            && (input.getServiceAEnd().getServiceRate().intValue() == 100)
-                            && (input.getServiceAEnd().getServiceFormat().getName().equals("Ethernet"))) {
+                        if (((input.getServiceAEnd().getServiceRate() != null)
+                            && (input.getServiceAEnd().getServiceRate().intValue() == 100))
+                            && ((input.getServiceAEnd().getServiceFormat().getName().equals("Ethernet"))
+                                || (input.getServiceAEnd().getServiceFormat().getName().equals("OC")))) {
                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
                                 input.getServiceAEnd().getServiceFormat(), input.getServiceAEnd().getServiceRate());
                             ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
@@ -200,8 +201,6 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                             }
                             // If Service activation is success update Network ModelMappingUtils
                             networkModelWavelengthService.useWavelengths(input.getPathDescription());
-                            sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
-                                input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
                         } else { // This implies, service-rate is 1 or 10G
                             // This includes the lower-order odu (1 G, 10 G) and
                             LOG.info("RPC implementation for LO-ODU");
@@ -234,9 +233,9 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                                     OPERATION_FAILED);
                             }
                             LOG.info("OTN rendering result size {}", otnRenderingResults.size());
-                            sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
-                                input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
                         }
+                        sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
+                            input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
                         break;
                     case Infrastructure:
                         LOG.info("RPC implementation for {}", input.getConnectionType());
@@ -304,7 +303,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                             // First create the OCH and OTU interfaces
                             String serviceRate = "100G"; // For OtnDeviceRendererServiceImpl
                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
-                                input.getServiceAEnd().getOtuServiceRate(), serviceRate);
+                                input.getServiceAEnd().getOduServiceRate(), serviceRate);
                             // Now start rendering ODU4 interface
                             String serviceFormat = "ODU"; // Since we need to create ODU4 Ttp interfaces as well
                             // This is A-Z side
index 48ca830c4149033404328ed4c5d7e76ed04c16b0..9c8abbc9bb5a42870d75477e792ab5c91c39067a 100644 (file)
@@ -146,25 +146,12 @@ class TransportPCEtesting(unittest.TestCase):
         self.assertEqual(response.status_code, requests.codes.ok)
         res = response.json()
 
-        input_dict = {'name': 'XPDR1-NETWORK1-1',
-                      'administrative-state': 'inService',
-                      'supporting-circuit-pack-name': 'CP1-CFP0',
-                      'type': 'org-openroadm-interfaces:opticalChannel',
-                      'supporting-port': 'CP1-CFP0-P1'
-                      }
-        # assertDictContainsSubset is deprecated
-        '''
-        self.assertDictContainsSubset({'name': 'XPDR1-NETWORK1-1', 'administrative-state': 'inService',
-                                       'supporting-circuit-pack-name': 'CP1-CFP0',
-                                       'type': 'org-openroadm-interfaces:opticalChannel',
-                                       'supporting-port': 'CP1-CFP0-P1'}, res['interface'][0])
-        '''
-        self.assertDictEqual(dict({'name': 'XPDR1-NETWORK1-1',
+        self.assertDictEqual(dict(res['interface'][0], **{'name': 'XPDR1-NETWORK1-1',
                                    'administrative-state': 'inService',
                                    'supporting-circuit-pack-name': 'CP1-CFP0',
                                    'type': 'org-openroadm-interfaces:opticalChannel',
                                    'supporting-port': 'CP1-CFP0-P1'
-                                   } ,**res['interface'][0]),
+                                   } ),
                              res['interface'][0])
 
         self.assertDictEqual(
@@ -197,7 +184,7 @@ class TransportPCEtesting(unittest.TestCase):
                         'fec': 'scfec'
                         }
 
-        self.assertDictEqual(dict(input_dict_1, **res['interface'][0]),
+        self.assertDictEqual(dict(res['interface'][0], **input_dict_1),
                              res['interface'][0])
 
         self.assertDictEqual(input_dict_2,
@@ -262,12 +249,16 @@ class TransportPCEtesting(unittest.TestCase):
                         'type': 'org-openroadm-interfaces:otnOdu',
                         'supporting-port': 'CP1-CFP0-P1'}
         input_dict_2 = {'odu-function': 'org-openroadm-otn-common-types:ODU-TTP',
-                        'rate': 'org-openroadm-otn-common-types:ODU4'}
+                        'rate': 'org-openroadm-otn-common-types:ODU4',
+                        'expected-dapi': 'Swfw02qXGyI=',
+                        'expected-sapi': 'Swfw02qXGyI=',
+                        'tx-dapi': 'Swfw02qXGyI=',
+                        'tx-sapi': 'Swfw02qXGyI='}
 
-        self.assertDictEqual(dict(input_dict_1, **res['interface'][0]),
+        self.assertDictEqual(dict(res['interface'][0], **input_dict_1),
                              res['interface'][0])
-        self.assertDictEqual(dict(input_dict_2,
-                                  **res['interface'][0]['org-openroadm-otn-odu-interfaces:odu']
+        self.assertDictEqual(dict(res['interface'][0]['org-openroadm-otn-odu-interfaces:odu'],
+                                  **input_dict_2
                                   ),
                                   res['interface'][0]['org-openroadm-otn-odu-interfaces:odu']
                              )
@@ -318,7 +309,7 @@ class TransportPCEtesting(unittest.TestCase):
                       'type': 'org-openroadm-interfaces:ethernetCsmacd',
                       'supporting-port': 'CP1-SFP4-P1'
                       }
-        self.assertDictEqual(dict(input_dict, **res['interface'][0]),
+        self.assertDictEqual(dict(res['interface'][0], **input_dict),
                              res['interface'][0])
         self.assertDictEqual(
             {u'speed': 10000},
@@ -345,10 +336,10 @@ class TransportPCEtesting(unittest.TestCase):
             'rate': 'org-openroadm-otn-common-types:ODU2e',
             'monitoring-mode': 'terminated'}
 
-        self.assertDictEqual(dict(input_dict_1, **res['interface'][0]),
+        self.assertDictEqual(dict(res['interface'][0], **input_dict_1),
                              res['interface'][0])
-        self.assertDictEqual(dict(input_dict_2,
-                             **res['interface'][0]['org-openroadm-otn-odu-interfaces:odu']),
+        self.assertDictEqual(dict(res['interface'][0]['org-openroadm-otn-odu-interfaces:odu'],
+                                  **input_dict_2),
                              res['interface'][0]['org-openroadm-otn-odu-interfaces:odu'])
         self.assertDictEqual(
             {u'payload-type': u'03', u'exp-payload-type': u'03'},
@@ -375,14 +366,14 @@ class TransportPCEtesting(unittest.TestCase):
 
         input_dict_3 = {'trib-port-number': 1}
 
-        self.assertDictEqual(dict(input_dict_1, **res['interface'][0]),
+        self.assertDictEqual(dict(res['interface'][0], **input_dict_1),
                              res['interface'][0])
-        self.assertDictEqual(dict(input_dict_2,
-                             **res['interface'][0]['org-openroadm-otn-odu-interfaces:odu']),
+        self.assertDictEqual(dict(res['interface'][0]['org-openroadm-otn-odu-interfaces:odu'],
+                                  **input_dict_2),
                              res['interface'][0]['org-openroadm-otn-odu-interfaces:odu'])
-        self.assertDictEqual(dict(input_dict_3,
-                                  **res['interface'][0]['org-openroadm-otn-odu-interfaces:odu'][
-                                                  'parent-odu-allocation']),
+        self.assertDictEqual(dict(res['interface'][0]['org-openroadm-otn-odu-interfaces:odu'][
+                                    'parent-odu-allocation'], **input_dict_3
+                                  ),
                              res['interface'][0]['org-openroadm-otn-odu-interfaces:odu'][
                                'parent-odu-allocation'])
         self.assertIn(1,
@@ -405,7 +396,7 @@ class TransportPCEtesting(unittest.TestCase):
             'direction': 'bidirectional'
         }
 
-        self.assertDictEqual(dict(input_dict_1, **res['odu-connection'][0]),
+        self.assertDictEqual(dict(res['odu-connection'][0], **input_dict_1),
                              res['odu-connection'][0])
         self.assertDictEqual({u'dst-if': u'XPDR1-NETWORK1-ODU2e-service1'},
                              res['odu-connection'][0]['destination'])