Manage low order otn services over multiple ODU4
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / RendererServiceOperationsImpl.java
index d1b3848986a10ea52ba1a48f320ef34d509ea095..ccb610049439d18965b8b2a3cd3076025f5dae02 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -20,6 +21,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
 import org.opendaylight.mdsal.binding.api.ReadTransaction;
@@ -38,8 +40,8 @@ import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetu
 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.Action;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.OtnServicePathInput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.Action;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
@@ -47,16 +49,17 @@ import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev21
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownOutput;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.TransportpceOlmService;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.RendererRpcResultSp;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.RendererRpcResultSpBuilder;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceDeleteInput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceDeleteOutput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceImplementationRequestInput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceImplementationRequestOutput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.link._for.notif.ATerminationBuilder;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.link._for.notif.ZTerminationBuilder;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.renderer.rpc.result.sp.Link;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.renderer.rpc.result.sp.LinkBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210927.mapping.Mapping;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSp;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSpBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteInput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteOutput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestOutput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ATerminationBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ZTerminationBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.LinkBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
@@ -71,6 +74,7 @@ import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service
 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTp;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.olm.get.pm.input.ResourceIdentifierBuilder;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.optical.renderer.nodes.Nodes;
+import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev210511.OtnLinkType;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -150,6 +154,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                     case StringConstants.SERVICE_TYPE_1GE:
                     case StringConstants.SERVICE_TYPE_10GE:
                     case StringConstants.SERVICE_TYPE_100GE_M:
+                    case StringConstants.SERVICE_TYPE_100GE_S:
                     case StringConstants.SERVICE_TYPE_ODU4:
                     case StringConstants.SERVICE_TYPE_ODUC4:
                         if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
@@ -159,7 +164,8 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                         break;
                     default:
                         LOG.error("unsupported service-type");
-                        break;
+                        return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
+                            OPERATION_FAILED);
                 }
                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
                     OPERATION_SUCCESSFUL);
@@ -181,7 +187,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                 Optional<
                     org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.service
                     .path.PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
-                if (!pathDescriptionOpt.isPresent()) {
+                if (pathDescriptionOpt.isEmpty()) {
                     LOG.error("Unable to get path description for service {}!", serviceName);
                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
                             RpcStatusEx.Failed, "Unable to get path description for service");
@@ -189,8 +195,10 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                             OPERATION_FAILED);
                 }
                 PathDescription pathDescription = pathDescriptionOpt.get();
+                Mapping mapping = portMapping.getMapping(service.getServiceAEnd().getNodeId().getValue(),
+                    service.getServiceAEnd().getTxDirection().getPort().getPortName());
                 String serviceType = ServiceTypes.getServiceType(service.getServiceAEnd().getServiceFormat().getName(),
-                    service.getServiceAEnd().getServiceRate(), null);
+                    service.getServiceAEnd().getServiceRate(), mapping);
                 switch (serviceType) {
                     case StringConstants.SERVICE_TYPE_100GE_T:
                     case StringConstants.SERVICE_TYPE_400GE:
@@ -204,6 +212,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                     case StringConstants.SERVICE_TYPE_1GE:
                     case StringConstants.SERVICE_TYPE_10GE:
                     case StringConstants.SERVICE_TYPE_100GE_M:
+                    case StringConstants.SERVICE_TYPE_100GE_S:
                     case StringConstants.SERVICE_TYPE_ODU4:
                     case StringConstants.SERVICE_TYPE_ODUC4:
                         if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
@@ -213,7 +222,8 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                         break;
                     default:
                         LOG.error("unsupported service-type");
-                        break;
+                        return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
+                            OPERATION_FAILED);
                 }
                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
             }
@@ -231,43 +241,33 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         if (input.getServiceAEnd().getServiceRate() != null) {
             return input.getServiceAEnd().getServiceRate();
         }
-        if (ServiceFormat.OTU.equals(input.getServiceAEnd().getServiceFormat())
-                && input.getServiceAEnd().getOtuServiceRate() != null) {
-            switch (input.getServiceAEnd().getOtuServiceRate().getSimpleName()) {
-                case "OTUCn":
-                    return Uint32.valueOf(400);
-                case "OTU4":
-                    return Uint32.valueOf(100);
-                case "OTU2":
-                case "OTU2e":
-                    return Uint32.valueOf(10);
-                default:
-                    LOG.warn("otu-service-rate {} not managed yet", input.getServiceAEnd().getOtuServiceRate()
-                        .getSimpleName());
-                    return Uint32.ZERO;
-            }
-        } else if (ServiceFormat.ODU.equals(input.getServiceAEnd().getServiceFormat())
-                && input.getServiceAEnd().getOduServiceRate() != null) {
-            switch (input.getServiceAEnd().getOduServiceRate().getSimpleName()) {
-                case "ODUCn":
-                    return Uint32.valueOf(400);
-                case "ODU4":
-                    return Uint32.valueOf(100);
-                case "ODU2":
-                case "ODU2e":
-                    return Uint32.valueOf(10);
-                case "ODU0":
-                    return Uint32.valueOf(1);
-                default:
-                    LOG.warn("odu-service-rate {} not managed yet", input.getServiceAEnd().getOduServiceRate()
-                        .getSimpleName());
-                    return Uint32.ZERO;
-            }
-        } else {
-            LOG.warn("Unable to get service-rate for service {} - otu-service-rate should not be null",
-                input.getServiceName());
+        Map<ServiceFormat, Map<String, Uint32>> formatRateMap  = Map.of(
+                ServiceFormat.OTU, Map.of(
+                    "OTUCn", Uint32.valueOf(400),
+                    "OTU4", Uint32.valueOf(100),
+                    "OTU2", Uint32.valueOf(10),
+                    "OTU2e", Uint32.valueOf(10)),
+                ServiceFormat.ODU, Map.of(
+                    "ODUCn",Uint32.valueOf(400),
+                    "ODU4", Uint32.valueOf(100),
+                    "ODU2", Uint32.valueOf(10),
+                    "ODU2e", Uint32.valueOf(10),
+                    "ODU0", Uint32.valueOf(1)));
+        if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
+            LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
+                input.getServiceName(), input.getServiceAEnd().getServiceFormat());
+            return Uint32.ZERO;
+        }
+        String serviceName =
+            ServiceFormat.OTU.equals(input.getServiceAEnd().getServiceFormat())
+                ? input.getServiceAEnd().getOtuServiceRate().getSimpleName()
+                : input.getServiceAEnd().getOduServiceRate().getSimpleName();
+        if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
+            LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
+                input.getServiceName(), serviceName);
             return Uint32.ZERO;
         }
+        return formatRateMap.get(input.getServiceAEnd().getServiceFormat()).get(serviceName);
     }
 
     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
@@ -352,19 +352,19 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         value = "UPM_UNCALLED_PRIVATE_METHOD",
         justification = "call in call() method")
     private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
-        OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA) {
+        OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA, String serviceType) {
         LOG.info(RENDERING_DEVICES_A_Z_MSG);
         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
             otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
             RENDERING_DEVICES_A_Z_MSG);
         ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
-            this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ));
-        LOG.info("Rendering devices Z-A");
+            this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
+        LOG.info(RENDERING_DEVICES_Z_A_MSG);
         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
             otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
             RENDERING_DEVICES_Z_A_MSG);
         ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
-            this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA));
+            this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
         ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
@@ -435,17 +435,17 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
         for (int i = 0; i < 3; i++) {
             List<Measurements> measurements = getMeasurements(nodeId, tpId);
-            if ((measurements != null) && verifyPreFecBer(measurements)) {
-                return true;
-            } else if (measurements == null) {
+            if (measurements == null) {
                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
                 return true;
-            } else {
-                try {
-                    Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
-                } catch (InterruptedException ex) {
-                    Thread.currentThread().interrupt();
-                }
+            }
+            if (verifyPreFecBer(measurements)) {
+                return true;
+            }
+            try {
+                Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
+            } catch (InterruptedException ex) {
+                Thread.currentThread().interrupt();
             }
         }
         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
@@ -482,11 +482,15 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         double fecUncorrectableBlocks = Double.MIN_VALUE;
 
         for (Measurements measurement : measurements) {
-            if (measurement.getPmparameterName().equals("preFECCorrectedErrors")) {
-                preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
-            }
-            if (measurement.getPmparameterName().equals("FECUncorrectableBlocks")) {
-                fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
+            switch (measurement.getPmparameterName()) {
+                case "preFECCorrectedErrors":
+                    preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
+                    break;
+                case "FECUncorrectableBlocks":
+                    fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
+                    break;
+                default:
+                    break;
             }
         }
 
@@ -496,13 +500,13 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
             LOG.error("Data has uncorrectable errors, BER test failed");
             return false;
-        } else {
-            double numOfBitsPerSecond = 112000000000d;
-            double threshold = 0.00002d;
-            double result = preFecCorrectedErrors / numOfBitsPerSecond;
-            LOG.info("PreFEC value is {}", Double.toString(result));
-            return result <= threshold;
         }
+
+        double numOfBitsPerSecond = 112000000000d;
+        double threshold = 0.00002d;
+        double result = preFecCorrectedErrors / numOfBitsPerSecond;
+        LOG.info("PreFEC value is {}", Double.toString(result));
+        return result <= threshold;
     }
 
     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
@@ -564,7 +568,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
 
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
             input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
-            notifLink, serviceType);
+            notifLink, null, serviceType);
         return true;
     }
 
@@ -617,7 +621,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
 
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
-                serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, serviceType);
+            serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, null, serviceType);
         return true;
     }
 
@@ -641,7 +645,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         // Rollback should be same for all conditions, so creating a new one
         RollbackProcessor rollbackProcessor = new RollbackProcessor();
         List<OtnDeviceRenderingResult> renderingResults =
-            otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA);
+            otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
             rollbackProcessor.rollbackAll();
             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
@@ -651,10 +655,12 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
         renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
+        List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription());
+        List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
 
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
             input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
-            notifLink, serviceType);
+            notifLink, supportedLinks, serviceType);
         return true;
     }
 
@@ -681,14 +687,17 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
 
         RollbackProcessor rollbackProcessor = new RollbackProcessor();
         List<OtnDeviceRenderingResult> renderingResults =
-            otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA);
+            otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
 
         List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
         renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
+        List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(pathDescription);
+        List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
 
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
-                serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, serviceType);
+                serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, supportedLinks,
+                serviceType);
         return true;
     }
 
@@ -702,7 +711,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
     private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
             RpcStatusEx rpcStatusEx, String message) {
         Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
-                null, null, null);
+                null, null, null, null);
         send(notification);
     }
 
@@ -716,9 +725,9 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
      */
     private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
             String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
-            Link notifLink, String serviceType) {
+            Link notifLink, List<String> supportedLinks, String serviceType) {
         Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
-                pathDescription, notifLink, serviceType);
+                pathDescription, notifLink, supportedLinks, serviceType);
         send(notification);
     }
 
@@ -733,7 +742,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
      */
     private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
             String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
-            Link notifLink, String serviceType) {
+            Link notifLink, List<String> supportedLinks, String serviceType) {
         RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
                 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
                 .setStatusMessage(message)
@@ -745,6 +754,9 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         if (notifLink != null) {
             builder.setLink(notifLink);
         }
+        if (supportedLinks != null) {
+            builder.setLinkId(supportedLinks);
+        }
         return builder.build();
     }
 
@@ -763,10 +775,10 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
     }
 
     private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
-        if (otnLinkTerminationPoints.size() != 2 || otnLinkTerminationPoints.isEmpty()) {
+        if (otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2) {
             return null;
-        } else {
-            return new LinkBuilder()
+        }
+        return new LinkBuilder()
                 .setATermination(new ATerminationBuilder()
                     .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
                     .setTpId(otnLinkTerminationPoints.get(0).getTpId())
@@ -776,6 +788,26 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                     .setTpId(otnLinkTerminationPoints.get(1).getTpId())
                     .build())
                 .build();
+    }
+
+    private List<String> getSupportedLinks(List<String> allSupportLinks, String serviceType) {
+        switch (serviceType) {
+            case StringConstants.SERVICE_TYPE_10GE:
+            case StringConstants.SERVICE_TYPE_1GE:
+                return allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toList());
+            case StringConstants.SERVICE_TYPE_100GE_M:
+                return allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toList());
+            case StringConstants.SERVICE_TYPE_ODU4:
+            case StringConstants.SERVICE_TYPE_100GE_S:
+                return allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toList());
+            case StringConstants.SERVICE_TYPE_ODUC4:
+                return allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toList());
+            default:
+                return null;
         }
     }
 }