2 * Copyright © 2019 Orange, 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
9 package org.opendaylight.transportpce.pce.gnpy;
11 import java.math.BigDecimal;
12 import java.nio.charset.StandardCharsets;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
21 import org.opendaylight.transportpce.pce.constraints.PceConstraints.ResourcePair;
22 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.Elements;
23 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.RouteIncludeEro;
24 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.TeHopType;
25 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.TeNodeId;
26 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.TePathDisjointness;
27 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.TeTpId;
28 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.common.constraints_config.TeBandwidth;
29 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.common.constraints_config.TeBandwidthBuilder;
30 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.explicit.route.hop.Type;
31 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.explicit.route.hop.type.NumUnnumHopBuilder;
32 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.explicit.route.hop.type.num.unnum.hop.NumUnnumHop;
33 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.generic.path.constraints.PathConstraints;
34 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.generic.path.constraints.PathConstraintsBuilder;
35 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.gnpy.specific.parameters.EffectiveFreqSlot;
36 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.gnpy.specific.parameters.EffectiveFreqSlotBuilder;
37 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.path.route.objects.ExplicitRouteObjects;
38 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.path.route.objects.ExplicitRouteObjectsBuilder;
39 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.path.route.objects.explicit.route.objects.RouteObjectIncludeExclude;
40 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.path.route.objects.explicit.route.objects.RouteObjectIncludeExcludeBuilder;
41 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.service.PathRequest;
42 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.service.PathRequestBuilder;
43 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.synchronization.info.Synchronization;
44 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.synchronization.info.SynchronizationBuilder;
45 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.synchronization.info.synchronization.Svec;
46 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.synchronization.info.synchronization.SvecBuilder;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev200128.PathComputationRequestInput;
48 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.AToZDirection;
49 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.ZToADirection;
50 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.atoz.direction.AToZ;
51 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.ztoa.direction.ZToA;
52 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.pce.resource.resource.Resource;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
54 import org.opendaylight.yangtools.yang.common.Uint32;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
59 * Class to create the service corresponding to GNPy requirements.
61 * @author Ahmed Triki ( ahmed.triki@orange.com )
65 public class GnpyServiceImpl {
66 private static final Logger LOG = LoggerFactory.getLogger(GnpyServiceImpl.class);
67 //Fix-grid channel width (THz)
68 private static final double FIX_CH = 0.05;
69 //Number of slot in 50GHz channel (THz)
70 private static final int NB_SLOT_BW = 4;
71 //Nominal central frequency granularity (THz)
72 private static final double SLOT_BW = 0.00625;
73 //Minimum channel center frequency (openRoadm spec) (THz)
74 private static final double MAX_CENTRAL_FREQ = 196.1;
75 //Flex-grid reference channel frequency (THz)
76 private static final double FLEX_CENTRAL_FREQ = 193.1;
78 private static final double CONVERT_TH_HZ = 1e12;
80 private List<PathRequest> pathRequest = new ArrayList<>();
81 private List<Synchronization> synchronization = new ArrayList<>();
82 private Map<String, String> mapDisgNodeRefNode = new HashMap<>();
83 private Map<String, IpAddress> mapNodeRefIp = new HashMap<>();
84 private Map<String, List<String>> mapLinkFiber = new HashMap<>();
85 private Map<String, IpAddress> mapFiberIp = new HashMap<>();
86 private List<String> trxList = new ArrayList<>();
87 private List<Elements> elements = new ArrayList<>();
88 private List<RouteObjectIncludeExclude> routeObjectIncludeExcludes = new ArrayList<>();
89 private IpAddress currentNodeIpAddress = null;
92 * Construct the GnpyServiceImpl
94 public GnpyServiceImpl(PathComputationRequestInput input, AToZDirection atoz, Uint32 requestId,
95 GnpyTopoImpl gnpyTopo, PceConstraints pceHardConstraints) throws GnpyException {
96 this.elements = gnpyTopo.getElements();
97 this.mapDisgNodeRefNode = gnpyTopo.getMapDisgNodeRefNode();
98 this.mapNodeRefIp = gnpyTopo.getMapNodeRefIp();
99 this.mapLinkFiber = gnpyTopo.getMapLinkFiber();
100 this.mapFiberIp = gnpyTopo.getMapFiberIp();
101 this.trxList = gnpyTopo.getTrxList();
103 this.pathRequest = extractPathRequest(input, atoz, requestId.toJava(), pceHardConstraints);
104 this.synchronization = extractSynchronization(requestId);
105 } catch (NullPointerException e) {
106 throw new GnpyException("In GnpyServiceImpl: one of the elements is null",e);
110 public GnpyServiceImpl(PathComputationRequestInput input, ZToADirection ztoa, Uint32 requestId,
111 GnpyTopoImpl gnpyTopo, PceConstraints pceHardConstraints) throws GnpyException {
112 this.elements = gnpyTopo.getElements();
113 this.mapDisgNodeRefNode = gnpyTopo.getMapDisgNodeRefNode();
114 this.mapNodeRefIp = gnpyTopo.getMapNodeRefIp();
115 this.mapLinkFiber = gnpyTopo.getMapLinkFiber();
116 this.mapFiberIp = gnpyTopo.getMapFiberIp();
117 this.trxList = gnpyTopo.getTrxList();
119 pathRequest = extractPathRequest(input, ztoa, requestId.toJava(), pceHardConstraints);
120 synchronization = extractSynchronization(requestId);
121 } catch (NullPointerException e) {
122 throw new GnpyException("In GnpyServiceImpl: one of the elements of service is null",e);
126 private List<PathRequest> extractPathRequest(PathComputationRequestInput input, AToZDirection atoz, Long requestId,
127 PceConstraints pceHardConstraints) throws GnpyException {
129 // Create the source and destination nodes
130 String sourceNode = input.getServiceAEnd().getNodeId();
131 String destNode = input.getServiceZEnd().getNodeId();
132 if (!trxList.contains(sourceNode) || !trxList.contains(destNode)) {
133 throw new GnpyException("In GnpyServiceImpl: source and destination should be transmitter nodes");
136 // Create explicitRouteObjects
137 List<AToZ> listAtoZ = atoz.getAToZ();
138 if (listAtoZ != null) {
139 extractRouteObjectIcludeAtoZ(listAtoZ);
141 extractHardConstraints(pceHardConstraints);
143 ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder()
144 .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build();
145 //Create Path Constraint
146 Long atozWavelength = null;
147 if (atoz.getAToZWavelengthNumber() != null) {
148 atozWavelength = atoz.getAToZWavelengthNumber().toJava();
150 PathConstraints pathConstraints = createPathConstraints(atoz.getRate().toJava(), atozWavelength);
152 // Create the path request
153 List<PathRequest> pathRequestList = new ArrayList<>();
154 PathRequest pathRequestEl = new PathRequestBuilder().setRequestId(requestId)
155 .setSource(this.mapNodeRefIp.get(sourceNode)).setDestination(this.mapNodeRefIp.get(destNode))
156 .setSrcTpId("srcTpId".getBytes(StandardCharsets.UTF_8))
157 .setDstTpId("dstTpId".getBytes(StandardCharsets.UTF_8))
158 .setBidirectional(false).setPathConstraints(pathConstraints).setPathConstraints(pathConstraints)
159 .setExplicitRouteObjects(explicitRouteObjects).build();
160 pathRequestList.add(pathRequestEl);
161 LOG.debug("In GnpyServiceImpl: path request AToZ is extracted");
162 return pathRequestList;
165 private List<PathRequest> extractPathRequest(PathComputationRequestInput input, ZToADirection ztoa, Long requestId,
166 PceConstraints pceHardConstraints) throws GnpyException {
167 // Create the source and destination nodes
168 String sourceNode = input.getServiceZEnd().getNodeId();
169 String destNode = input.getServiceAEnd().getNodeId();
170 if (!trxList.contains(sourceNode) || !trxList.contains(destNode)) {
171 throw new GnpyException("In GnpyServiceImpl: source and destination should be transmitter nodes");
173 // Create explicitRouteObjects
174 List<ZToA> listZtoA = ztoa.getZToA();
175 if (listZtoA != null) {
176 extractRouteObjectIcludeZtoA(listZtoA);
178 extractHardConstraints(pceHardConstraints);
180 ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder()
181 .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build();
182 //Create Path Constraint
183 Long ztoaWavelength = null;
184 if (ztoa.getZToAWavelengthNumber() != null) {
185 ztoaWavelength = ztoa.getZToAWavelengthNumber().toJava();
187 PathConstraints pathConstraints = createPathConstraints(ztoa.getRate().toJava(), ztoaWavelength);
189 // Create the path request
190 List<PathRequest> pathRequestList = new ArrayList<>();
191 PathRequest pathRequestEl = new PathRequestBuilder().setRequestId(requestId)
192 .setSource(this.mapNodeRefIp.get(sourceNode)).setDestination(this.mapNodeRefIp.get(destNode))
193 .setSrcTpId("srcTpId".getBytes(StandardCharsets.UTF_8))
194 .setDstTpId("dstTpId".getBytes(StandardCharsets.UTF_8))
195 .setBidirectional(false).setPathConstraints(pathConstraints)
196 .setExplicitRouteObjects(explicitRouteObjects).build();
197 pathRequestList.add(pathRequestEl);
198 LOG.debug("In GnpyServiceImpl: path request ZToA is extracted");
199 return pathRequestList;
202 //Extract RouteObjectIncludeExclude list in the case of pre-computed path A-to-Z
203 private void extractRouteObjectIcludeAtoZ(List<AToZ> listAtoZ) throws GnpyException {
205 for (int i = 0; i < listAtoZ.size(); i++) {
206 index = createResource(listAtoZ.get(i).getResource().getResource(),index);
210 //Extract RouteObjectIncludeExclude list in the case of pre-computed path Z-to-A
211 private void extractRouteObjectIcludeZtoA(List<ZToA> listZtoA) throws GnpyException {
213 for (int i = 0; i < listZtoA.size(); i++) {
214 index = createResource(listZtoA.get(i).getResource().getResource(),index);
218 //Create a new resource node or link
219 private Long createResource(@Nullable Resource resource, Long index) throws GnpyException {
223 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017
224 .pce.resource.resource.resource.Node) {
225 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017
226 .pce.resource.resource.resource.Node node =
227 (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017
228 .pce.resource.resource.resource.Node) resource;
229 if (node.getNodeId() == null) {
230 throw new GnpyException("In gnpyServiceImpl: nodeId is null");
232 idx = addNodeToRouteObject(this.mapDisgNodeRefNode.get(node.getNodeId()),idx);
237 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017
238 .pce.resource.resource.resource.Link) {
239 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017
240 .pce.resource.resource.resource.Link link =
241 (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017
242 .pce.resource.resource.resource.Link) resource;
243 idx = addLinkToRouteObject(link.getLinkId(),idx);
248 //Create RouteObjectIncludeExclude list in the case of hard constraint
249 private void extractHardConstraints(PceConstraints pceHardConstraints) throws GnpyException {
250 List<String> listNodeToInclude = getListToInclude(pceHardConstraints);
251 if (!listNodeToInclude.isEmpty()) {
253 for (int i = 0; i < listNodeToInclude.size(); i++) {
254 String nodeId = listNodeToInclude.get(i);
255 index = addNodeToRouteObject(nodeId, index);
260 // Create the list of nodes to include
261 private List<String> getListToInclude(PceConstraints pceHardConstraints) {
262 List<String> listNodeToInclude = new ArrayList<>();
263 if (pceHardConstraints != null) {
264 List<ResourcePair> listToInclude = pceHardConstraints.getListToInclude();
265 Iterator<ResourcePair> it = listToInclude.iterator();
266 while (it.hasNext()) {
267 ResourcePair rs = it.next();
268 if (rs.getType().name().equals("NODE")) {
269 listNodeToInclude.add(rs.getName());
273 return listNodeToInclude;
276 //Add a node to the route object
277 private Long addNodeToRouteObject(String nodeRef, Long index) throws GnpyException {
279 IpAddress ipAddress = this.mapNodeRefIp.get(nodeRef);
280 if (ipAddress == null) {
281 throw new GnpyException(String.format("In gnpyServiceImpl : NodeRef %s does not exist", nodeRef));
284 for (Elements element : this.elements) {
285 if (element.getUid().contains(ipAddress.getIpv4Address().getValue())) {
286 if ((this.currentNodeIpAddress == null) || (!this.currentNodeIpAddress.equals(ipAddress))) {
287 this.currentNodeIpAddress = ipAddress;
288 RouteObjectIncludeExclude routeObjectIncludeExclude =
289 addRouteObjectIncludeExclude(ipAddress, Uint32.valueOf(1),idx);
290 routeObjectIncludeExcludes.add(routeObjectIncludeExclude);
296 throw new GnpyException(String.format("In gnpyServiceImpl : NodeRef %s does not exist",nodeRef));
299 //Add a link to the route object
300 private Long addLinkToRouteObject(String linkId, Long index) throws GnpyException {
302 if (linkId == null) {
303 throw new GnpyException("In GnpyServiceImpl: the linkId is null");
305 //Only the ROADM-to-ROADM link are included in the route object
306 if (!mapLinkFiber.containsKey(linkId)) {
309 List<String> listSubLink = this.mapLinkFiber.get(linkId);
310 if (listSubLink == null) {
311 throw new GnpyException(String.format("In gnpyServiceImpl addNodeRouteObject : no sublink in %s",linkId));
313 for (String subLink : listSubLink) {
314 IpAddress fiberIp = this.mapFiberIp.get(subLink);
315 if (fiberIp == null) {
316 throw new GnpyException(String.format("In gnpyServiceImpl addNodeRouteObject : fiberIp of %s is null",
319 RouteObjectIncludeExclude routeObjectIncludeExclude =
320 addRouteObjectIncludeExclude(fiberIp, Uint32.valueOf(1),idx);
321 routeObjectIncludeExcludes.add(routeObjectIncludeExclude);
327 // Add routeObjectIncludeExclude
328 private RouteObjectIncludeExclude addRouteObjectIncludeExclude(IpAddress ipAddress, Uint32 teTpValue, Long index) {
329 TeNodeId teNodeId = new TeNodeId(ipAddress);
330 TeTpId teTpId = new TeTpId(teTpValue);
331 NumUnnumHop numUnnumHop = new org.opendaylight.yang.gen.v1.gnpy.path.rev200202.explicit.route.hop.type.num
332 .unnum.hop.NumUnnumHopBuilder()
333 .setNodeId(teNodeId.getIpv4Address().getValue())
334 .setLinkTpId(teTpId.getUint32().toString())
335 .setHopType(TeHopType.STRICT).build();
336 Type type1 = new NumUnnumHopBuilder().setNumUnnumHop(numUnnumHop).build();
337 // Create routeObjectIncludeExclude element
338 return new RouteObjectIncludeExcludeBuilder()
339 .setIndex(index).setExplicitRouteUsage(RouteIncludeEro.class).setType(type1).build();
342 //Create the path constraints
343 private PathConstraints createPathConstraints(Long rate, Long wavelengthNumber) {
344 // Create EffectiveFreqSlot
346 if (wavelengthNumber != null) {
347 double freq = (MAX_CENTRAL_FREQ - FIX_CH * (wavelengthNumber - 1));
348 freqNdex = (int) Math.round((freq - FLEX_CENTRAL_FREQ) / SLOT_BW);
350 List<EffectiveFreqSlot> effectiveFreqSlot = new ArrayList<>();
351 EffectiveFreqSlot effectiveFreqSlot1 = new EffectiveFreqSlotBuilder().setM(NB_SLOT_BW).setN(freqNdex).build();
352 effectiveFreqSlot.add(effectiveFreqSlot1);
353 // Create Te-Bandwidth
354 TeBandwidth teBandwidth = new TeBandwidthBuilder().setPathBandwidth(new BigDecimal(rate))
355 .setTechnology("flexi-grid").setTrxType("openroadm-beta1")
356 .setTrxMode("W100G").setEffectiveFreqSlot(effectiveFreqSlot)
357 .setSpacing(BigDecimal.valueOf(FIX_CH * CONVERT_TH_HZ)).build();
358 return new PathConstraintsBuilder().setTeBandwidth(teBandwidth).build();
361 //Create the synchronization
362 private List<Synchronization> extractSynchronization(Uint32 requestId) {
363 // Create RequestIdNumber
364 List<Uint32> requestIdNumber = new ArrayList<>();
365 requestIdNumber.add(requestId);
366 // Create a synchronization
367 Svec svec = new SvecBuilder().setRelaxable(true)
368 .setDisjointness(new TePathDisjointness(true, true, false))
369 .setRequestIdNumber(requestIdNumber).build();
370 List<Synchronization> synchro = new ArrayList<>();
371 Synchronization synchronization1 = new SynchronizationBuilder().setSynchronizationId(Long.valueOf(0))
372 .setSvec(svec).build();
373 synchro.add(synchronization1);
377 public List<PathRequest> getPathRequest() {
381 public void setPathRequest(List<PathRequest> pathRequest) {
382 this.pathRequest = pathRequest;
385 public List<Synchronization> getSynchronization() {
386 return synchronization;
389 public void setSynchronization(List<Synchronization> synchronization) {
390 this.synchronization = synchronization;