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 com.google.common.collect.HashBasedTable;
12 import com.google.common.collect.Table;
13 import java.math.BigDecimal;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.List;
22 import java.util.Optional;
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.opendaylight.transportpce.common.ServiceRateConstant;
27 import org.opendaylight.transportpce.common.fixedflex.GridConstant;
28 import org.opendaylight.transportpce.common.fixedflex.GridUtils;
29 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
30 import org.opendaylight.transportpce.pce.constraints.PceConstraints.ResourcePair;
31 import org.opendaylight.transportpce.pce.gnpy.utils.AToZComparator;
32 import org.opendaylight.transportpce.pce.gnpy.utils.ZToAComparator;
33 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.topo.Elements;
34 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.topo.ElementsKey;
35 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.RouteIncludeEro;
36 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.TeHopType;
37 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.TePathDisjointness;
38 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.common.constraints_config.TeBandwidth;
39 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.common.constraints_config.TeBandwidthBuilder;
40 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.explicit.route.hop.Type;
41 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.explicit.route.hop.type.NumUnnumHopBuilder;
42 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.explicit.route.hop.type.num.unnum.hop.NumUnnumHop;
43 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.constraints.PathConstraints;
44 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.constraints.PathConstraintsBuilder;
45 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.gnpy.specific.parameters.EffectiveFreqSlot;
46 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.gnpy.specific.parameters.EffectiveFreqSlotBuilder;
47 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.path.route.objects.ExplicitRouteObjects;
48 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.path.route.objects.ExplicitRouteObjectsBuilder;
49 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.path.route.objects.explicit.route.objects.RouteObjectIncludeExclude;
50 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.path.route.objects.explicit.route.objects.RouteObjectIncludeExcludeBuilder;
51 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.path.route.objects.explicit.route.objects.RouteObjectIncludeExcludeKey;
52 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.service.PathRequest;
53 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.service.PathRequestBuilder;
54 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.service.PathRequestKey;
55 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.synchronization.info.Synchronization;
56 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.synchronization.info.SynchronizationBuilder;
57 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.synchronization.info.synchronization.Svec;
58 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.synchronization.info.synchronization.SvecBuilder;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.PathComputationRequestInput;
60 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.optical.channel.types.rev211210.FrequencyTHz;
61 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev181019.ModulationFormat;
62 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.AToZDirection;
63 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ZToADirection;
64 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.atoz.direction.AToZ;
65 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ztoa.direction.ZToA;
66 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.pce.resource.resource.Resource;
67 import org.opendaylight.yangtools.yang.common.Decimal64;
68 import org.opendaylight.yangtools.yang.common.Uint32;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
74 * Class to create the service corresponding to GNPy requirements.
76 * @author Ahmed Triki ( ahmed.triki@orange.com )
80 public class GnpyServiceImpl {
81 private static final Logger LOG = LoggerFactory.getLogger(GnpyServiceImpl.class);
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, List<String>> mapLinkFiber = new HashMap<>();
87 private List<String> trxList = new ArrayList<>();
88 private Map<ElementsKey, Elements> elements = new HashMap<>();
89 private Map<RouteObjectIncludeExcludeKey, RouteObjectIncludeExclude> routeObjectIncludeExcludes = new HashMap<>();
90 private String currentNodeId = null;
91 private AToZComparator atoZComparator = new AToZComparator();
92 private ZToAComparator ztoAComparator = new ZToAComparator();
93 private static final Table<Uint32, BigDecimal, String> TRX_MODE_TABLE = initTrxModeTable();
95 private static Table<Uint32, BigDecimal, String> initTrxModeTable() {
96 Table<Uint32, BigDecimal, String> trxModeTable = HashBasedTable.create();
97 trxModeTable.put(ServiceRateConstant.RATE_100, GridConstant.SLOT_WIDTH_50, "100 Gbit/s, 27.95 Gbaud, DP-QPSK");
98 trxModeTable.put(ServiceRateConstant.RATE_200, GridConstant.SLOT_WIDTH_50, "200 Gbit/s, 31.57 Gbaud, DP-16QAM");
99 trxModeTable.put(ServiceRateConstant.RATE_200, GridConstant.SLOT_WIDTH_87_5, "200 Gbit/s, DP-QPSK");
100 trxModeTable.put(ServiceRateConstant.RATE_300, GridConstant.SLOT_WIDTH_87_5, "300 Gbit/s, DP-8QAM");
101 trxModeTable.put(ServiceRateConstant.RATE_400, GridConstant.SLOT_WIDTH_87_5, "400 Gbit/s, DP-16QAM");
105 public static final Map<Uint32, BigDecimal> RATE_OUTPUTPOWER = Map.of(
106 ServiceRateConstant.RATE_100, GridConstant.OUTPUT_POWER_100GB_W,
107 ServiceRateConstant.RATE_400, GridConstant.OUTPUT_POWER_400GB_W);
110 * Construct the GnpyServiceImpl
112 public GnpyServiceImpl(PathComputationRequestInput input, AToZDirection atoz, Uint32 requestId,
113 GnpyTopoImpl gnpyTopo, PceConstraints pceHardConstraints) throws GnpyException {
114 this.elements = gnpyTopo.getElements();
115 this.mapDisgNodeRefNode = gnpyTopo.getMapDisgNodeRefNode();
116 this.mapLinkFiber = gnpyTopo.getMapLinkFiber();
117 this.trxList = gnpyTopo.getTrxList();
118 this.pathRequest = extractPathRequest(input, atoz, requestId.toJava(), pceHardConstraints);
119 this.synchronization = extractSynchronization(requestId);
122 public GnpyServiceImpl(PathComputationRequestInput input, ZToADirection ztoa, Uint32 requestId,
123 GnpyTopoImpl gnpyTopo, PceConstraints pceHardConstraints) throws GnpyException {
124 this.elements = gnpyTopo.getElements();
125 this.mapDisgNodeRefNode = gnpyTopo.getMapDisgNodeRefNode();
126 this.mapLinkFiber = gnpyTopo.getMapLinkFiber();
127 this.trxList = gnpyTopo.getTrxList();
128 pathRequest = extractPathRequest(input, ztoa, requestId.toJava(), pceHardConstraints);
129 synchronization = extractSynchronization(requestId);
132 private Map<PathRequestKey, PathRequest> extractPathRequest(
133 PathComputationRequestInput input, AToZDirection atoz, Long requestId,
134 PceConstraints pceHardConstraints) throws GnpyException {
136 // Create the source and destination nodes
137 String sourceNode = input.getServiceAEnd().getNodeId();
138 String destNode = input.getServiceZEnd().getNodeId();
139 if (!trxList.contains(sourceNode) || !trxList.contains(destNode)) {
140 throw new GnpyException("In GnpyServiceImpl: source and destination should be transmitter nodes");
143 // Create explicitRouteObjects
144 List<AToZ> listAtoZ = new ArrayList<>(atoz.nonnullAToZ().values());
145 if (listAtoZ.isEmpty()) {
146 extractHardConstraints(pceHardConstraints);
148 Collections.sort(listAtoZ, atoZComparator);
149 extractRouteObjectIcludeAtoZ(listAtoZ);
152 ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder()
153 .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build();
154 //Create Path Constraint
155 PathConstraints pathConstraints = createPathConstraints(atoz.getRate().toJava(),
156 atoz.getModulationFormat(),
157 atoz.getAToZMinFrequency(),
158 atoz.getAToZMaxFrequency());
160 // Create the path request
161 Map<PathRequestKey, PathRequest> pathRequestMap = new HashMap<>();
162 PathRequest pathRequestEl = new PathRequestBuilder().setRequestId(requestId.toString())
163 .setSource(sourceNode)
164 .setDestination(destNode)
165 .setSrcTpId(sourceNode)
166 .setDstTpId(destNode)
167 .setBidirectional(false).setPathConstraints(pathConstraints).setPathConstraints(pathConstraints)
168 .setExplicitRouteObjects(explicitRouteObjects).build();
169 pathRequestMap.put(pathRequestEl.key(),pathRequestEl);
170 LOG.debug("In GnpyServiceImpl: path request AToZ is extracted");
171 return pathRequestMap;
174 private Map<PathRequestKey, PathRequest> extractPathRequest(
175 PathComputationRequestInput input, ZToADirection ztoa, Long requestId,
176 PceConstraints pceHardConstraints) throws GnpyException {
177 // Create the source and destination nodes
178 String sourceNode = input.getServiceZEnd().getNodeId();
179 String destNode = input.getServiceAEnd().getNodeId();
180 if (!trxList.contains(sourceNode) || !trxList.contains(destNode)) {
181 throw new GnpyException("In GnpyServiceImpl: source and destination should be transmitter nodes");
183 // Create explicitRouteObjects
184 @NonNull List<ZToA> listZtoA = new ArrayList<>(ztoa.nonnullZToA().values());
185 if (listZtoA.isEmpty()) {
186 extractHardConstraints(pceHardConstraints);
188 Collections.sort(listZtoA, ztoAComparator);
189 extractRouteObjectIcludeZtoA(listZtoA);
192 ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder()
193 .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build();
194 //Create Path Constraint
195 PathConstraints pathConstraints = createPathConstraints(ztoa.getRate().toJava(),
196 ztoa.getModulationFormat(),
197 ztoa.getZToAMinFrequency(),
198 ztoa.getZToAMaxFrequency());
200 //Create the path request
201 Map<PathRequestKey, PathRequest> pathRequestMap = new HashMap<>();
202 PathRequest pathRequestEl = new PathRequestBuilder().setRequestId(requestId.toString())
203 .setSource(sourceNode)
204 .setDestination(destNode)
205 .setSrcTpId(sourceNode)
206 .setDstTpId(destNode)
207 .setBidirectional(false).setPathConstraints(pathConstraints)
208 .setExplicitRouteObjects(explicitRouteObjects).build();
209 pathRequestMap.put(pathRequestEl.key(),pathRequestEl);
210 LOG.debug("In GnpyServiceImpl: path request ZToA is extracted is extracted");
211 return pathRequestMap;
214 //Extract RouteObjectIncludeExclude list in the case of pre-computed path A-to-Z
215 private void extractRouteObjectIcludeAtoZ(Collection<AToZ> listAtoZ) throws GnpyException {
217 for (AToZ entry : listAtoZ) {
218 index = createResource(entry.getResource().getResource(),index);
222 //Extract RouteObjectIncludeExclude list in the case of pre-computed path Z-to-A
223 private void extractRouteObjectIcludeZtoA(@NonNull List<ZToA> listZtoA) throws GnpyException {
225 for (ZToA entry : listZtoA) {
226 index = createResource(entry.getResource().getResource(),index);
230 //Create a new resource node or link
231 private Long createResource(@Nullable Resource resource, Long index) throws GnpyException {
235 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
236 .pce.resource.resource.resource.Node) {
237 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
238 .pce.resource.resource.resource.Node node =
239 (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
240 .pce.resource.resource.resource.Node) resource;
241 if (node.getNodeId() == null) {
242 throw new GnpyException("In gnpyServiceImpl: nodeId is null");
244 idx = addNodeToRouteObject(this.mapDisgNodeRefNode.get(node.getNodeId()),idx);
249 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
250 .pce.resource.resource.resource.Link) {
251 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
252 .pce.resource.resource.resource.Link link =
253 (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
254 .pce.resource.resource.resource.Link) resource;
255 idx = addLinkToRouteObject(link.getLinkId(),idx);
260 //Create RouteObjectIncludeExclude list in the case of hard constraint
261 private void extractHardConstraints(PceConstraints pceHardConstraints) throws GnpyException {
262 List<String> listNodeToInclude = getListToInclude(pceHardConstraints);
263 if (!listNodeToInclude.isEmpty()) {
265 for (int i = 0; i < listNodeToInclude.size(); i++) {
266 String nodeId = listNodeToInclude.get(i);
267 index = addNodeToRouteObject(nodeId, index);
272 //Create the list of nodes to include
273 private List<String> getListToInclude(PceConstraints pceHardConstraints) {
274 List<String> listNodeToInclude = new ArrayList<>();
275 if (pceHardConstraints != null) {
276 List<ResourcePair> listToInclude = pceHardConstraints.getListToInclude();
277 Iterator<ResourcePair> it = listToInclude.iterator();
278 while (it.hasNext()) {
279 ResourcePair rs = it.next();
280 if (rs.getType().name().equals("NODE")) {
281 listNodeToInclude.add(rs.getName());
285 return listNodeToInclude;
288 //Add a node to the route object
289 private Long addNodeToRouteObject(String nodeRef, Long index) throws GnpyException {
291 for (Elements element : this.elements.values()) {
292 if (element.getUid().equals(nodeRef)) {
293 if ((this.currentNodeId == null) || (!this.currentNodeId.equals(nodeRef))) {
294 this.currentNodeId = nodeRef;
295 RouteObjectIncludeExclude routeObjectIncludeExclude = addRouteObjectIncludeExclude(nodeRef,
296 Uint32.valueOf(1), idx);
297 RouteObjectIncludeExcludeKey key = new RouteObjectIncludeExcludeKey(Uint32.valueOf(idx));
298 routeObjectIncludeExcludes.put(key, routeObjectIncludeExclude);
304 throw new GnpyException(String.format("In gnpyServiceImpl : NodeRef %s does not exist",nodeRef));
307 //Add a link to the route object
308 private Long addLinkToRouteObject(String linkId, Long index) throws GnpyException {
310 if (linkId == null) {
311 throw new GnpyException("In GnpyServiceImpl: the linkId is null");
313 //Only the ROADM-to-ROADM link are included in the route object
314 if (!mapLinkFiber.containsKey(linkId)) {
317 List<String> listSubLink = this.mapLinkFiber.get(linkId);
318 if (listSubLink == null) {
319 throw new GnpyException(String.format("In gnpyServiceImpl addNodeRouteObject : no sublink in %s",linkId));
321 for (String subLink : listSubLink) {
322 RouteObjectIncludeExclude routeObjectIncludeExclude =
323 addRouteObjectIncludeExclude(subLink, Uint32.valueOf(1),idx);
324 RouteObjectIncludeExcludeKey key = new RouteObjectIncludeExcludeKey(Uint32.valueOf(idx));
325 routeObjectIncludeExcludes.put(key, routeObjectIncludeExclude);
331 // Add routeObjectIncludeExclude
332 private RouteObjectIncludeExclude addRouteObjectIncludeExclude(String nodeId, Uint32 teTpValue, Long index) {
333 NumUnnumHop numUnnumHop = new org.opendaylight.yang.gen.v1.gnpy.path.rev220615.explicit.route.hop.type.num
334 .unnum.hop.NumUnnumHopBuilder()
336 .setLinkTpId(teTpValue.toString())
337 .setHopType(TeHopType.STRICT).build();
338 Type type1 = new NumUnnumHopBuilder().setNumUnnumHop(numUnnumHop).build();
339 // Create routeObjectIncludeExclude element
340 return new RouteObjectIncludeExcludeBuilder()
341 .setIndex(Uint32.valueOf(index)).setExplicitRouteUsage(RouteIncludeEro.class).setType(type1).build();
344 //Create the path constraints
345 private PathConstraints createPathConstraints(Long rate, String modulationFormat, FrequencyTHz minFrequency,
346 FrequencyTHz maxFrequency) {
347 BigDecimal spacing = GridConstant.SLOT_WIDTH_50;
348 int mvalue = GridConstant.NB_SLOTS_100G;
350 if (minFrequency != null && maxFrequency != null && modulationFormat != null) {
351 LOG.info("Creating path constraints for rate {}, modulationFormat {}, min freq {}, max freq {}", rate,
352 modulationFormat, minFrequency, maxFrequency);
353 ModulationFormat mformat = ModulationFormat.DpQpsk;
354 Optional<ModulationFormat> optionalModulationFormat = ModulationFormat.forName(modulationFormat);
355 if (optionalModulationFormat.isPresent()) {
356 mformat = optionalModulationFormat.get();
358 spacing = GridConstant.FREQUENCY_SLOT_WIDTH_TABLE.get(Uint32.valueOf(rate), mformat);
359 FrequencyTHz centralFrequency = GridUtils.getCentralFrequency(
360 minFrequency.getValue().decimalValue(),
361 maxFrequency.getValue().decimalValue());
362 int centralFrequencyBitSetIndex = GridUtils.getIndexFromFrequency(centralFrequency.getValue());
363 mvalue = (int) Math.ceil(spacing.doubleValue() / (GridConstant.GRANULARITY));
364 nvalue = GridUtils.getNFromFrequencyIndex(centralFrequencyBitSetIndex);
366 LOG.info("Creating path constraints for rate {}, mvalue {}, nvalue {}, spacing {}", rate,
367 mvalue, nvalue, spacing);
368 EffectiveFreqSlot effectiveFreqSlot = new EffectiveFreqSlotBuilder()
369 .setM(Uint32.valueOf(mvalue / 2)).setN(nvalue).build();
371 TeBandwidth teBandwidth = new TeBandwidthBuilder()
372 .setPathBandwidth(Decimal64.valueOf(BigDecimal.valueOf(rate * 1e9)))
373 .setTechnology("flexi-grid").setTrxType("OpenROADM MSA ver. 5.0")
374 .setTrxMode(TRX_MODE_TABLE.get(Uint32.valueOf(rate), spacing))
375 .setOutputPower(Decimal64.valueOf(GridUtils.convertDbmW(GridConstant.OUTPUT_POWER_100GB_DBM
376 + 10 * Math.log10(mvalue / (double)GridConstant.NB_SLOTS_100G))))
377 .setEffectiveFreqSlot(Map.of(effectiveFreqSlot.key(), effectiveFreqSlot))
378 .setSpacing(Decimal64.valueOf(spacing.multiply(BigDecimal.valueOf(1e9))))
380 return new PathConstraintsBuilder().setTeBandwidth(teBandwidth).build();
383 //Create the synchronization
384 private List<Synchronization> extractSynchronization(Uint32 requestId) {
385 // Create RequestIdNumber
386 Set<String> requestIdNumber = new HashSet<>();
387 requestIdNumber.add(requestId.toString());
388 // Create a synchronization
389 Svec svec = new SvecBuilder().setRelaxable(true)
390 .setDisjointness(new TePathDisjointness(true, true, false))
391 .setRequestIdNumber(requestIdNumber).build();
392 List<Synchronization> synchro = new ArrayList<>();
393 Synchronization synchronization1 = new SynchronizationBuilder()
394 .setSynchronizationId(Uint32.valueOf(0).toString())
395 .setSvec(svec).build();
396 synchro.add(synchronization1);
400 public Map<PathRequestKey, PathRequest> getPathRequest() {
404 public void setPathRequest(Map<PathRequestKey, PathRequest> pathRequest) {
405 this.pathRequest = pathRequest;
408 public List<Synchronization> getSynchronization() {
409 return synchronization;
412 public void setSynchronization(List<Synchronization> synchronization) {
413 this.synchronization = synchronization;