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;
18 import org.eclipse.jdt.annotation.NonNull;
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.gnpy.network.topology.rev181214.topo.ElementsKey;
24 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.RouteIncludeEro;
25 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.TeHopType;
26 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.TeNodeId;
27 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.TePathDisjointness;
28 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.TeTpId;
29 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.common.constraints_config.TeBandwidth;
30 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.common.constraints_config.TeBandwidthBuilder;
31 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.explicit.route.hop.Type;
32 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.explicit.route.hop.type.NumUnnumHopBuilder;
33 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.explicit.route.hop.type.num.unnum.hop.NumUnnumHop;
34 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.generic.path.constraints.PathConstraints;
35 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.generic.path.constraints.PathConstraintsBuilder;
36 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.gnpy.specific.parameters.EffectiveFreqSlot;
37 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.gnpy.specific.parameters.EffectiveFreqSlotBuilder;
38 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.path.route.objects.ExplicitRouteObjects;
39 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.path.route.objects.ExplicitRouteObjectsBuilder;
40 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.path.route.objects.explicit.route.objects.RouteObjectIncludeExclude;
41 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.path.route.objects.explicit.route.objects.RouteObjectIncludeExcludeBuilder;
42 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.path.route.objects.explicit.route.objects.RouteObjectIncludeExcludeKey;
43 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.service.PathRequest;
44 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.service.PathRequestBuilder;
45 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.service.PathRequestKey;
46 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.synchronization.info.Synchronization;
47 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.synchronization.info.SynchronizationBuilder;
48 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.synchronization.info.synchronization.Svec;
49 import org.opendaylight.yang.gen.v1.gnpy.path.rev200202.synchronization.info.synchronization.SvecBuilder;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev200128.PathComputationRequestInput;
51 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629.path.description.AToZDirection;
52 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629.path.description.ZToADirection;
53 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629.path.description.atoz.direction.AToZ;
54 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629.path.description.ztoa.direction.ZToA;
55 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629.pce.resource.resource.Resource;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
57 import org.opendaylight.yangtools.yang.common.Uint32;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
62 * Class to create the service corresponding to GNPy requirements.
64 * @author Ahmed Triki ( ahmed.triki@orange.com )
68 public class GnpyServiceImpl {
69 private static final Logger LOG = LoggerFactory.getLogger(GnpyServiceImpl.class);
70 //Fix-grid channel width (THz)
71 private static final double FIX_CH = 0.05;
72 //Number of slot in 50GHz channel (THz)
73 private static final int NB_SLOT_BW = 4;
74 //Nominal central frequency granularity (THz)
75 private static final double SLOT_BW = 0.00625;
76 //Minimum channel center frequency (openRoadm spec) (THz)
77 private static final double MAX_CENTRAL_FREQ = 196.1;
78 //Flex-grid reference channel frequency (THz)
79 private static final double FLEX_CENTRAL_FREQ = 193.1;
81 private static final double CONVERT_TH_HZ = 1e12;
83 private Map<PathRequestKey, PathRequest> pathRequest = new HashMap<>();
84 private List<Synchronization> synchronization = new ArrayList<>();
85 private Map<String, String> mapDisgNodeRefNode = new HashMap<>();
86 private Map<String, IpAddress> mapNodeRefIp = new HashMap<>();
87 private Map<String, List<String>> mapLinkFiber = new HashMap<>();
88 private Map<String, IpAddress> mapFiberIp = new HashMap<>();
89 private List<String> trxList = new ArrayList<>();
90 private Map<ElementsKey, Elements> elements = new HashMap<>();
91 private Map<RouteObjectIncludeExcludeKey,RouteObjectIncludeExclude> routeObjectIncludeExcludes = new HashMap<>();
92 private IpAddress currentNodeIpAddress = null;
95 * Construct the GnpyServiceImpl
97 public GnpyServiceImpl(PathComputationRequestInput input, AToZDirection atoz, Uint32 requestId,
98 GnpyTopoImpl gnpyTopo, PceConstraints pceHardConstraints) throws GnpyException {
99 this.elements = gnpyTopo.getElements();
100 this.mapDisgNodeRefNode = gnpyTopo.getMapDisgNodeRefNode();
101 this.mapNodeRefIp = gnpyTopo.getMapNodeRefIp();
102 this.mapLinkFiber = gnpyTopo.getMapLinkFiber();
103 this.mapFiberIp = gnpyTopo.getMapFiberIp();
104 this.trxList = gnpyTopo.getTrxList();
106 this.pathRequest = extractPathRequest(input, atoz, requestId.toJava(), pceHardConstraints);
107 this.synchronization = extractSynchronization(requestId);
108 } catch (NullPointerException e) {
109 throw new GnpyException("In GnpyServiceImpl: one of the elements is null",e);
113 public GnpyServiceImpl(PathComputationRequestInput input, ZToADirection ztoa, Uint32 requestId,
114 GnpyTopoImpl gnpyTopo, PceConstraints pceHardConstraints) throws GnpyException {
115 this.elements = gnpyTopo.getElements();
116 this.mapDisgNodeRefNode = gnpyTopo.getMapDisgNodeRefNode();
117 this.mapNodeRefIp = gnpyTopo.getMapNodeRefIp();
118 this.mapLinkFiber = gnpyTopo.getMapLinkFiber();
119 this.mapFiberIp = gnpyTopo.getMapFiberIp();
120 this.trxList = gnpyTopo.getTrxList();
122 pathRequest = extractPathRequest(input, ztoa, requestId.toJava(), pceHardConstraints);
123 synchronization = extractSynchronization(requestId);
124 } catch (NullPointerException e) {
125 throw new GnpyException("In GnpyServiceImpl: one of the elements of service is null",e);
129 private Map<PathRequestKey, PathRequest> extractPathRequest(
130 PathComputationRequestInput input, AToZDirection atoz, Long requestId,
131 PceConstraints pceHardConstraints) throws GnpyException {
133 // Create the source and destination nodes
134 String sourceNode = input.getServiceAEnd().getNodeId();
135 String destNode = input.getServiceZEnd().getNodeId();
136 if (!trxList.contains(sourceNode) || !trxList.contains(destNode)) {
137 throw new GnpyException("In GnpyServiceImpl: source and destination should be transmitter nodes");
140 // Create explicitRouteObjects
141 List<AToZ> listAtoZ = new ArrayList<>(atoz.nonnullAToZ().values());
142 if (!listAtoZ.isEmpty()) {
143 extractRouteObjectIcludeAtoZ(listAtoZ);
145 extractHardConstraints(pceHardConstraints);
147 ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder()
148 .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build();
149 //Create Path Constraint
150 Long atozWavelength = null;
151 if (atoz.getAToZWavelengthNumber() != null) {
152 atozWavelength = atoz.getAToZWavelengthNumber().toJava();
154 PathConstraints pathConstraints = createPathConstraints(atoz.getRate().toJava(), atozWavelength);
156 // Create the path request
157 Map<PathRequestKey, PathRequest> pathRequestMap = new HashMap<>();
158 PathRequest pathRequestEl = new PathRequestBuilder().setRequestId(Uint32.valueOf(requestId))
159 .setSource(this.mapNodeRefIp.get(sourceNode)).setDestination(this.mapNodeRefIp.get(destNode))
160 .setSrcTpId("srcTpId".getBytes(StandardCharsets.UTF_8))
161 .setDstTpId("dstTpId".getBytes(StandardCharsets.UTF_8))
162 .setBidirectional(false).setPathConstraints(pathConstraints).setPathConstraints(pathConstraints)
163 .setExplicitRouteObjects(explicitRouteObjects).build();
164 pathRequestMap.put(pathRequestEl.key(),pathRequestEl);
165 LOG.debug("In GnpyServiceImpl: path request AToZ is extracted");
166 return pathRequestMap;
169 private Map<PathRequestKey, PathRequest> extractPathRequest(
170 PathComputationRequestInput input, ZToADirection ztoa, Long requestId,
171 PceConstraints pceHardConstraints) throws GnpyException {
172 // Create the source and destination nodes
173 String sourceNode = input.getServiceZEnd().getNodeId();
174 String destNode = input.getServiceAEnd().getNodeId();
175 if (!trxList.contains(sourceNode) || !trxList.contains(destNode)) {
176 throw new GnpyException("In GnpyServiceImpl: source and destination should be transmitter nodes");
178 // Create explicitRouteObjects
179 @NonNull List<ZToA> listZtoA = new ArrayList<>(ztoa.nonnullZToA().values());
180 if (!listZtoA.isEmpty()) {
181 extractRouteObjectIcludeZtoA(listZtoA);
183 extractHardConstraints(pceHardConstraints);
185 ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder()
186 .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build();
187 //Create Path Constraint
188 Long ztoaWavelength = null;
189 if (ztoa.getZToAWavelengthNumber() != null) {
190 ztoaWavelength = ztoa.getZToAWavelengthNumber().toJava();
192 PathConstraints pathConstraints = createPathConstraints(ztoa.getRate().toJava(), ztoaWavelength);
194 // Create the path request
195 Map<PathRequestKey, PathRequest> pathRequestMap = new HashMap<>();
196 PathRequest pathRequestEl = new PathRequestBuilder().setRequestId(Uint32.valueOf(requestId))
197 .setSource(this.mapNodeRefIp.get(sourceNode)).setDestination(this.mapNodeRefIp.get(destNode))
198 .setSrcTpId("srcTpId".getBytes(StandardCharsets.UTF_8))
199 .setDstTpId("dstTpId".getBytes(StandardCharsets.UTF_8))
200 .setBidirectional(false).setPathConstraints(pathConstraints)
201 .setExplicitRouteObjects(explicitRouteObjects).build();
202 pathRequestMap.put(pathRequestEl.key(),pathRequestEl);
203 LOG.debug("In GnpyServiceImpl: path request ZToA is extracted");
204 return pathRequestMap;
207 //Extract RouteObjectIncludeExclude list in the case of pre-computed path A-to-Z
208 private void extractRouteObjectIcludeAtoZ(List<AToZ> listAtoZ) throws GnpyException {
210 for (AToZ entry : listAtoZ) {
211 index = createResource(entry.getResource().getResource(),index);
215 //Extract RouteObjectIncludeExclude list in the case of pre-computed path Z-to-A
216 private void extractRouteObjectIcludeZtoA(@NonNull List<ZToA> listZtoA) throws GnpyException {
218 for (ZToA entry : listZtoA) {
219 index = createResource(entry.getResource().getResource(),index);
223 //Create a new resource node or link
224 private Long createResource(@Nullable Resource resource, Long index) throws GnpyException {
228 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629
229 .pce.resource.resource.resource.Node) {
230 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629
231 .pce.resource.resource.resource.Node node =
232 (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629
233 .pce.resource.resource.resource.Node) resource;
234 if (node.getNodeId() == null) {
235 throw new GnpyException("In gnpyServiceImpl: nodeId is null");
237 idx = addNodeToRouteObject(this.mapDisgNodeRefNode.get(node.getNodeId()),idx);
242 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629
243 .pce.resource.resource.resource.Link) {
244 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629
245 .pce.resource.resource.resource.Link link =
246 (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev200629
247 .pce.resource.resource.resource.Link) resource;
248 idx = addLinkToRouteObject(link.getLinkId(),idx);
253 //Create RouteObjectIncludeExclude list in the case of hard constraint
254 private void extractHardConstraints(PceConstraints pceHardConstraints) throws GnpyException {
255 List<String> listNodeToInclude = getListToInclude(pceHardConstraints);
256 if (!listNodeToInclude.isEmpty()) {
258 for (int i = 0; i < listNodeToInclude.size(); i++) {
259 String nodeId = listNodeToInclude.get(i);
260 index = addNodeToRouteObject(nodeId, index);
265 // Create the list of nodes to include
266 private List<String> getListToInclude(PceConstraints pceHardConstraints) {
267 List<String> listNodeToInclude = new ArrayList<>();
268 if (pceHardConstraints != null) {
269 List<ResourcePair> listToInclude = pceHardConstraints.getListToInclude();
270 Iterator<ResourcePair> it = listToInclude.iterator();
271 while (it.hasNext()) {
272 ResourcePair rs = it.next();
273 if (rs.getType().name().equals("NODE")) {
274 listNodeToInclude.add(rs.getName());
278 return listNodeToInclude;
281 //Add a node to the route object
282 private Long addNodeToRouteObject(String nodeRef, Long index) throws GnpyException {
284 IpAddress ipAddress = this.mapNodeRefIp.get(nodeRef);
285 if (ipAddress == null) {
286 throw new GnpyException(String.format("In gnpyServiceImpl : NodeRef %s does not exist", nodeRef));
289 for (Elements element : this.elements.values()) {
290 if (element.getUid().contains(ipAddress.getIpv4Address().getValue())) {
291 if ((this.currentNodeIpAddress == null) || (!this.currentNodeIpAddress.equals(ipAddress))) {
292 this.currentNodeIpAddress = ipAddress;
293 RouteObjectIncludeExclude routeObjectIncludeExclude =
294 addRouteObjectIncludeExclude(ipAddress, Uint32.valueOf(1),idx);
295 routeObjectIncludeExcludes.put(routeObjectIncludeExclude.key(),routeObjectIncludeExclude);
301 throw new GnpyException(String.format("In gnpyServiceImpl : NodeRef %s does not exist",nodeRef));
304 //Add a link to the route object
305 private Long addLinkToRouteObject(String linkId, Long index) throws GnpyException {
307 if (linkId == null) {
308 throw new GnpyException("In GnpyServiceImpl: the linkId is null");
310 //Only the ROADM-to-ROADM link are included in the route object
311 if (!mapLinkFiber.containsKey(linkId)) {
314 List<String> listSubLink = this.mapLinkFiber.get(linkId);
315 if (listSubLink == null) {
316 throw new GnpyException(String.format("In gnpyServiceImpl addNodeRouteObject : no sublink in %s",linkId));
318 for (String subLink : listSubLink) {
319 IpAddress fiberIp = this.mapFiberIp.get(subLink);
320 if (fiberIp == null) {
321 throw new GnpyException(String.format("In gnpyServiceImpl addNodeRouteObject : fiberIp of %s is null",
324 RouteObjectIncludeExclude routeObjectIncludeExclude =
325 addRouteObjectIncludeExclude(fiberIp, Uint32.valueOf(1),idx);
326 routeObjectIncludeExcludes.put(routeObjectIncludeExclude.key(),routeObjectIncludeExclude);
332 // Add routeObjectIncludeExclude
333 private RouteObjectIncludeExclude addRouteObjectIncludeExclude(IpAddress ipAddress, Uint32 teTpValue, Long index) {
334 TeNodeId teNodeId = new TeNodeId(ipAddress);
335 TeTpId teTpId = new TeTpId(teTpValue);
336 NumUnnumHop numUnnumHop = new org.opendaylight.yang.gen.v1.gnpy.path.rev200202.explicit.route.hop.type.num
337 .unnum.hop.NumUnnumHopBuilder()
338 .setNodeId(teNodeId.getIpv4Address().getValue())
339 .setLinkTpId(teTpId.getUint32().toString())
340 .setHopType(TeHopType.STRICT).build();
341 Type type1 = new NumUnnumHopBuilder().setNumUnnumHop(numUnnumHop).build();
342 // Create routeObjectIncludeExclude element
343 return new RouteObjectIncludeExcludeBuilder()
344 .setIndex(Uint32.valueOf(index)).setExplicitRouteUsage(RouteIncludeEro.class).setType(type1).build();
347 //Create the path constraints
348 private PathConstraints createPathConstraints(Long rate, Long wavelengthNumber) {
349 // Create EffectiveFreqSlot
351 if (wavelengthNumber != null) {
352 double freq = (MAX_CENTRAL_FREQ - FIX_CH * (wavelengthNumber - 1));
353 freqNdex = (int) Math.round((freq - FLEX_CENTRAL_FREQ) / SLOT_BW);
355 EffectiveFreqSlot effectiveFreqSlot1 = new EffectiveFreqSlotBuilder().setM(NB_SLOT_BW).setN(freqNdex).build();
356 // Create Te-Bandwidth
357 TeBandwidth teBandwidth = new TeBandwidthBuilder().setPathBandwidth(new BigDecimal(rate))
358 .setTechnology("flexi-grid").setTrxType("openroadm-beta1")
359 .setTrxMode("W100G").setEffectiveFreqSlot(Map.of(effectiveFreqSlot1.key(),effectiveFreqSlot1))
360 .setSpacing(BigDecimal.valueOf(FIX_CH * CONVERT_TH_HZ)).build();
361 return new PathConstraintsBuilder().setTeBandwidth(teBandwidth).build();
364 //Create the synchronization
365 private List<Synchronization> extractSynchronization(Uint32 requestId) {
366 // Create RequestIdNumber
367 List<Uint32> requestIdNumber = new ArrayList<>();
368 requestIdNumber.add(requestId);
369 // Create a synchronization
370 Svec svec = new SvecBuilder().setRelaxable(true)
371 .setDisjointness(new TePathDisjointness(true, true, false))
372 .setRequestIdNumber(requestIdNumber).build();
373 List<Synchronization> synchro = new ArrayList<>();
374 Synchronization synchronization1 = new SynchronizationBuilder().setSynchronizationId(Uint32.valueOf(0))
375 .setSvec(svec).build();
376 synchro.add(synchronization1);
380 public Map<PathRequestKey, PathRequest> getPathRequest() {
384 public void setPathRequest(Map<PathRequestKey, PathRequest> pathRequest) {
385 this.pathRequest = pathRequest;
388 public List<Synchronization> getSynchronization() {
389 return synchronization;
392 public void setSynchronization(List<Synchronization> synchronization) {
393 this.synchronization = synchronization;