2 * Copyright © 2017 AT&T, Inc. and others. All rights reserved.
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
8 package org.opendaylight.transportpce.pce.service;
10 import com.google.common.util.concurrent.ListenableFuture;
11 import com.google.common.util.concurrent.ListeningExecutorService;
12 import com.google.common.util.concurrent.MoreExecutors;
13 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.concurrent.Callable;
17 import java.util.concurrent.Executors;
18 import java.util.stream.Collectors;
19 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
20 import org.opendaylight.transportpce.common.mapping.PortMapping;
21 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
22 import org.opendaylight.transportpce.pce.PceComplianceCheck;
23 import org.opendaylight.transportpce.pce.PceComplianceCheckResult;
24 import org.opendaylight.transportpce.pce.PceSendingPceRPCs;
25 import org.opendaylight.transportpce.pce.gnpy.GnpyResult;
26 import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
27 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.Response;
28 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.CancelResourceReserveInput;
29 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.CancelResourceReserveOutput;
30 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.CancelResourceReserveOutputBuilder;
31 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestInput;
32 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestInputBuilder;
33 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestOutput;
34 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestOutputBuilder;
35 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRerouteRequestInput;
36 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRerouteRequestOutput;
37 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRerouteRequestOutputBuilder;
38 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.ServicePathRpcResult;
39 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.ServicePathRpcResultBuilder;
40 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.gnpy.GnpyResponse;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.gnpy.GnpyResponseBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.gnpy.gnpy.response.response.type.NoPathCaseBuilder;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.gnpy.gnpy.response.response.type.PathCaseBuilder;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.computation.request.input.ServiceAEndBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.computation.request.input.ServiceZEndBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.performance.PathPropertiesBuilder;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.performance.path.properties.PathMetric;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.performance.path.properties.PathMetricBuilder;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.service.path.rpc.result.PathDescription;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.service.path.rpc.result.PathDescriptionBuilder;
51 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.configuration.response.common.ConfigurationResponseCommonBuilder;
52 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.AToZDirection;
53 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ZToADirection;
54 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
55 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
56 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.response.parameters.sp.ResponseParametersBuilder;
57 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.handler.header.ServiceHandlerHeaderBuilder;
58 import org.osgi.service.component.annotations.Activate;
59 import org.osgi.service.component.annotations.Component;
60 import org.osgi.service.component.annotations.Reference;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
64 @Component(immediate = true)
65 public class PathComputationServiceImpl implements PathComputationService {
67 private static final Logger LOG = LoggerFactory.getLogger(PathComputationServiceImpl.class);
68 private final NotificationPublishService notificationPublishService;
69 private NetworkTransactionService networkTransactionService;
70 private final ListeningExecutorService executor;
71 private ServicePathRpcResult notification = null;
72 private final GnpyConsumer gnpyConsumer;
73 private PortMapping portMapping;
76 public PathComputationServiceImpl(@Reference NetworkTransactionService networkTransactionService,
77 @Reference NotificationPublishService notificationPublishService,
78 @Reference GnpyConsumer gnpyConsumer,
79 @Reference PortMapping portMapping) {
80 this.notificationPublishService = notificationPublishService;
81 this.networkTransactionService = networkTransactionService;
82 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
83 this.gnpyConsumer = gnpyConsumer;
84 this.portMapping = portMapping;
85 LOG.debug("PathComputationServiceImpl instantiated");
89 value = "UPM_UNCALLED_PRIVATE_METHOD",
90 justification = "false positive, this method is used by public method cancelResourceReserve")
91 private void sendNotifications(
92 ServicePathNotificationTypes servicePathNotificationTypes,
94 RpcStatusEx rpcStatusEx,
96 PathDescription pathDescription) {
97 ServicePathRpcResultBuilder servicePathRpcResultBuilder =
98 new ServicePathRpcResultBuilder()
99 .setNotificationType(servicePathNotificationTypes)
100 .setServiceName(serviceName)
101 .setStatus(rpcStatusEx)
102 .setStatusMessage(message);
103 if (pathDescription != null) {
104 servicePathRpcResultBuilder.setPathDescription(pathDescription);
106 this.notification = servicePathRpcResultBuilder.build();
108 notificationPublishService.putNotification(this.notification);
109 } catch (InterruptedException e) {
110 LOG.info("notification offer rejected: ", e);
115 public ListenableFuture<CancelResourceReserveOutput> cancelResourceReserve(CancelResourceReserveInput input) {
116 LOG.info("cancelResourceReserve");
117 return executor.submit(new Callable<CancelResourceReserveOutput>() {
120 public CancelResourceReserveOutput call() throws Exception {
122 ServicePathNotificationTypes.CancelResourceReserve,
123 input.getServiceName(),
125 "Service compliant, submitting cancelResourceReserve Request ...",
127 PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs(gnpyConsumer);
128 sendingPCE.cancelResourceReserve();
129 LOG.info("in PathComputationServiceImpl : {}",
130 Boolean.TRUE.equals(sendingPCE.getSuccess())
131 ? "ResourceReserve cancelled !"
132 : "Cancelling ResourceReserve failed !");
134 ServicePathNotificationTypes.CancelResourceReserve,
135 input.getServiceName(),
136 RpcStatusEx.Successful,
137 "cancel Resource Reserve successful!",
139 return new CancelResourceReserveOutputBuilder()
140 .setConfigurationResponseCommon(
141 new ConfigurationResponseCommonBuilder()
142 .setAckFinalIndicator("Yes")
143 .setRequestId(input.getServiceHandlerHeader().getRequestId())
144 .setResponseCode("200")
145 .setResponseMessage("")
153 public ListenableFuture<PathComputationRequestOutput> pathComputationRequest(PathComputationRequestInput input) {
154 LOG.debug("input parameters are : input = {}", input.toString());
155 return executor.submit(new Callable<PathComputationRequestOutput>() {
158 public PathComputationRequestOutput call() throws Exception {
159 PathComputationRequestOutputBuilder output = new PathComputationRequestOutputBuilder();
160 ConfigurationResponseCommonBuilder configurationResponseCommon =
161 new ConfigurationResponseCommonBuilder();
162 PceComplianceCheckResult check = PceComplianceCheck.check(input);
163 if (!check.hasPassed()) {
164 LOG.error("Path not calculated, service not compliant : {}", check.getMessage());
166 ServicePathNotificationTypes.PathComputationRequest,
167 input.getServiceName(),
169 "Path not calculated, service not compliant",
171 configurationResponseCommon
172 .setAckFinalIndicator("Yes")
173 .setRequestId(input.getServiceHandlerHeader().getRequestId())
174 .setResponseCode("Path not calculated")
175 .setResponseMessage(check.getMessage());
177 .setConfigurationResponseCommon(configurationResponseCommon.build())
178 .setResponseParameters(null)
182 ServicePathNotificationTypes.PathComputationRequest,
183 input.getServiceName(),
185 "Service compliant, submitting pathComputation Request ...",
187 PceSendingPceRPCs sendingPCE =
188 new PceSendingPceRPCs(input, networkTransactionService, gnpyConsumer, portMapping);
189 sendingPCE.pathComputation();
190 String message = sendingPCE.getMessage();
191 String responseCode = sendingPCE.getResponseCode();
192 LOG.info("PCE response: {} {}", message, responseCode);
194 //add the GNPy result
195 GnpyResult gnpyAtoZ = sendingPCE.getGnpyAtoZ();
196 GnpyResult gnpyZtoA = sendingPCE.getGnpyZtoA();
197 List<GnpyResponse> listResponse = new ArrayList<>();
198 if (gnpyAtoZ != null) {
199 GnpyResponse respAtoZ = generateGnpyResponse(gnpyAtoZ.getResponse(),"A-to-Z");
200 listResponse.add(respAtoZ);
202 if (gnpyZtoA != null) {
203 GnpyResponse respZtoA = generateGnpyResponse(gnpyZtoA.getResponse(),"Z-to-A");
204 listResponse.add(respZtoA);
208 listResponse.stream()
209 .collect(Collectors.toMap(GnpyResponse::key, gnpyResponse -> gnpyResponse)));
211 PathDescriptionBuilder path = sendingPCE.getPathDescription();
212 if (Boolean.FALSE.equals(sendingPCE.getSuccess()) || (path == null)) {
214 ServicePathNotificationTypes.PathComputationRequest,
215 input.getServiceName(),
217 "Path not calculated",
220 .setConfigurationResponseCommon(
221 configurationResponseCommon
222 .setAckFinalIndicator("Yes")
223 .setRequestId(input.getServiceHandlerHeader().getRequestId())
224 .setResponseCode(responseCode)
225 .setResponseMessage(message)
229 // Path calculator returned Success
230 PathDescription pathDescription =
231 new PathDescriptionBuilder()
232 .setAToZDirection(path.getAToZDirection())
233 .setZToADirection(path.getZToADirection())
236 ServicePathNotificationTypes.PathComputationRequest,
237 input.getServiceName(),
238 RpcStatusEx.Successful,
241 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
242 .response.parameters.sp.response.parameters.PathDescription pathDescription1 =
243 new org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
244 .response.parameters.sp.response.parameters.PathDescriptionBuilder()
245 .setAToZDirection(path.getAToZDirection())
246 .setZToADirection(path.getZToADirection())
249 .setConfigurationResponseCommon(
250 configurationResponseCommon
251 .setAckFinalIndicator("Yes")
252 .setRequestId(input.getServiceHandlerHeader().getRequestId())
253 .setResponseCode(responseCode)
254 .setResponseMessage(message)
256 .setResponseParameters(
257 new ResponseParametersBuilder().setPathDescription(pathDescription1).build());
259 AToZDirection atoz = pathDescription.getAToZDirection();
260 if ((atoz != null) && (atoz.getAToZ() != null)) {
261 LOG.debug("Impl AtoZ Notification: [{}] elements in description", atoz.getAToZ().size());
262 for (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
263 .path.description.atoz.direction.AToZKey key : atoz.getAToZ().keySet()) {
264 LOG.debug("Impl AtoZ Notification: [{}] {}", key, atoz.getAToZ().get(key));
267 ZToADirection ztoa = pathDescription.getZToADirection();
268 if ((ztoa != null) && (ztoa.getZToA() != null)) {
269 LOG.debug("Impl ZtoA Notification: [{}] elements in description", ztoa.getZToA().size());
270 for (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
271 .path.description.ztoa.direction.ZToAKey key : ztoa.getZToA().keySet()) {
272 LOG.debug("Impl ZtoA Notification: [{}] {}", key, ztoa.getZToA().get(key));
275 return output.build();
281 public ListenableFuture<PathComputationRerouteRequestOutput> pathComputationRerouteRequest(
282 PathComputationRerouteRequestInput input) {
283 return executor.submit(() -> {
284 PathComputationRerouteRequestOutputBuilder output = new PathComputationRerouteRequestOutputBuilder();
285 ConfigurationResponseCommonBuilder configurationResponseCommon = new ConfigurationResponseCommonBuilder()
286 .setRequestId("none");
287 PceComplianceCheckResult check = PceComplianceCheck.check(input);
288 if (!check.hasPassed()) {
289 LOG.error("Path not calculated, path computation reroute request not compliant : {}",
291 configurationResponseCommon
292 .setAckFinalIndicator("Yes")
293 .setResponseCode("Path not calculated")
294 .setResponseMessage(check.getMessage());
296 .setConfigurationResponseCommon(configurationResponseCommon.build())
299 PathComputationRequestInput pathComputationInput = new PathComputationRequestInputBuilder()
300 .setServiceName("no_name")
301 .setServiceHandlerHeader(new ServiceHandlerHeaderBuilder().setRequestId("none").build())
302 .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
303 .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
304 .setHardConstraints(input.getHardConstraints())
305 .setPceRoutingMetric(input.getPceRoutingMetric())
306 .setResourceReserve(false)
307 .setSoftConstraints(input.getSoftConstraints())
308 .setRoutingMetric(input.getRoutingMetric())
310 PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs(pathComputationInput, networkTransactionService,
311 gnpyConsumer, portMapping, input.getEndpoints());
312 sendingPCE.pathComputation();
313 String message = sendingPCE.getMessage();
314 String responseCode = sendingPCE.getResponseCode();
315 LOG.info("PCE response: {} {}", message, responseCode);
316 return output.setConfigurationResponseCommon(
317 configurationResponseCommon
318 .setAckFinalIndicator("Yes")
319 .setResponseCode(responseCode)
320 .setResponseMessage(message)
326 public GnpyResponse generateGnpyResponse(Response responseGnpy, String pathDir) {
327 if (responseGnpy == null) {
328 return new GnpyResponseBuilder()
330 .setResponseType(null)
331 .setFeasibility(true)
334 if (responseGnpy.getResponseType()
335 instanceof org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase) {
336 LOG.info("GNPy : path is not feasible");
337 org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase
339 (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase)
340 responseGnpy.getResponseType();
341 return new GnpyResponseBuilder()
344 new NoPathCaseBuilder()
345 .setNoPath(noPathGnpy.getNoPath())
347 .setFeasibility(false)
350 if (responseGnpy.getResponseType()
351 instanceof org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase) {
352 LOG.info("GNPy : path is feasible");
353 org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase
355 (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase)
356 responseGnpy.getResponseType();
357 List<org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.properties.path.properties.PathMetric>
359 new ArrayList<>(pathCase.getPathProperties().getPathMetric().values());
360 List<PathMetric> gnpyPathMetricList = new ArrayList<>();
361 for (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.properties.path.properties.PathMetric
362 pathMetricGnpy : pathMetricList) {
363 gnpyPathMetricList.add(
364 new PathMetricBuilder()
365 .setMetricType(pathMetricGnpy.getMetricType())
366 .setAccumulativeValue(pathMetricGnpy.getAccumulativeValue())
369 return new GnpyResponseBuilder()
372 new PathCaseBuilder()
374 new PathPropertiesBuilder()
375 .setPathMetric(gnpyPathMetricList.stream()
376 .collect(Collectors.toMap(PathMetric::key, pathMetric -> pathMetric)))
379 .setFeasibility(true)
382 return new GnpyResponseBuilder()
384 .setResponseType(null)
385 .setFeasibility(true)