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.util.ArrayList;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.List;
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.rev190624.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;
57 * Class to create the service corresponding to GNPy requirements.
59 * @author Ahmed Triki ( ahmed.triki@orange.com )
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
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;
85 * Construct the GnpyServiceImpl
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();
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);
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();
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);
119 private List<PathRequest> extractPathRequest(PathComputationRequestInput input, AToZDirection atoz, Long requestId,
120 PceConstraints pceHardConstraints) throws GnpyException {
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");
129 // Create explicitRouteObjects
130 List<AToZ> listAtoZ = atoz.getAToZ();
131 if (listAtoZ != null) {
132 extractRouteObjectIcludeAtoZ(listAtoZ);
134 extractHardConstraints(pceHardConstraints);
136 ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder()
137 .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build();
138 //Create Path Constraint
139 PathConstraints pathConstraints = createPathConstraints(atoz.getRate(),atoz.getAToZWavelengthNumber());
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;
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");
160 // Create explicitRouteObjects
161 List<ZToA> listZtoA = ztoa.getZToA();
162 if (listZtoA != null) {
163 extractRouteObjectIcludeZtoA(listZtoA);
165 extractHardConstraints(pceHardConstraints);
167 ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder()
168 .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build();
169 //Create Path Constraint
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;
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());
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());
198 //Create a new resource node or link
199 private void createResource(@Nullable Resource resource) throws GnpyException {
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");
211 addNodeToRouteObject(this.mapDisgNodeRefNode.get(node.getNodeId()));
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());
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);
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());
252 return listNodeToInclude;
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));
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);
276 throw new GnpyException(String.format("In gnpyServiceImpl : NodeRef %s does not exist",nodeRef));
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));
285 //Only the ROADM-to-ROADM link are included in the route object
286 if (!mapLinkFiber.containsKey(linkId)) {
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));
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",
299 RouteObjectIncludeExclude routeObjectIncludeExclude = addRouteObjectIncludeExclude(fiberIp, 1);
300 routeObjectIncludeExcludes.add(routeObjectIncludeExclude);
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;
321 //Create the path constraints
322 private PathConstraints createPathConstraints(Long rate, Long wavelengthNumber) {
323 // Create EffectiveFreqSlot
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);
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;
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)
353 synchro.add(synchronization1);
357 public List<PathRequest> getPathRequest() {
361 public void setPathRequest(List<PathRequest> pathRequest) {
362 this.pathRequest = pathRequest;
365 public List<Synchronization> getSynchronization() {
366 return synchronization;
369 public void setSynchronization(List<Synchronization> synchronization) {
370 this.synchronization = synchronization;