Marc De Leenheer
Committed by Gerrit Code Review

Allow static lambda and port mappings (ONOS-2067).

Fix bug in device resource store.

Change-Id: I219a4de9ec803b3d142a6b957868f64dc599fa24
...@@ -85,6 +85,10 @@ public final class AnnotationKeys { ...@@ -85,6 +85,10 @@ public final class AnnotationKeys {
85 */ 85 */
86 public static final String ROUTER_ID = "routerId"; 86 public static final String ROUTER_ID = "routerId";
87 87
88 + public static final String STATIC_LAMBDA = "staticLambda";
89 +
90 + public static final String STATIC_PORT = "staticPort";
91 +
88 /** 92 /**
89 * Returns the value annotated object for the specified annotation key. 93 * Returns the value annotated object for the specified annotation key.
90 * The annotated value is expected to be String that can be parsed as double. 94 * The annotated value is expected to be String that can be parsed as double.
......
...@@ -23,8 +23,8 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -23,8 +23,8 @@ import org.apache.felix.scr.annotations.Reference;
23 import org.apache.felix.scr.annotations.ReferenceCardinality; 23 import org.apache.felix.scr.annotations.ReferenceCardinality;
24 import org.onosproject.core.ApplicationId; 24 import org.onosproject.core.ApplicationId;
25 import org.onosproject.core.CoreService; 25 import org.onosproject.core.CoreService;
26 +import org.onosproject.net.AnnotationKeys;
26 import org.onosproject.net.ConnectPoint; 27 import org.onosproject.net.ConnectPoint;
27 -import org.onosproject.net.DeviceId;
28 import org.onosproject.net.OchPort; 28 import org.onosproject.net.OchPort;
29 import org.onosproject.net.OduCltPort; 29 import org.onosproject.net.OduCltPort;
30 import org.onosproject.net.OduSignalType; 30 import org.onosproject.net.OduSignalType;
...@@ -138,7 +138,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -138,7 +138,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
138 .signalType(OduSignalType.ODU4) 138 .signalType(OduSignalType.ODU4)
139 .bidirectional(intent.isBidirectional()) 139 .bidirectional(intent.isBidirectional())
140 .build(); 140 .build();
141 - intents.add(connIntent); 141 + intentService.submit(connIntent);
142 } 142 }
143 143
144 // Create optical circuit intent 144 // Create optical circuit intent
...@@ -155,7 +155,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -155,7 +155,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
155 circuitIntent = new FlowRuleIntent(appId, rules, intent.resources()); 155 circuitIntent = new FlowRuleIntent(appId, rules, intent.resources());
156 156
157 // Save circuit to connectivity intent mapping 157 // Save circuit to connectivity intent mapping
158 - deviceResourceService.requestMapping(connIntent.id(), circuitIntent.id()); 158 + deviceResourceService.requestMapping(connIntent.id(), intent.id());
159 intents.add(circuitIntent); 159 intents.add(circuitIntent);
160 160
161 return intents; 161 return intents;
...@@ -163,16 +163,43 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -163,16 +163,43 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
163 163
164 /** 164 /**
165 * Checks if current allocations on given resource can satisfy request. 165 * Checks if current allocations on given resource can satisfy request.
166 + * If the resource is null, return true.
166 * 167 *
167 * @param request 168 * @param request
168 * @param resource 169 * @param resource
169 * @return 170 * @return
170 */ 171 */
171 private boolean isAvailable(Intent request, IntentId resource) { 172 private boolean isAvailable(Intent request, IntentId resource) {
173 + if (resource == null) {
174 + return true;
175 + }
176 +
172 Set<IntentId> mapping = deviceResourceService.getMapping(resource); 177 Set<IntentId> mapping = deviceResourceService.getMapping(resource);
173 178
174 - // TODO: hardcoded 10 x 10G 179 + if (mapping == null) {
175 - return mapping.size() < 10; 180 + return true;
181 + }
182 +
183 + // TODO: hardcoded 80% utilization
184 + return mapping.size() < 8;
185 + }
186 +
187 + private boolean isAllowed(OpticalCircuitIntent circuitIntent, OpticalConnectivityIntent connIntent) {
188 + ConnectPoint srcStaticPort = staticPort(circuitIntent.getSrc());
189 + if (srcStaticPort != null) {
190 + if (!srcStaticPort.equals(connIntent.getSrc())) {
191 + return false;
192 + }
193 + }
194 +
195 + ConnectPoint dstStaticPort = staticPort(circuitIntent.getDst());
196 + if (dstStaticPort != null) {
197 + if (!dstStaticPort.equals(connIntent.getDst())) {
198 + return false;
199 + }
200 + }
201 +
202 + return true;
176 } 203 }
177 204
178 /** 205 /**
...@@ -191,7 +218,13 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -191,7 +218,13 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
191 218
192 ConnectPoint src = circuitIntent.getSrc(); 219 ConnectPoint src = circuitIntent.getSrc();
193 ConnectPoint dst = circuitIntent.getDst(); 220 ConnectPoint dst = circuitIntent.getDst();
194 - if (!src.equals(connIntent.getSrc()) && !dst.equals(connIntent.getDst())) { 221 + // Ignore if the intents don't have identical src and dst devices
222 + if (!src.deviceId().equals(connIntent.getSrc().deviceId()) &&
223 + !dst.deviceId().equals(connIntent.getDst().deviceId())) {
224 + continue;
225 + }
226 +
227 + if (!isAllowed(circuitIntent, connIntent)) {
195 continue; 228 continue;
196 } 229 }
197 230
...@@ -203,21 +236,44 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -203,21 +236,44 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
203 return null; 236 return null;
204 } 237 }
205 238
206 - private OchPort findAvailableOchPort(DeviceId deviceId, OpticalCircuitIntent circuitIntent) { 239 + private ConnectPoint staticPort(ConnectPoint connectPoint) {
207 - List<Port> ports = deviceService.getPorts(deviceId); 240 + Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
241 +
242 + String staticPort = port.annotations().value(AnnotationKeys.STATIC_PORT);
243 +
244 + // FIXME: need a better way to match the port
245 + if (staticPort != null) {
246 + for (Port p : deviceService.getPorts(connectPoint.deviceId())) {
247 + if (staticPort.equals(p.number().name())) {
248 + return new ConnectPoint(p.element().id(), p.number());
249 + }
250 + }
251 + }
252 +
253 + return null;
254 + }
255 +
256 + private OchPort findAvailableOchPort(ConnectPoint oduPort, OpticalCircuitIntent circuitIntent) {
257 + // First see if the port mappings are constrained
258 + ConnectPoint ochCP = staticPort(oduPort);
259 +
260 + if (ochCP != null) {
261 + OchPort ochPort = (OchPort) deviceService.getPort(ochCP.deviceId(), ochCP.port());
262 + IntentId intentId = deviceResourceService.getAllocations(ochPort);
263 + if (isAvailable(circuitIntent, intentId)) {
264 + return ochPort;
265 + }
266 + }
267 +
268 + // No port constraints, so find any port that works
269 + List<Port> ports = deviceService.getPorts(oduPort.deviceId());
208 270
209 for (Port port : ports) { 271 for (Port port : ports) {
210 if (!(port instanceof OchPort)) { 272 if (!(port instanceof OchPort)) {
211 continue; 273 continue;
212 } 274 }
213 275
214 - // Port is not used
215 IntentId intentId = deviceResourceService.getAllocations(port); 276 IntentId intentId = deviceResourceService.getAllocations(port);
216 - if (intentId == null) {
217 - return (OchPort) port;
218 - }
219 -
220 - // Port is used but has free resources
221 if (isAvailable(circuitIntent, intentId)) { 277 if (isAvailable(circuitIntent, intentId)) {
222 return (OchPort) port; 278 return (OchPort) port;
223 } 279 }
...@@ -226,16 +282,14 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -226,16 +282,14 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
226 return null; 282 return null;
227 } 283 }
228 284
229 - // TODO: Add constraints for OduClt to OCh port mappings
230 - // E.g., ports need to belong to same line card.
231 private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent) { 285 private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent) {
232 286
233 - OchPort srcPort = findAvailableOchPort(intent.getSrc().deviceId(), intent); 287 + OchPort srcPort = findAvailableOchPort(intent.getSrc(), intent);
234 if (srcPort == null) { 288 if (srcPort == null) {
235 return null; 289 return null;
236 } 290 }
237 291
238 - OchPort dstPort = findAvailableOchPort(intent.getDst().deviceId(), intent); 292 + OchPort dstPort = findAvailableOchPort(intent.getDst(), intent);
239 if (dstPort == null) { 293 if (dstPort == null) {
240 return null; 294 return null;
241 } 295 }
......
...@@ -26,8 +26,10 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -26,8 +26,10 @@ import org.apache.felix.scr.annotations.Deactivate;
26 import org.apache.felix.scr.annotations.Reference; 26 import org.apache.felix.scr.annotations.Reference;
27 import org.apache.felix.scr.annotations.ReferenceCardinality; 27 import org.apache.felix.scr.annotations.ReferenceCardinality;
28 import org.onlab.util.Frequency; 28 import org.onlab.util.Frequency;
29 +import org.onosproject.net.AnnotationKeys;
29 import org.onosproject.net.ChannelSpacing; 30 import org.onosproject.net.ChannelSpacing;
30 import org.onosproject.net.ConnectPoint; 31 import org.onosproject.net.ConnectPoint;
32 +import org.onosproject.net.DeviceId;
31 import org.onosproject.net.GridType; 33 import org.onosproject.net.GridType;
32 import org.onosproject.net.Link; 34 import org.onosproject.net.Link;
33 import org.onosproject.net.OchPort; 35 import org.onosproject.net.OchPort;
...@@ -123,17 +125,26 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical ...@@ -123,17 +125,26 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
123 125
124 // Use first path that can be successfully reserved 126 // Use first path that can be successfully reserved
125 for (Path path : paths) { 127 for (Path path : paths) {
128 +
129 + // Static or dynamic lambda allocation
130 + LambdaResourceAllocation lambdaAlloc;
131 + String staticLambda = srcPort.annotations().value(AnnotationKeys.STATIC_LAMBDA);
132 + if (staticLambda != null) {
133 + // FIXME: need to actually reserve the lambda
134 + lambdaAlloc = new LambdaResourceAllocation(LambdaResource.valueOf(Integer.parseInt(staticLambda)));
135 + } else {
126 // Request and reserve lambda on path 136 // Request and reserve lambda on path
127 LinkResourceAllocations linkAllocs = assignWavelength(intent, path); 137 LinkResourceAllocations linkAllocs = assignWavelength(intent, path);
128 if (linkAllocs == null) { 138 if (linkAllocs == null) {
129 continue; 139 continue;
130 } 140 }
141 + lambdaAlloc = getWavelength(path, linkAllocs);
142 + }
131 143
132 OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port()); 144 OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port());
133 145
134 // Create installable optical path intent 146 // Create installable optical path intent
135 - LambdaResourceAllocation lambdaAlloc = getWavelength(path, linkAllocs); 147 + OchSignal ochSignal = getOchSignal(lambdaAlloc, omsPort.maxFrequency(), omsPort.grid());
136 - OchSignal ochSignal = getOchSignal(lambdaAlloc, omsPort.minFrequency(), omsPort.grid());
137 // Only support fixed grid for now 148 // Only support fixed grid for now
138 OchSignalType signalType = OchSignalType.FIXED_GRID; 149 OchSignalType signalType = OchSignalType.FIXED_GRID;
139 150
...@@ -188,7 +199,10 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical ...@@ -188,7 +199,10 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
188 199
189 LinkResourceAllocations allocations = linkResourceService.requestResources(request.build()); 200 LinkResourceAllocations allocations = linkResourceService.requestResources(request.build());
190 201
191 - checkWavelengthContinuity(allocations, path); 202 + if (!checkWavelengthContinuity(allocations, path)) {
203 + linkResourceService.releaseResources(allocations);
204 + return null;
205 + }
192 206
193 return allocations; 207 return allocations;
194 } 208 }
...@@ -229,15 +243,15 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical ...@@ -229,15 +243,15 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
229 * Convert lambda resource allocation in OCh signal. 243 * Convert lambda resource allocation in OCh signal.
230 * 244 *
231 * @param alloc lambda resource allocation 245 * @param alloc lambda resource allocation
232 - * @param minFrequency minimum frequency 246 + * @param maxFrequency maximum frequency
233 * @param grid grid spacing frequency 247 * @param grid grid spacing frequency
234 * @return OCh signal 248 * @return OCh signal
235 */ 249 */
236 - private OchSignal getOchSignal(LambdaResourceAllocation alloc, Frequency minFrequency, Frequency grid) { 250 + private OchSignal getOchSignal(LambdaResourceAllocation alloc, Frequency maxFrequency, Frequency grid) {
237 int channel = alloc.lambda().toInt(); 251 int channel = alloc.lambda().toInt();
238 252
239 // Calculate center frequency 253 // Calculate center frequency
240 - Frequency centerFrequency = minFrequency.add(grid.multiply(channel)).add(grid.floorDivision(2)); 254 + Frequency centerFrequency = maxFrequency.subtract(grid.multiply(channel - 1));
241 255
242 // Build OCh signal object 256 // Build OCh signal object
243 int spacingMultiplier = (int) (centerFrequency.subtract(OchSignal.CENTER_FREQUENCY).asHz() / grid.asHz()); 257 int spacingMultiplier = (int) (centerFrequency.subtract(OchSignal.CENTER_FREQUENCY).asHz() / grid.asHz());
...@@ -248,6 +262,23 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical ...@@ -248,6 +262,23 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
248 return ochSignal; 262 return ochSignal;
249 } 263 }
250 264
265 + private ConnectPoint staticPort(ConnectPoint connectPoint) {
266 + Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
267 +
268 + String staticPort = port.annotations().value(AnnotationKeys.STATIC_PORT);
269 +
270 + // FIXME: need a better way to match the port
271 + if (staticPort != null) {
272 + for (Port p : deviceService.getPorts(connectPoint.deviceId())) {
273 + if (staticPort.equals(p.number().name())) {
274 + return new ConnectPoint(p.element().id(), p.number());
275 + }
276 + }
277 + }
278 +
279 + return null;
280 + }
281 +
251 /** 282 /**
252 * Calculates optical paths in WDM topology. 283 * Calculates optical paths in WDM topology.
253 * 284 *
...@@ -260,13 +291,29 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical ...@@ -260,13 +291,29 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
260 LinkWeight weight = new LinkWeight() { 291 LinkWeight weight = new LinkWeight() {
261 @Override 292 @Override
262 public double weight(TopologyEdge edge) { 293 public double weight(TopologyEdge edge) {
294 + // Disregard inactive or non-optical links
263 if (edge.link().state() == Link.State.INACTIVE) { 295 if (edge.link().state() == Link.State.INACTIVE) {
264 return -1; 296 return -1;
265 } 297 }
266 if (edge.link().type() != Link.Type.OPTICAL) { 298 if (edge.link().type() != Link.Type.OPTICAL) {
267 return -1; 299 return -1;
268 } 300 }
269 - //return edge.link().annotations().value("optical.type").equals("WDM") ? +1 : -1; 301 + // Adhere to static port mappings
302 + DeviceId srcDeviceId = edge.link().src().deviceId();
303 + if (srcDeviceId.equals(intent.getSrc().deviceId())) {
304 + ConnectPoint srcStaticPort = staticPort(intent.getSrc());
305 + if (srcStaticPort != null) {
306 + return srcStaticPort.equals(edge.link().src()) ? 1 : -1;
307 + }
308 + }
309 + DeviceId dstDeviceId = edge.link().dst().deviceId();
310 + if (dstDeviceId.equals(intent.getDst().deviceId())) {
311 + ConnectPoint dstStaticPort = staticPort(intent.getDst());
312 + if (dstStaticPort != null) {
313 + return dstStaticPort.equals(edge.link().dst()) ? 1 : -1;
314 + }
315 + }
316 +
270 return 1; 317 return 1;
271 } 318 }
272 }; 319 };
......
...@@ -165,7 +165,13 @@ public class ConsistentDeviceResourceStore implements DeviceResourceStore { ...@@ -165,7 +165,13 @@ public class ConsistentDeviceResourceStore implements DeviceResourceStore {
165 165
166 @Override 166 @Override
167 public Set<IntentId> getMapping(IntentId intentId) { 167 public Set<IntentId> getMapping(IntentId intentId) {
168 - return intentMapping.get(intentId).value(); 168 + Versioned<Set<IntentId>> result = intentMapping.get(intentId);
169 +
170 + if (result == null) {
171 + return result.value();
172 + }
173 +
174 + return null;
169 } 175 }
170 176
171 @Override 177 @Override
...@@ -174,10 +180,11 @@ public class ConsistentDeviceResourceStore implements DeviceResourceStore { ...@@ -174,10 +180,11 @@ public class ConsistentDeviceResourceStore implements DeviceResourceStore {
174 180
175 181
176 if (versionedIntents == null) { 182 if (versionedIntents == null) {
177 - intentMapping.put(keyIntentId, Collections.singleton(valIntentId)); 183 + Set<IntentId> newSet = new HashSet<>();
184 + newSet.add(valIntentId);
185 + intentMapping.put(keyIntentId, newSet);
178 } else { 186 } else {
179 versionedIntents.value().add(valIntentId); 187 versionedIntents.value().add(valIntentId);
180 - intentMapping.put(keyIntentId, versionedIntents.value());
181 } 188 }
182 189
183 return true; 190 return true;
......
...@@ -214,15 +214,28 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -214,15 +214,28 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
214 private void parsePorts(DeviceId deviceId, JsonNode nodes) { 214 private void parsePorts(DeviceId deviceId, JsonNode nodes) {
215 List<PortDescription> ports = new ArrayList<>(); 215 List<PortDescription> ports = new ArrayList<>();
216 for (JsonNode node : nodes) { 216 for (JsonNode node : nodes) {
217 - ports.add(parsePort(node)); 217 + ports.add(parsePort(deviceId, node));
218 } 218 }
219 deviceProviderService.updatePorts(deviceId, ports); 219 deviceProviderService.updatePorts(deviceId, ports);
220 } 220 }
221 221
222 // Parses the given node with port information. 222 // Parses the given node with port information.
223 - private PortDescription parsePort(JsonNode node) { 223 + private PortDescription parsePort(DeviceId deviceId, JsonNode node) {
224 Port.Type type = Port.Type.valueOf(node.path("type").asText("COPPER")); 224 Port.Type type = Port.Type.valueOf(node.path("type").asText("COPPER"));
225 - PortNumber port = portNumber(node.path("port").asLong(0)); 225 + // TL1-based ports have a name
226 + PortNumber port = null;
227 + if (node.has("name")) {
228 + for (Port p : deviceService.getPorts(deviceId)) {
229 + if (p.number().name().equals(node.get("name").asText())) {
230 + port = p.number();
231 + break;
232 + }
233 + }
234 + } else {
235 + port = portNumber(node.path("port").asLong(0));
236 + }
237 +
238 + checkNotNull(port);
226 String portName = Strings.emptyToNull(port.name()); 239 String portName = Strings.emptyToNull(port.name());
227 SparseAnnotations annotations = null; 240 SparseAnnotations annotations = null;
228 if (portName != null) { 241 if (portName != null) {
...@@ -239,6 +252,22 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -239,6 +252,22 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
239 return new OmsPortDescription(port, node.path("enabled").asBoolean(true), 252 return new OmsPortDescription(port, node.path("enabled").asBoolean(true),
240 CENTER, CENTER.add(TOTAL), 253 CENTER, CENTER.add(TOTAL),
241 Frequency.ofGHz(100), annotations); 254 Frequency.ofGHz(100), annotations);
255 + case ODUCLT:
256 + annotations = annotations(node.get("annotations"));
257 + OduCltPort oduCltPort = (OduCltPort) deviceService.getPort(deviceId, port);
258 + return new OduCltPortDescription(port, node.path("enabled").asBoolean(true),
259 + oduCltPort.signalType(), annotations);
260 + case OCH:
261 + annotations = annotations(node.get("annotations"));
262 + OchPort ochPort = (OchPort) deviceService.getPort(deviceId, port);
263 + return new OchPortDescription(port, node.path("enabled").asBoolean(true),
264 + ochPort.signalType(), ochPort.isTunable(),
265 + ochPort.lambda(), annotations);
266 + case OMS:
267 + annotations = annotations(node.get("annotations"));
268 + OmsPort omsPort = (OmsPort) deviceService.getPort(deviceId, port);
269 + return new OmsPortDescription(port, node.path("enabled").asBoolean(true),
270 + omsPort.minFrequency(), omsPort.maxFrequency(), omsPort.grid(), annotations);
242 default: 271 default:
243 log.warn("{}: Unsupported Port Type"); 272 log.warn("{}: Unsupported Port Type");
244 } 273 }
......