/* * Copyright 2016-present Open Networking Laboratory * * 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); } }