c6c409b77251a50c86571f059c746892ab0361a4
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / OtnDeviceRendererServiceImpl.java
1 /*
2  * Copyright © 2019 AT&T and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.transportpce.renderer.provisiondevice;
9
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.HashMap;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Optional;
17 import java.util.concurrent.ConcurrentLinkedQueue;
18 import java.util.concurrent.CopyOnWriteArrayList;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.ForkJoinPool;
21 import java.util.concurrent.ForkJoinTask;
22 import java.util.concurrent.atomic.AtomicBoolean;
23 import java.util.stream.Collectors;
24 import org.opendaylight.transportpce.common.StringConstants;
25 import org.opendaylight.transportpce.common.crossconnect.CrossConnect;
26 import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
27 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaceException;
28 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaces;
29 import org.opendaylight.transportpce.networkmodel.service.NetworkModelService;
30 import org.opendaylight.transportpce.renderer.openroadminterface.OpenRoadmInterfaceFactory;
31 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.OtnServicePathInput;
32 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.OtnServicePathOutput;
33 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.OtnServicePathOutputBuilder;
34 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev200327.OpucnTribSlotDef;
35 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTp;
36 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTpBuilder;
37 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.node.interfaces.NodeInterface;
38 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.node.interfaces.NodeInterfaceBuilder;
39 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.node.interfaces.NodeInterfaceKey;
40 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.otn.renderer.nodes.Nodes;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44
45 public class OtnDeviceRendererServiceImpl implements OtnDeviceRendererService {
46     private static final Logger LOG = LoggerFactory.getLogger(OtnDeviceRendererServiceImpl.class);
47     private static final String PT_03 = "03";
48     private static final String PT_07 = "07";
49     private final OpenRoadmInterfaceFactory openRoadmInterfaceFactory;
50     private final CrossConnect crossConnect;
51     private final OpenRoadmInterfaces openRoadmInterfaces;
52     private final DeviceTransactionManager deviceTransactionManager;
53     private final NetworkModelService networkModelService;
54
55     public OtnDeviceRendererServiceImpl(OpenRoadmInterfaceFactory openRoadmInterfaceFactory, CrossConnect crossConnect,
56                                         OpenRoadmInterfaces openRoadmInterfaces,
57                                         DeviceTransactionManager deviceTransactionManager,
58                                         NetworkModelService networkModelService) {
59         this.openRoadmInterfaceFactory = openRoadmInterfaceFactory;
60         this.crossConnect = crossConnect;
61         this.openRoadmInterfaces = openRoadmInterfaces;
62         this.deviceTransactionManager = deviceTransactionManager;
63         this.networkModelService = networkModelService;
64     }
65
66 //TODO Align log messages and returned results messages
67     @Override
68     public OtnServicePathOutput setupOtnServicePath(OtnServicePathInput input, String serviceType) {
69         LOG.info("Calling setup otn-service path");
70         if (input.getServiceFormat() == null || input.getServiceRate() == null) {
71             return new OtnServicePathOutputBuilder()
72                 .setSuccess(false)
73                 .setResult("Error - service-type and service-rate must be present")
74                 .build();
75         }
76         List<NodeInterface> nodeInterfaces = new ArrayList<>();
77         CopyOnWriteArrayList<LinkTp> otnLinkTps = new CopyOnWriteArrayList<>();
78         try {
79             switch (serviceType) {
80                 case StringConstants.SERVICE_TYPE_1GE:
81                 case StringConstants.SERVICE_TYPE_10GE:
82                 case StringConstants.SERVICE_TYPE_100GE_M:
83                     LOG.info("Calling Node interfaces {} {} {} {} {} {} {}",
84                         input.getServiceRate(), input.getEthernetEncoding(),
85                         input.getServiceFormat(), input.getOperation(), input.getTribPortNumber(),
86                         input.getTribSlot(), input.getNodes());
87                     if (input.getNodes() != null) {
88                         createLowOrderInterfaces(input, nodeInterfaces, otnLinkTps);
89                         LOG.info("Node interfaces created just fine ");
90                     }
91                     break;
92                 case StringConstants.SERVICE_TYPE_ODU4:
93                     createODU4TtpInterface(input, nodeInterfaces, otnLinkTps);
94                     break;
95                 case StringConstants.SERVICE_TYPE_ODUC4:
96                     createOduc4TtpInterface(input, nodeInterfaces, otnLinkTps);
97                     break;
98                 case StringConstants.SERVICE_TYPE_100GE_S:
99                     LOG.info("Calling Node interface for service-type {}", serviceType);
100                     if (input.getNodes() != null) {
101                         createHighOrderInterfaces(input, nodeInterfaces, otnLinkTps);
102                         LOG.info("Node interfaces created");
103                     }
104                     break;
105                 default:
106                     LOG.error("Service-type {} not managed yet", serviceType);
107                     return new OtnServicePathOutputBuilder()
108                         .setSuccess(false)
109                         .setResult("Service-type not managed")
110                         .build();
111             }
112         } catch (OpenRoadmInterfaceException e) {
113             LOG.warn("Service path set-up failed", e);
114             Map<NodeInterfaceKey,NodeInterface> nodeInterfacesMap = new HashMap<>();
115             for (NodeInterface nodeInterface : nodeInterfaces) {
116                 if (nodeInterface != null) {
117                     nodeInterfacesMap.put(nodeInterface.key(), nodeInterface);
118                 }
119             }
120             //TODO check if we need to set a NodeInterface Map in the result in that case
121             return new OtnServicePathOutputBuilder()
122                     .setSuccess(false)
123                     .setNodeInterface(nodeInterfacesMap)
124                     .setResult("Service path set-up failed")
125                     .setLinkTp(otnLinkTps)
126                     .build();
127         }
128         LOG.info("Service path set-up succeed");
129         List<String> results = new ArrayList<>();
130         Map<NodeInterfaceKey,NodeInterface> nodeInterfacesMap = new HashMap<>();
131         for (NodeInterface nodeInterface : nodeInterfaces) {
132             if (nodeInterface != null) {
133                 results.add("Otn Service path was set up successfully for node :" + nodeInterface.getNodeId());
134                 nodeInterfacesMap.put(nodeInterface.key(), nodeInterface);
135             }
136         }
137         return new OtnServicePathOutputBuilder()
138                 .setSuccess(true)
139                 .setNodeInterface(nodeInterfacesMap)
140                 .setResult(String.join("\n", results))
141                 .setLinkTp(otnLinkTps)
142                 .build();
143     }
144
145     @SuppressWarnings("rawtypes")
146     // FIXME check if the ForkJoinTask raw type can be avoided
147     // Raw types use are discouraged since they lack type safety.
148     // Resulting Problems are observed at run time and not at compile time
149     public OtnServicePathOutput deleteOtnServicePath(OtnServicePathInput input, String serviceType) {
150         if (input.getNodes() == null) {
151             LOG.error("Unable to delete otn service path. input nodes = null");
152             return new OtnServicePathOutputBuilder()
153                 .setResult("Unable to delete otn service path. input nodes = null")
154                 .setSuccess(false)
155                 .build();
156         }
157         List<Nodes> nodes = input.getNodes();
158         AtomicBoolean success = new AtomicBoolean(true);
159         ConcurrentLinkedQueue<String> results = new ConcurrentLinkedQueue<>();
160         CopyOnWriteArrayList<LinkTp> otnLinkTps = new CopyOnWriteArrayList<>();
161         ForkJoinPool forkJoinPool = new ForkJoinPool();
162         ForkJoinTask forkJoinTask = forkJoinPool.submit(() -> nodes.parallelStream().forEach(node -> {
163             String nodeId = node.getNodeId();
164             LOG.info("Deleting service setup on node {}", nodeId);
165             String networkTp = node.getNetworkTp();
166             if (networkTp == null || input.getServiceRate() == null || input.getServiceFormat() == null) {
167                 LOG.error("destination ({}) or service-rate ({}) or service-format ({}) is null.",
168                     networkTp, input.getServiceRate(), input.getServiceFormat());
169                 return;
170             }
171             if (!this.deviceTransactionManager.isDeviceMounted(nodeId)) {
172                 String result = nodeId + " is not mounted on the controller";
173                 results.add(result);
174                 success.set(false);
175                 LOG.warn(result);
176                 forkJoinPool.shutdown();
177                 return;
178                 // TODO should deletion end here?
179             }
180             // if the node is currently mounted then proceed.
181             List<String> interfacesToDelete = new LinkedList<>();
182             String connectionNumber = "";
183             switch (serviceType) {
184                 case StringConstants.SERVICE_TYPE_100GE_S:
185                     connectionNumber = getConnectionNumber(null, node, networkTp, "ODU4");
186                     break;
187                 case StringConstants.SERVICE_TYPE_100GE_M:
188                     connectionNumber = getConnectionNumber(input.getServiceName(), node, networkTp, "ODU4");
189                     break;
190                 case StringConstants.SERVICE_TYPE_ODU4:
191                     interfacesToDelete.add(networkTp + "-ODU4");
192                     if (node.getNetwork2Tp() != null) {
193                         interfacesToDelete.add(node.getNetwork2Tp() + "-ODU4");
194                     }
195                     break;
196                 case StringConstants.SERVICE_TYPE_ODUC4:
197                     interfacesToDelete.add(networkTp + "-ODUC4");
198                     if (node.getNetwork2Tp() != null) {
199                         interfacesToDelete.add(node.getNetwork2Tp() + "-ODUC4");
200                     }
201                     break;
202                 case StringConstants.SERVICE_TYPE_10GE:
203                     connectionNumber = getConnectionNumber(input.getServiceName(), node, networkTp, "ODU2e");
204                     break;
205                 case StringConstants.SERVICE_TYPE_1GE:
206                     connectionNumber = getConnectionNumber(input.getServiceName(), node, networkTp, "ODU0");
207                     break;
208                 default:
209                     LOG.error("service-type {} not managed yet", serviceType);
210                     String result = serviceType + " is not supported";
211                     results.add(result);
212                     success.set(false);
213                     return;
214             }
215             List<String> intToDelete = this.crossConnect.deleteCrossConnect(nodeId, connectionNumber, true);
216             for (String interf : intToDelete == null ? new ArrayList<String>() : intToDelete) {
217                 if (!this.openRoadmInterfaceFactory.isUsedByOtnXc(nodeId, interf, connectionNumber,
218                         this.deviceTransactionManager)) {
219                     interfacesToDelete.add(interf);
220                     String supportedInterface = this.openRoadmInterfaces.getSupportedInterface(nodeId, interf);
221                     if (supportedInterface == null) {
222                         continue;
223                     }
224                     if ((input.getServiceRate().intValue() == 100 && !supportedInterface.contains("ODUC4"))
225                         || (input.getServiceRate().intValue() != 100 && !supportedInterface.contains("ODU4"))) {
226                         interfacesToDelete.add(supportedInterface);
227                     }
228                 }
229             }
230
231             for (String interfaceId : interfacesToDelete) {
232                 try {
233                     this.openRoadmInterfaces.deleteInterface(nodeId, interfaceId);
234                 } catch (OpenRoadmInterfaceException e) {
235                     String result = String.format("Failed to delete interface %s on node %s!", interfaceId, nodeId);
236                     success.set(false);
237                     LOG.error(result, e);
238                     results.add(result);
239                 }
240             }
241             List<String> interList =
242                     interfacesToDelete.stream().filter(ele -> ele.contains("NETWORK")).collect(Collectors.toList());
243             if (!interList.isEmpty()) {
244                 for (String inter : interList) {
245                     otnLinkTps.add(new LinkTpBuilder()
246                             .setNodeId(nodeId)
247                             .setTpId(inter.split("-ODU")[0])
248                             .build());
249                 }
250             }
251         }));
252         try {
253             forkJoinTask.get();
254         } catch (InterruptedException | ExecutionException e) {
255             LOG.error("Error while deleting service paths!", e);
256             return new OtnServicePathOutputBuilder()
257                 .setResult("Error while deleting service paths!")
258                 .setSuccess(false)
259                 .build();
260         }
261         forkJoinPool.shutdown();
262         return new OtnServicePathOutputBuilder()
263                 .setSuccess(success.get())
264                 .setLinkTp(otnLinkTps)
265                 .setResult(
266                     results.isEmpty()
267                         ? "Request processed"
268                         : String.join("\n", results))
269                 .build();
270     }
271
272     private String getConnectionNumber(String serviceName, Nodes node, String networkTp, String oduType) {
273         List<String> list1 = new ArrayList<>();
274         List<String> list2 = new ArrayList<>(Arrays.asList("x"));
275         if (node.getClientTp() != null) {
276             list1.addAll(Arrays.asList(node.getClientTp(), oduType));
277             list2.addAll(Arrays.asList(networkTp, oduType));
278         } else if (node.getNetwork2Tp() != null) {
279             list1.addAll(Arrays.asList(networkTp, oduType));
280             list2.addAll(Arrays.asList(node.getNetwork2Tp(), oduType));
281         } else {
282             return "";
283         }
284         if (serviceName != null) {
285             list1.add(serviceName);
286             list2.add(serviceName);
287         }
288         list1.addAll(list2);
289         return String.join("-", list1);
290     }
291
292     private Optional<String> postCrossConnect(List<String> createdOduInterfaces, Nodes node)
293             throws OpenRoadmInterfaceException {
294         return this.crossConnect.postOtnCrossConnect(createdOduInterfaces, node);
295     }
296
297     private void createLowOrderInterfaces(OtnServicePathInput input, List<NodeInterface> nodeInterfaces,
298             CopyOnWriteArrayList<LinkTp> linkTpList) throws OpenRoadmInterfaceException {
299         for (Nodes node : input.getNodes()) {
300             // check if the node is mounted or not?
301             List<String> createdEthInterfaces = new ArrayList<>();
302             List<String> createdOduInterfaces = new ArrayList<>();
303             switch (input.getServiceRate().intValue()) {
304                 case 1:
305                     LOG.info("Input service is 1G");
306                     if (node.getClientTp() != null) {
307                         createdEthInterfaces.add(
308                             openRoadmInterfaceFactory.createOpenRoadmEth1GInterface(node.getNodeId(),
309                                 node.getClientTp()));
310                         createdOduInterfaces.add(
311                             // suppporting interface?, payload ?
312                             openRoadmInterfaceFactory.createOpenRoadmOdu0Interface(node.getNodeId(), node.getClientTp(),
313                                 input.getServiceName(), PT_07, false, input.getTribPortNumber(), input.getTribSlot()));
314                     }
315                     createdOduInterfaces.add(
316                         openRoadmInterfaceFactory.createOpenRoadmOdu0Interface(node.getNodeId(), node.getNetworkTp(),
317                             input.getServiceName(), PT_07, true, input.getTribPortNumber(), input.getTribSlot()));
318                     linkTpList.add(
319                         new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
320                     if (node.getNetwork2Tp() != null) {
321                         createdOduInterfaces.add(
322                             // supporting interface? payload ?
323                             openRoadmInterfaceFactory.createOpenRoadmOdu0Interface(node.getNodeId(),
324                                 node.getNetwork2Tp(), input.getServiceName(), PT_07, true, input.getTribPortNumber(),
325                                 input.getTribSlot()));
326                         linkTpList.add(
327                             new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
328                     }
329                     break;
330                 case 10:
331                     LOG.info("Input service is 10G");
332                     if (node.getClientTp() != null) {
333                         createdEthInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmEth10GInterface(
334                             node.getNodeId(), node.getClientTp()));
335                         createdOduInterfaces.add(
336                             // suppporting interface?, payload ?
337                             openRoadmInterfaceFactory.createOpenRoadmOdu2eInterface(node.getNodeId(),
338                                 node.getClientTp(), input.getServiceName(), PT_03, false, input.getTribPortNumber(),
339                                 input.getTribSlot()));
340                     }
341                     createdOduInterfaces.add(
342                         // supporting interface? payload ?
343                         openRoadmInterfaceFactory.createOpenRoadmOdu2eInterface(node.getNodeId(), node.getNetworkTp(),
344                             input.getServiceName(), PT_03, true, input.getTribPortNumber(), input.getTribSlot()));
345                     linkTpList.add(
346                         new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
347                     if (node.getNetwork2Tp() != null) {
348                         createdOduInterfaces.add(
349                             // supporting interface? payload ?
350                             openRoadmInterfaceFactory.createOpenRoadmOdu2eInterface(node.getNodeId(),
351                                 node.getNetwork2Tp(), input.getServiceName(), PT_03, true, input.getTribPortNumber(),
352                                 input.getTribSlot()));
353                         linkTpList.add(
354                             new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
355                     }
356                     break;
357                 case 100:
358                     LOG.info("Input service is 100G");
359                     // Take the first and last value in the list of OpucnTribSlot (assuming SH would provide
360                     // min and max value only, size two)
361                     OpucnTribSlotDef minOpucnTs = OpucnTribSlotDef.getDefaultInstance(
362                         input.getOpucnTribSlots().get(0).getValue());
363                     OpucnTribSlotDef maxOpucnTs = OpucnTribSlotDef.getDefaultInstance(
364                         input.getOpucnTribSlots().get(1).getValue());
365                     if (node.getClientTp() != null) {
366                         createdEthInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmEth100GInterface(
367                             node.getNodeId(), node.getClientTp()));
368                         // OPUCn trib information is optional when creating ODU4 ethernet (client) interface
369                         createdOduInterfaces.add(
370                             openRoadmInterfaceFactory.createOpenRoadmOtnOdu4LoInterface(node.getNodeId(),
371                             node.getClientTp(), input.getServiceName(), PT_07, false, minOpucnTs,
372                                 maxOpucnTs));
373                     }
374                     // Here payload-type is optional and is not used for interface creation (especially for network)
375                     createdOduInterfaces.add(
376                         openRoadmInterfaceFactory.createOpenRoadmOtnOdu4LoInterface(node.getNodeId(),
377                             node.getNetworkTp(), input.getServiceName(), PT_07, true, minOpucnTs,
378                             maxOpucnTs));
379                     linkTpList.add(
380                         new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
381                     // Here payload-type is optional and is not used for service creation
382                     // This is needed if there is an intermediate node
383                     if (node.getNetwork2Tp() != null) {
384                         createdOduInterfaces.add(
385                             openRoadmInterfaceFactory.createOpenRoadmOtnOdu4LoInterface(node.getNodeId(),
386                                 node.getNetwork2Tp(), input.getServiceName(), PT_07, true, minOpucnTs,
387                                 maxOpucnTs));
388                         linkTpList.add(
389                             new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
390                     }
391                     break;
392                 default:
393                     LOG.error("service rate {} not managed yet", input.getServiceRate());
394                     return;
395             }
396
397             // implement cross connect
398             List<String> createdConnections = new ArrayList<>();
399             if (!createdOduInterfaces.isEmpty()) {
400                 Optional<String> connectionNameOpt = postCrossConnect(createdOduInterfaces, node);
401                 createdConnections.add(connectionNameOpt.get());
402                 LOG.info("Created cross connects");
403             }
404             nodeInterfaces.add(new NodeInterfaceBuilder()
405                     .withKey(new NodeInterfaceKey(node.getNodeId()))
406                     .setNodeId(node.getNodeId())
407                     .setConnectionId(createdConnections)
408                     .setEthInterfaceId(createdEthInterfaces)
409                     .setOduInterfaceId(createdOduInterfaces)
410                     .build());
411         }
412     }
413
414     private void createHighOrderInterfaces(OtnServicePathInput input, List<NodeInterface> nodeInterfaces,
415             CopyOnWriteArrayList<LinkTp> linkTpList) throws OpenRoadmInterfaceException {
416         for (Nodes node : input.getNodes()) {
417             // check if the node is mounted or not?
418             List<String> createdEthInterfaces = new ArrayList<>();
419             List<String> createdOduInterfaces = new ArrayList<>();
420             switch (input.getServiceRate().intValue()) {
421                 case 100:
422                     LOG.info("Input service is 100G");
423                     if (node.getClientTp() != null) {
424                         String supEthInter = openRoadmInterfaceFactory.createOpenRoadmEth100GInterface(
425                                 node.getNodeId(), node.getClientTp());
426                         createdEthInterfaces.add(supEthInter);
427                         createdOduInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface(
428                                 node.getNodeId(), node.getClientTp(), false, supEthInter));
429                     }
430                     createdOduInterfaces.add(
431                         // supporting interface? payload ?
432                         openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface(node.getNodeId(), node.getNetworkTp(),
433                                 true, null));
434                     linkTpList.add(
435                         new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
436                     if (node.getNetwork2Tp() != null) {
437                         createdOduInterfaces.add(
438                             // supporting interface? payload ?
439                             openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface(node.getNodeId(),
440                                 node.getNetwork2Tp(), true, null));
441                         linkTpList.add(
442                             new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
443                     }
444                     break;
445                 default:
446                     LOG.error("service rate {} not managed yet", input.getServiceRate());
447                     return;
448             }
449
450             // implement cross connect
451             List<String> createdConnections = new ArrayList<>();
452             if (!createdOduInterfaces.isEmpty()) {
453                 Optional<String> connectionNameOpt = postCrossConnect(createdOduInterfaces, node);
454                 createdConnections.add(connectionNameOpt.get());
455                 LOG.info("Created cross connects");
456             }
457             nodeInterfaces.add(new NodeInterfaceBuilder()
458                     .withKey(new NodeInterfaceKey(node.getNodeId()))
459                     .setNodeId(node.getNodeId())
460                     .setConnectionId(createdConnections)
461                     .setEthInterfaceId(createdEthInterfaces)
462                     .setOduInterfaceId(createdOduInterfaces)
463                     .build());
464         }
465     }
466
467     private void createOduc4TtpInterface(OtnServicePathInput input, List<NodeInterface> nodeInterfaces,
468         CopyOnWriteArrayList<LinkTp> linkTpList) throws OpenRoadmInterfaceException {
469         if (input.getNodes() == null) {
470             return;
471         }
472         LOG.info("Creation of ODUC4 TTP interface in OTN service path {}", input);
473         for (int i = 0; i < input.getNodes().size(); i++) {
474             Nodes node = input.getNodes().get(i);
475             String supportingOtuInterface = node.getNetworkTp() + "-OTUC4";
476
477             Nodes tgtNode =
478                 i + 1 == input.getNodes().size()
479                 // For the end node, tgtNode becomes the first node in the list
480                     ? input.getNodes().get(0)
481                     : input.getNodes().get(i + 1);
482
483             nodeInterfaces.add(new NodeInterfaceBuilder()
484                     .withKey(new NodeInterfaceKey(node.getNodeId()))
485                     .setNodeId(node.getNodeId())
486                     .setOduInterfaceId(List.of(
487                         // though this is odu, actually it has ODUC4 interfaces
488                         openRoadmInterfaceFactory.createOpenRoadmOtnOduc4Interface(node.getNodeId(),
489                             node.getNetworkTp(), supportingOtuInterface, tgtNode.getNodeId(), tgtNode.getNetworkTp())))
490                     .build());
491             linkTpList.add(new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
492         }
493     }
494
495     private void createODU4TtpInterface(OtnServicePathInput input, List<NodeInterface> nodeInterfaces,
496         CopyOnWriteArrayList<LinkTp> linkTpList) throws OpenRoadmInterfaceException {
497         if (input.getNodes() == null) {
498             return;
499         }
500         LOG.info("Creation of ODU4 tp interface {}", input);
501         for (int i = 0; i < input.getNodes().size(); i++) {
502             Nodes node = input.getNodes().get(i);
503             String supportingOtuInterface = node.getNetworkTp() + "-OTU";
504
505             Nodes tgtNode =
506                 i + 1 == input.getNodes().size()
507                 // For the end node, tgtNode becomes the first node in the list
508                     ? input.getNodes().get(0)
509                     : input.getNodes().get(i + 1);
510
511             nodeInterfaces.add(new NodeInterfaceBuilder()
512                     .withKey(new NodeInterfaceKey(node.getNodeId()))
513                     .setNodeId(node.getNodeId())
514                     .setOduInterfaceId(List.of(
515                         openRoadmInterfaceFactory.createOpenRoadmOtnOdu4Interface(node.getNodeId(),
516                             node.getNetworkTp(), supportingOtuInterface, tgtNode.getNodeId(), tgtNode.getNetworkTp())))
517                     .build());
518             linkTpList.add(new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
519         }
520     }
521 }