blob: 18ff3f76dd97c5665654f4352c4a30e10e01c4d5 [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.domain.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.ItemNotFoundException;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.DomainIntentConfigurable;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.domain.DomainIntent;
import org.onosproject.net.domain.DomainIntentOperation;
import org.onosproject.net.domain.DomainIntentOperations;
import org.onosproject.net.domain.DomainIntentService;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newFixedThreadPool;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.domain.DomainIntentOperation.Type.ADD;
import static org.onosproject.net.domain.DomainIntentOperation.Type.REMOVE;
/**
* {@link DomainIntentService} implementation class.
*/
@Component(immediate = true)
@Service
public class DomainIntentManager implements DomainIntentService {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DriverService driverService;
private ExecutorService executorService =
newFixedThreadPool(Runtime.getRuntime().availableProcessors(),
groupedThreads("onos/domain-intent-mgmt", "%d", log));
private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
private final Map<DeviceId, DomainIntentConfigurable> driversMap = Maps.newConcurrentMap();
@Activate
public void activate() {
log.info("Started");
}
@Deactivate
public void deactivate() {
log.info("Stopped");
}
@Override
public void sumbit(DomainIntentOperations domainOperations) {
executorService.execute(new DomainIntentProcessor(domainOperations));
}
private class DomainIntentProcessor implements Runnable {
private final DomainIntentOperations idos;
private final List<DomainIntentOperation> stages;
private boolean hasFailed = false;
public DomainIntentProcessor(DomainIntentOperations dios) {
this.idos = checkNotNull(dios);
this.stages = Lists.newArrayList(checkNotNull(dios.stages()));
}
@Override
public synchronized void run() {
if (stages.size() > 0) {
process(stages.remove(0));
} else if (!hasFailed) {
idos.callback().onSuccess(idos);
}
}
private void process(DomainIntentOperation dio) {
Optional<DomainIntentConfigurable> config =
dio.intent().filteredIngressPoints().stream()
.map(x -> getDomainIntentConfigurable(x.connectPoint().deviceId()))
.filter(Objects::nonNull)
.findAny();
DomainIntent domainIntent = null;
if (config.isPresent()) {
if (dio.type() == ADD) {
domainIntent = config.get().sumbit(dio.intent());
} else if (dio.type() == REMOVE) {
domainIntent = config.get().remove(dio.intent());
}
executorService.execute(this);
} else {
log.error("Ingresses devices does not support " +
"DomainIntentConfigurable. Installation failed");
hasFailed = true;
}
if (domainIntent == null) {
log.error("Installation failed for Domain Intent {}", dio.intent());
hasFailed = true;
}
if (hasFailed) {
DomainIntentOperations failedBuilder = DomainIntentOperations.builder()
.add(dio.intent()).build();
idos.callback().onError(failedBuilder);
executorService.execute(this);
}
}
}
private DomainIntentConfigurable getDomainIntentConfigurable(DeviceId deviceId) {
return driversMap.computeIfAbsent(deviceId, this::initDomainIntentDriver);
}
private DomainIntentConfigurable initDomainIntentDriver(DeviceId deviceId) {
// Attempt to lookup the handler in the cache
DriverHandler handler = driverHandlers.get(deviceId);
if (handler == null) {
try {
// Otherwise create it and if it has DomainIntentConfig behaviour, cache it
handler = driverService.createHandler(deviceId);
if (!handler.driver().hasBehaviour(DomainIntentConfigurable.class)) {
log.warn("DomainIntentConfig behaviour not supported for device {}",
deviceId);
return null;
}
} catch (ItemNotFoundException e) {
log.warn("No applicable driver for device {}", deviceId);
return null;
}
driverHandlers.put(deviceId, handler);
}
// Always (re)initialize the pipeline behaviour
log.info("Driver {} bound to device {} ... initializing driver",
handler.driver().name(), deviceId);
return handler.behaviour(DomainIntentConfigurable.class);
}
}