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