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.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
61 public class PathComputationServiceImpl implements PathComputationService {
63 private static final Logger LOG = LoggerFactory.getLogger(PathComputationServiceImpl.class);
64 private final NotificationPublishService notificationPublishService;
65 private NetworkTransactionService networkTransactionService;
66 private final ListeningExecutorService executor;
67 private ServicePathRpcResult notification = null;
68 private final GnpyConsumer gnpyConsumer;
69 private PortMapping portMapping;
71 public PathComputationServiceImpl(NetworkTransactionService networkTransactionService,
72 NotificationPublishService notificationPublishService,
73 GnpyConsumer gnpyConsumer, PortMapping portMapping) {
74 this.notificationPublishService = notificationPublishService;
75 this.networkTransactionService = networkTransactionService;
76 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
77 this.gnpyConsumer = gnpyConsumer;
78 this.portMapping = portMapping;
90 value = "UPM_UNCALLED_PRIVATE_METHOD",
91 justification = "false positive, this method is used by public method cancelResourceReserve")
92 private void sendNotifications(
93 ServicePathNotificationTypes servicePathNotificationTypes,
95 RpcStatusEx rpcStatusEx,
97 PathDescription pathDescription) {
98 ServicePathRpcResultBuilder servicePathRpcResultBuilder =
99 new ServicePathRpcResultBuilder()
100 .setNotificationType(servicePathNotificationTypes)
101 .setServiceName(serviceName)
102 .setStatus(rpcStatusEx)
103 .setStatusMessage(message);
104 if (pathDescription != null) {
105 servicePathRpcResultBuilder.setPathDescription(pathDescription);
107 this.notification = servicePathRpcResultBuilder.build();
109 notificationPublishService.putNotification(this.notification);
110 } catch (InterruptedException e) {
111 LOG.info("notification offer rejected: ", e);
116 public ListenableFuture<CancelResourceReserveOutput> cancelResourceReserve(CancelResourceReserveInput input) {
117 LOG.info("cancelResourceReserve");
118 return executor.submit(new Callable<CancelResourceReserveOutput>() {
121 public CancelResourceReserveOutput call() throws Exception {
123 ServicePathNotificationTypes.CancelResourceReserve,
124 input.getServiceName(),
126 "Service compliant, submitting cancelResourceReserve Request ...",
128 PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs(gnpyConsumer);
129 sendingPCE.cancelResourceReserve();
130 LOG.info("in PathComputationServiceImpl : {}",
131 Boolean.TRUE.equals(sendingPCE.getSuccess())
132 ? "ResourceReserve cancelled !"
133 : "Cancelling ResourceReserve failed !");
135 ServicePathNotificationTypes.CancelResourceReserve,
136 input.getServiceName(),
137 RpcStatusEx.Successful,
138 "cancel Resource Reserve successful!",
140 return new CancelResourceReserveOutputBuilder()
141 .setConfigurationResponseCommon(
142 new ConfigurationResponseCommonBuilder()
143 .setAckFinalIndicator("Yes")
144 .setRequestId(input.getServiceHandlerHeader().getRequestId())
145 .setResponseCode("200")
146 .setResponseMessage("")
154 public ListenableFuture<PathComputationRequestOutput> pathComputationRequest(PathComputationRequestInput input) {
155 LOG.debug("input parameters are : input = {}", input.toString());
156 return executor.submit(new Callable<PathComputationRequestOutput>() {
159 public PathComputationRequestOutput call() throws Exception {
160 PathComputationRequestOutputBuilder output = new PathComputationRequestOutputBuilder();
161 ConfigurationResponseCommonBuilder configurationResponseCommon =
162 new ConfigurationResponseCommonBuilder();
163 PceComplianceCheckResult check = PceComplianceCheck.check(input);
164 if (!check.hasPassed()) {
165 LOG.error("Path not calculated, service not compliant : {}", check.getMessage());
167 ServicePathNotificationTypes.PathComputationRequest,
168 input.getServiceName(),
170 "Path not calculated, service not compliant",
172 configurationResponseCommon
173 .setAckFinalIndicator("Yes")
174 .setRequestId(input.getServiceHandlerHeader().getRequestId())
175 .setResponseCode("Path not calculated")
176 .setResponseMessage(check.getMessage());
178 .setConfigurationResponseCommon(configurationResponseCommon.build())
179 .setResponseParameters(null)
183 ServicePathNotificationTypes.PathComputationRequest,
184 input.getServiceName(),
186 "Service compliant, submitting pathComputation Request ...",
188 PceSendingPceRPCs sendingPCE =
189 new PceSendingPceRPCs(input, networkTransactionService, gnpyConsumer, portMapping);
190 sendingPCE.pathComputation();
191 String message = sendingPCE.getMessage();
192 String responseCode = sendingPCE.getResponseCode();
193 LOG.info("PCE response: {} {}", message, responseCode);
195 //add the GNPy result
196 GnpyResult gnpyAtoZ = sendingPCE.getGnpyAtoZ();
197 GnpyResult gnpyZtoA = sendingPCE.getGnpyZtoA();
198 List<GnpyResponse> listResponse = new ArrayList<>();
199 if (gnpyAtoZ != null) {
200 GnpyResponse respAtoZ = generateGnpyResponse(gnpyAtoZ.getResponse(),"A-to-Z");
201 listResponse.add(respAtoZ);
203 if (gnpyZtoA != null) {
204 GnpyResponse respZtoA = generateGnpyResponse(gnpyZtoA.getResponse(),"Z-to-A");
205 listResponse.add(respZtoA);
209 listResponse.stream()
210 .collect(Collectors.toMap(GnpyResponse::key, gnpyResponse -> gnpyResponse)));
212 PathDescriptionBuilder path = sendingPCE.getPathDescription();
213 if (Boolean.FALSE.equals(sendingPCE.getSuccess()) || (path == null)) {
215 ServicePathNotificationTypes.PathComputationRequest,
216 input.getServiceName(),
218 "Path not calculated",
221 .setConfigurationResponseCommon(
222 configurationResponseCommon
223 .setAckFinalIndicator("Yes")
224 .setRequestId(input.getServiceHandlerHeader().getRequestId())
225 .setResponseCode(responseCode)
226 .setResponseMessage(message)
230 // Path calculator returned Success
231 PathDescription pathDescription =
232 new PathDescriptionBuilder()
233 .setAToZDirection(path.getAToZDirection())
234 .setZToADirection(path.getZToADirection())
237 ServicePathNotificationTypes.PathComputationRequest,
238 input.getServiceName(),
239 RpcStatusEx.Successful,
242 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
243 .response.parameters.sp.response.parameters.PathDescription pathDescription1 =
244 new org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
245 .response.parameters.sp.response.parameters.PathDescriptionBuilder()
246 .setAToZDirection(path.getAToZDirection())
247 .setZToADirection(path.getZToADirection())
250 .setConfigurationResponseCommon(
251 configurationResponseCommon
252 .setAckFinalIndicator("Yes")
253 .setRequestId(input.getServiceHandlerHeader().getRequestId())
254 .setResponseCode(responseCode)
255 .setResponseMessage(message)
257 .setResponseParameters(
258 new ResponseParametersBuilder().setPathDescription(pathDescription1).build());
260 AToZDirection atoz = pathDescription.getAToZDirection();
261 if ((atoz != null) && (atoz.getAToZ() != null)) {
262 LOG.debug("Impl AtoZ Notification: [{}] elements in description", atoz.getAToZ().size());
263 for (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
264 .path.description.atoz.direction.AToZKey key : atoz.getAToZ().keySet()) {
265 LOG.debug("Impl AtoZ Notification: [{}] {}", key, atoz.getAToZ().get(key));
268 ZToADirection ztoa = pathDescription.getZToADirection();
269 if ((ztoa != null) && (ztoa.getZToA() != null)) {
270 LOG.debug("Impl ZtoA Notification: [{}] elements in description", ztoa.getZToA().size());
271 for (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
272 .path.description.ztoa.direction.ZToAKey key : ztoa.getZToA().keySet()) {
273 LOG.debug("Impl ZtoA Notification: [{}] {}", key, ztoa.getZToA().get(key));
276 return output.build();
282 public ListenableFuture<PathComputationRerouteRequestOutput> pathComputationRerouteRequest(
283 PathComputationRerouteRequestInput input) {
284 return executor.submit(() -> {
285 PathComputationRerouteRequestOutputBuilder output = new PathComputationRerouteRequestOutputBuilder();
286 ConfigurationResponseCommonBuilder configurationResponseCommon = new ConfigurationResponseCommonBuilder()
287 .setRequestId("none");
288 PceComplianceCheckResult check = PceComplianceCheck.check(input);
289 if (!check.hasPassed()) {
290 LOG.error("Path not calculated, path computation reroute request not compliant : {}",
292 configurationResponseCommon
293 .setAckFinalIndicator("Yes")
294 .setResponseCode("Path not calculated")
295 .setResponseMessage(check.getMessage());
297 .setConfigurationResponseCommon(configurationResponseCommon.build())
300 PathComputationRequestInput pathComputationInput = new PathComputationRequestInputBuilder()
301 .setServiceName("no_name")
302 .setServiceHandlerHeader(new ServiceHandlerHeaderBuilder().setRequestId("none").build())
303 .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
304 .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
305 .setHardConstraints(input.getHardConstraints())
306 .setPceRoutingMetric(input.getPceRoutingMetric())
307 .setResourceReserve(false)
308 .setSoftConstraints(input.getSoftConstraints())
309 .setRoutingMetric(input.getRoutingMetric())
311 PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs(pathComputationInput, networkTransactionService,
312 gnpyConsumer, portMapping, input.getEndpoints());
313 sendingPCE.pathComputation();
314 String message = sendingPCE.getMessage();
315 String responseCode = sendingPCE.getResponseCode();
316 LOG.info("PCE response: {} {}", message, responseCode);
317 return output.setConfigurationResponseCommon(
318 configurationResponseCommon
319 .setAckFinalIndicator("Yes")
320 .setResponseCode(responseCode)
321 .setResponseMessage(message)
327 public GnpyResponse generateGnpyResponse(Response responseGnpy, String pathDir) {
328 if (responseGnpy == null) {
329 return new GnpyResponseBuilder()
331 .setResponseType(null)
332 .setFeasibility(true)
335 if (responseGnpy.getResponseType()
336 instanceof org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase) {
337 LOG.info("GNPy : path is not feasible");
338 org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase
340 (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase)
341 responseGnpy.getResponseType();
342 return new GnpyResponseBuilder()
345 new NoPathCaseBuilder()
346 .setNoPath(noPathGnpy.getNoPath())
348 .setFeasibility(false)
351 if (responseGnpy.getResponseType()
352 instanceof org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase) {
353 LOG.info("GNPy : path is feasible");
354 org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase
356 (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase)
357 responseGnpy.getResponseType();
358 List<org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.properties.path.properties.PathMetric>
360 new ArrayList<>(pathCase.getPathProperties().getPathMetric().values());
361 List<PathMetric> gnpyPathMetricList = new ArrayList<>();
362 for (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.properties.path.properties.PathMetric
363 pathMetricGnpy : pathMetricList) {
364 gnpyPathMetricList.add(
365 new PathMetricBuilder()
366 .setMetricType(pathMetricGnpy.getMetricType())
367 .setAccumulativeValue(pathMetricGnpy.getAccumulativeValue())
370 return new GnpyResponseBuilder()
373 new PathCaseBuilder()
375 new PathPropertiesBuilder()
376 .setPathMetric(gnpyPathMetricList.stream()
377 .collect(Collectors.toMap(PathMetric::key, pathMetric -> pathMetric)))
380 .setFeasibility(true)
383 return new GnpyResponseBuilder()
385 .setResponseType(null)
386 .setFeasibility(true)