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
Showing
1 changed file
with
81 additions
and
58 deletions
... | @@ -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; | 139 | + |
140 | + Path firstPath = paths.iterator().next(); | ||
141 | + // FIXME: need to actually reserve the lambda for static lambda's | ||
142 | + // static lambda case: early return | ||
143 | + if (staticLambda != null) { | ||
144 | + allocateResources(intent, resources); | ||
145 | + | ||
146 | + OchSignal lambda = new OchSignal(Frequency.ofHz(Long.parseLong(staticLambda)), | ||
147 | + srcOchPort.lambda().channelSpacing(), | ||
148 | + srcOchPort.lambda().slotGranularity()); | ||
149 | + return ImmutableList.of(createIntent(intent, firstPath, lambda)); | ||
150 | + } | ||
151 | + | ||
152 | + // FIXME: also check destination OCh port | ||
153 | + // non-tunable case: early return | ||
154 | + if (!srcOchPort.isTunable() || !dstOchPort.isTunable()) { | ||
155 | + allocateResources(intent, resources); | ||
156 | + | ||
157 | + OchSignal lambda = srcOchPort.lambda(); | ||
158 | + return ImmutableList.of(createIntent(intent, firstPath, lambda)); | ||
159 | + } | ||
132 | 160 | ||
133 | // Use first path that can be successfully reserved | 161 | // Use first path that can be successfully reserved |
134 | for (Path path : paths) { | 162 | for (Path path : paths) { |
135 | - | 163 | + // find common lambda on path |
136 | - // FIXME: need to actually reserve the lambda for static lambda's | 164 | + // a list of OchSignal indicates consecutive OchSignals |
137 | - if (staticLambda != null) { | 165 | + List<OchSignal> lambda = findFirstAvailableOch(path); |
138 | - ochSignal = new OchSignal(Frequency.ofHz(Long.parseLong(staticLambda)), | 166 | + if (lambda.isEmpty()) { |
139 | - srcOchPort.lambda().channelSpacing(), | 167 | + continue; |
140 | - srcOchPort.lambda().slotGranularity()); | 168 | + } |
141 | - } else if (!srcOchPort.isTunable() || !dstOchPort.isTunable()) { | 169 | + List<Resource> lambdaResources = convertToResources(path.links(), lambda); |
142 | - // FIXME: also check destination OCh port | 170 | + if (!lambdaResources.stream().allMatch(resourceService::isAvailable)) { |
143 | - ochSignal = srcOchPort.lambda(); | 171 | + continue; |
144 | - } else { | ||
145 | - // Request and reserve lambda on path | ||
146 | - List<OchSignal> lambdas = assignWavelength(intent, path); | ||
147 | - if (lambdas.isEmpty()) { | ||
148 | - continue; | ||
149 | - } | ||
150 | - ochSignal = OchSignal.toFixedGrid(lambdas, ChannelSpacing.CHL_50GHZ); | ||
151 | } | 172 | } |
173 | + resources.addAll(lambdaResources); | ||
152 | 174 | ||
153 | - // Create installable optical path intent | 175 | + allocateResources(intent, resources); |
154 | - // Only support fixed grid for now | ||
155 | - OchSignalType signalType = OchSignalType.FIXED_GRID; | ||
156 | - | ||
157 | - Intent newIntent = OpticalPathIntent.builder() | ||
158 | - .appId(intent.appId()) | ||
159 | - .src(intent.getSrc()) | ||
160 | - .dst(intent.getDst()) | ||
161 | - .path(path) | ||
162 | - .lambda(ochSignal) | ||
163 | - .signalType(signalType) | ||
164 | - .bidirectional(intent.isBidirectional()) | ||
165 | - .build(); | ||
166 | - | ||
167 | - return ImmutableList.of(newIntent); | ||
168 | - } | ||
169 | 176 | ||
170 | - // Release port allocations if unsuccessful | 177 | + OchSignal ochSignal = OchSignal.toFixedGrid(lambda, ChannelSpacing.CHL_50GHZ); |
171 | - resourceService.release(intent.id()); | 178 | + return ImmutableList.of(createIntent(intent, path, ochSignal)); |
179 | + } | ||
172 | 180 | ||
173 | throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent); | 181 | throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent); |
174 | } | 182 | } |
175 | 183 | ||
176 | - /** | 184 | + private Intent createIntent(OpticalConnectivityIntent parentIntent, Path path, OchSignal lambda) { |
177 | - * Request and reserve first available wavelength across path. | 185 | + // Create installable optical path intent |
178 | - * | 186 | + // Only support fixed grid for now |
179 | - * @param path path in WDM topology | 187 | + OchSignalType signalType = OchSignalType.FIXED_GRID; |
180 | - * @return first available lambda allocated | 188 | + |
181 | - */ | 189 | + return OpticalPathIntent.builder() |
182 | - private List<OchSignal> assignWavelength(Intent intent, Path path) { | 190 | + .appId(parentIntent.appId()) |
191 | + .src(parentIntent.getSrc()) | ||
192 | + .dst(parentIntent.getDst()) | ||
193 | + // calling paths.iterator().next() is safe because of non-empty set | ||
194 | + .path(path) | ||
195 | + .lambda(lambda) | ||
196 | + .signalType(signalType) | ||
197 | + .bidirectional(parentIntent.isBidirectional()) | ||
198 | + .build(); | ||
199 | + } | ||
200 | + | ||
201 | + private void allocateResources(Intent intent, List<Resource> resources) { | ||
202 | + // reserve all of required resources | ||
203 | + List<ResourceAllocation> allocations = resourceService.allocate(intent.id(), resources); | ||
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 | + } | ||
208 | + } | ||
209 | + | ||
210 | + private List<OchSignal> findFirstAvailableOch(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 | /** | ... | ... |
-
Please register or login to post a comment