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