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