Sho SHIMIZU
Committed by Gerrit Code Review

Separate resource search from resource allocation

This is a preparation task for the future Intent Framework major
enhancement that aims to consolidate resource allocation invocations
into the Framework side instead of the compiler side.

Declaring required resources and allocating the resources need to be
clearly separated. This patch tries to separate these phases.

Change-Id: Id254fe103803daf60ef2576fb5d717e9faa68c03
...@@ -97,7 +97,7 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical ...@@ -97,7 +97,7 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
97 @Override 97 @Override
98 public List<Intent> compile(OpticalConnectivityIntent intent, 98 public List<Intent> compile(OpticalConnectivityIntent intent,
99 List<Intent> installable, 99 List<Intent> installable,
100 - Set<LinkResourceAllocations> resources) { 100 + Set<LinkResourceAllocations> linkResources) {
101 // Check if source and destination are optical OCh ports 101 // Check if source and destination are optical OCh ports
102 ConnectPoint src = intent.getSrc(); 102 ConnectPoint src = intent.getSrc();
103 ConnectPoint dst = intent.getDst(); 103 ConnectPoint dst = intent.getDst();
...@@ -113,94 +113,117 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical ...@@ -113,94 +113,117 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
113 // TODO: try to release intent resources in IntentManager. 113 // TODO: try to release intent resources in IntentManager.
114 resourceService.release(intent.id()); 114 resourceService.release(intent.id());
115 115
116 - // Reserve OCh ports 116 + // Check OCh port availability
117 Resource srcPortResource = Resources.discrete(src.deviceId(), src.port()).resource(); 117 Resource srcPortResource = Resources.discrete(src.deviceId(), src.port()).resource();
118 Resource dstPortResource = Resources.discrete(dst.deviceId(), dst.port()).resource(); 118 Resource dstPortResource = Resources.discrete(dst.deviceId(), dst.port()).resource();
119 - List<ResourceAllocation> allocation = resourceService.allocate(intent.id(), srcPortResource, dstPortResource); 119 + // If ports are not available, compilation fails
120 - if (allocation.isEmpty()) { 120 + if (!Stream.of(srcPortResource, dstPortResource).allMatch(resourceService::isAvailable)) {
121 - throw new IntentCompilationException("Unable to reserve ports for intent " + intent); 121 + throw new IntentCompilationException("Ports for the intent are not available. Intent: " + intent);
122 } 122 }
123 123
124 + List<Resource> resources = new ArrayList<>();
125 + resources.add(srcPortResource);
126 + resources.add(dstPortResource);
127 +
124 // Calculate available light paths 128 // Calculate available light paths
125 Set<Path> paths = getOpticalPaths(intent); 129 Set<Path> paths = getOpticalPaths(intent);
126 130
131 + if (paths.isEmpty()) {
132 + throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent);
133 + }
134 +
127 // Static or dynamic lambda allocation 135 // Static or dynamic lambda allocation
128 String staticLambda = srcPort.annotations().value(AnnotationKeys.STATIC_LAMBDA); 136 String staticLambda = srcPort.annotations().value(AnnotationKeys.STATIC_LAMBDA);
129 OchPort srcOchPort = (OchPort) srcPort; 137 OchPort srcOchPort = (OchPort) srcPort;
130 OchPort dstOchPort = (OchPort) dstPort; 138 OchPort dstOchPort = (OchPort) dstPort;
131 - OchSignal ochSignal;
132 -
133 - // Use first path that can be successfully reserved
134 - for (Path path : paths) {
135 139
140 + Path firstPath = paths.iterator().next();
136 // FIXME: need to actually reserve the lambda for static lambda's 141 // FIXME: need to actually reserve the lambda for static lambda's
142 + // static lambda case: early return
137 if (staticLambda != null) { 143 if (staticLambda != null) {
138 - ochSignal = new OchSignal(Frequency.ofHz(Long.parseLong(staticLambda)), 144 + allocateResources(intent, resources);
145 +
146 + OchSignal lambda = new OchSignal(Frequency.ofHz(Long.parseLong(staticLambda)),
139 srcOchPort.lambda().channelSpacing(), 147 srcOchPort.lambda().channelSpacing(),
140 srcOchPort.lambda().slotGranularity()); 148 srcOchPort.lambda().slotGranularity());
141 - } else if (!srcOchPort.isTunable() || !dstOchPort.isTunable()) { 149 + return ImmutableList.of(createIntent(intent, firstPath, lambda));
150 + }
151 +
142 // FIXME: also check destination OCh port 152 // FIXME: also check destination OCh port
143 - ochSignal = srcOchPort.lambda(); 153 + // non-tunable case: early return
144 - } else { 154 + if (!srcOchPort.isTunable() || !dstOchPort.isTunable()) {
145 - // Request and reserve lambda on path 155 + allocateResources(intent, resources);
146 - List<OchSignal> lambdas = assignWavelength(intent, path); 156 +
147 - if (lambdas.isEmpty()) { 157 + OchSignal lambda = srcOchPort.lambda();
158 + return ImmutableList.of(createIntent(intent, firstPath, lambda));
159 + }
160 +
161 + // Use first path that can be successfully reserved
162 + for (Path path : paths) {
163 + // find common lambda on path
164 + // a list of OchSignal indicates consecutive OchSignals
165 + List<OchSignal> lambda = findFirstAvailableOch(path);
166 + if (lambda.isEmpty()) {
167 + continue;
168 + }
169 + List<Resource> lambdaResources = convertToResources(path.links(), lambda);
170 + if (!lambdaResources.stream().allMatch(resourceService::isAvailable)) {
148 continue; 171 continue;
149 } 172 }
150 - ochSignal = OchSignal.toFixedGrid(lambdas, ChannelSpacing.CHL_50GHZ); 173 + resources.addAll(lambdaResources);
174 +
175 + allocateResources(intent, resources);
176 +
177 + OchSignal ochSignal = OchSignal.toFixedGrid(lambda, ChannelSpacing.CHL_50GHZ);
178 + return ImmutableList.of(createIntent(intent, path, ochSignal));
179 + }
180 +
181 + throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent);
151 } 182 }
152 183
184 + private Intent createIntent(OpticalConnectivityIntent parentIntent, Path path, OchSignal lambda) {
153 // Create installable optical path intent 185 // Create installable optical path intent
154 // Only support fixed grid for now 186 // Only support fixed grid for now
155 OchSignalType signalType = OchSignalType.FIXED_GRID; 187 OchSignalType signalType = OchSignalType.FIXED_GRID;
156 188
157 - Intent newIntent = OpticalPathIntent.builder() 189 + return OpticalPathIntent.builder()
158 - .appId(intent.appId()) 190 + .appId(parentIntent.appId())
159 - .src(intent.getSrc()) 191 + .src(parentIntent.getSrc())
160 - .dst(intent.getDst()) 192 + .dst(parentIntent.getDst())
193 + // calling paths.iterator().next() is safe because of non-empty set
161 .path(path) 194 .path(path)
162 - .lambda(ochSignal) 195 + .lambda(lambda)
163 .signalType(signalType) 196 .signalType(signalType)
164 - .bidirectional(intent.isBidirectional()) 197 + .bidirectional(parentIntent.isBidirectional())
165 .build(); 198 .build();
166 -
167 - return ImmutableList.of(newIntent);
168 } 199 }
169 200
170 - // Release port allocations if unsuccessful 201 + private void allocateResources(Intent intent, List<Resource> resources) {
171 - resourceService.release(intent.id()); 202 + // reserve all of required resources
172 - 203 + List<ResourceAllocation> allocations = resourceService.allocate(intent.id(), resources);
173 - throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent); 204 + if (allocations.isEmpty()) {
205 + log.info("Resource allocation for {} failed (resource request: {})", intent, resources);
206 + throw new IntentCompilationException("Unable to allocate resources: " + resources);
207 + }
174 } 208 }
175 209
176 - /** 210 + private List<OchSignal> findFirstAvailableOch(Path path) {
177 - * Request and reserve first available wavelength across path.
178 - *
179 - * @param path path in WDM topology
180 - * @return first available lambda allocated
181 - */
182 - private List<OchSignal> assignWavelength(Intent intent, Path path) {
183 Set<OchSignal> lambdas = findCommonLambdasOverLinks(path.links()); 211 Set<OchSignal> lambdas = findCommonLambdasOverLinks(path.links());
184 if (lambdas.isEmpty()) { 212 if (lambdas.isEmpty()) {
185 return Collections.emptyList(); 213 return Collections.emptyList();
186 } 214 }
187 215
188 - List<OchSignal> minLambda = findFirstLambda(lambdas, slotCount()); 216 + return findFirstLambda(lambdas, slotCount());
189 - List<Resource> lambdaResources = path.links().stream() 217 + }
218 +
219 + private List<Resource> convertToResources(List<Link> links, List<OchSignal> lambda) {
220 + return links.stream()
190 .flatMap(x -> Stream.of( 221 .flatMap(x -> Stream.of(
191 Resources.discrete(x.src().deviceId(), x.src().port()).resource(), 222 Resources.discrete(x.src().deviceId(), x.src().port()).resource(),
192 Resources.discrete(x.dst().deviceId(), x.dst().port()).resource() 223 Resources.discrete(x.dst().deviceId(), x.dst().port()).resource()
193 )) 224 ))
194 - .flatMap(x -> minLambda.stream().map(l -> x.child(l))) 225 + .flatMap(x -> lambda.stream().map(x::child))
195 .collect(Collectors.toList()); 226 .collect(Collectors.toList());
196 -
197 - List<ResourceAllocation> allocations = resourceService.allocate(intent.id(), lambdaResources);
198 - if (allocations.isEmpty()) {
199 - log.info("Resource allocation for {} failed (resource request: {})", intent, lambdaResources);
200 - return Collections.emptyList();
201 - }
202 -
203 - return minLambda;
204 } 227 }
205 228
206 /** 229 /**
......