| /* |
| * Copyright 2017-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.incubator.net.virtual.impl.provider; |
| |
| import com.google.common.cache.Cache; |
| import com.google.common.cache.CacheBuilder; |
| import com.google.common.cache.RemovalCause; |
| import com.google.common.cache.RemovalNotification; |
| import org.onosproject.core.IdGenerator; |
| import org.onosproject.incubator.net.virtual.NetworkId; |
| import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider; |
| import org.onosproject.incubator.net.virtual.provider.VirtualMeterProvider; |
| import org.onosproject.incubator.net.virtual.provider.VirtualMeterProviderService; |
| import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.meter.Meter; |
| import org.onosproject.net.meter.MeterEvent; |
| import org.onosproject.net.meter.MeterFailReason; |
| import org.onosproject.net.meter.MeterListener; |
| import org.onosproject.net.meter.MeterOperation; |
| import org.onosproject.net.meter.MeterOperations; |
| import org.onosproject.net.meter.MeterService; |
| import org.onosproject.net.provider.ProviderId; |
| import org.osgi.service.component.annotations.Activate; |
| import org.osgi.service.component.annotations.Component; |
| import org.osgi.service.component.annotations.Deactivate; |
| import org.osgi.service.component.annotations.Reference; |
| import org.osgi.service.component.annotations.ReferenceCardinality; |
| import org.slf4j.Logger; |
| |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicLong; |
| |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /** |
| * Provider to handle meters for virtual networks. |
| */ |
| @Component(service = VirtualMeterProvider.class) |
| public class DefaultVirtualMeterProvider extends AbstractVirtualProvider |
| implements VirtualMeterProvider { |
| |
| private final Logger log = getLogger(getClass()); |
| |
| static final long TIMEOUT = 30; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY) |
| protected VirtualProviderRegistryService providerRegistryService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY) |
| protected MeterService meterService; |
| |
| private MeterListener internalMeterListener; |
| private Cache<Long, VirtualMeterOperation> pendingOperations; |
| private IdGenerator idGenerator; |
| |
| @Activate |
| public void activate() { |
| providerRegistryService.registerProvider(this); |
| internalMeterListener = new InternalMeterListener(); |
| |
| idGenerator = getIdGenerator(); |
| |
| pendingOperations = CacheBuilder.newBuilder() |
| .expireAfterWrite(TIMEOUT, TimeUnit.SECONDS) |
| .removalListener( |
| (RemovalNotification<Long, VirtualMeterOperation> |
| notification) -> { |
| if (notification.getCause() == RemovalCause.EXPIRED) { |
| NetworkId networkId = notification.getValue().networkId(); |
| MeterOperation op = notification.getValue().operation(); |
| |
| VirtualMeterProviderService providerService = |
| (VirtualMeterProviderService) providerRegistryService |
| .getProviderService(networkId, |
| VirtualMeterProvider.class); |
| |
| providerService.meterOperationFailed(op, |
| MeterFailReason.TIMEOUT); |
| } |
| }).build(); |
| |
| meterService.addListener(internalMeterListener); |
| |
| log.info("Started"); |
| } |
| |
| @Deactivate |
| public void deactivate() { |
| meterService.removeListener(internalMeterListener); |
| providerRegistryService.unregisterProvider(this); |
| } |
| |
| /** |
| * Creates a provider with the identifier. |
| */ |
| public DefaultVirtualMeterProvider() { |
| super(new ProviderId("vnet-meter", |
| "org.onosproject.virtual.vnet-meter")); |
| } |
| |
| @Override |
| public void performMeterOperation(NetworkId networkId, DeviceId deviceId, |
| MeterOperations meterOps) { |
| meterOps.operations().forEach(op -> performOperation(networkId, deviceId, op)); |
| } |
| |
| @Override |
| public void performMeterOperation(NetworkId networkId, DeviceId deviceId, |
| MeterOperation meterOp) { |
| performOperation(networkId, deviceId, meterOp); |
| } |
| |
| private void performOperation(NetworkId networkId, DeviceId deviceId, |
| MeterOperation op) { |
| |
| VirtualMeterOperation vOp = new VirtualMeterOperation(networkId, op); |
| pendingOperations.put(idGenerator.getNewId(), vOp); |
| |
| switch (op.type()) { |
| case ADD: |
| //TODO: devirtualize + submit |
| break; |
| case REMOVE: |
| //TODO: devirtualize + withdraw |
| break; |
| case MODIFY: |
| //TODO: devitualize + withdraw and submit |
| break; |
| default: |
| log.warn("Unknown Meter command {}; not sending anything", |
| op.type()); |
| VirtualMeterProviderService providerService = |
| (VirtualMeterProviderService) providerRegistryService |
| .getProviderService(networkId, |
| VirtualMeterProvider.class); |
| providerService.meterOperationFailed(op, |
| MeterFailReason.UNKNOWN_COMMAND); |
| } |
| |
| } |
| |
| /** |
| * De-virtualizes a meter operation. |
| * It takes a virtual meter operation, and translate it to a physical meter operation. |
| * |
| * @param networkId a virtual network identifier |
| * @param deviceId a virtual network device identifier |
| * @param meterOps a meter operation to be de-virtualized |
| * @return de-virtualized meter operation |
| */ |
| private VirtualMeterOperation devirtualize(NetworkId networkId, |
| DeviceId deviceId, |
| MeterOperation meterOps) { |
| return null; |
| } |
| |
| /** |
| * Virtualizes meter. |
| * This translates meter events for virtual networks before delivering them. |
| * |
| * @param meter |
| * @return |
| */ |
| private Meter virtualize(Meter meter) { |
| return null; |
| } |
| |
| |
| private class InternalMeterListener implements MeterListener { |
| @Override |
| public void event(MeterEvent event) { |
| //TODO: virtualize + notify event to meter provider service |
| //Is it enough to enable virtual network provider? |
| switch (event.type()) { |
| case METER_ADD_REQ: |
| break; |
| case METER_REM_REQ: |
| break; |
| case METER_ADDED: |
| break; |
| case METER_REMOVED: |
| break; |
| default: |
| log.warn("Unknown meter event {}", event.type()); |
| } |
| } |
| } |
| |
| /** |
| * A class to hold a network identifier and a meter operation. |
| * This class is designed to be used only in virtual network meter provider. |
| */ |
| private final class VirtualMeterOperation { |
| private NetworkId networkId; |
| private MeterOperation op; |
| |
| private VirtualMeterOperation(NetworkId networkId, MeterOperation op) { |
| this.networkId = networkId; |
| this.op = op; |
| } |
| |
| private NetworkId networkId() { |
| return networkId; |
| } |
| |
| private MeterOperation operation() { |
| return this.op; |
| } |
| } |
| |
| /** |
| * A class to hold a network identifier and a meter. |
| * This class is designed to be used in only virtual network meter provider. |
| */ |
| private final class VirtualMeter { |
| private NetworkId networkId; |
| private Meter meter; |
| |
| private VirtualMeter(NetworkId networkId, Meter meter) { |
| this.networkId = networkId; |
| this.meter = meter; |
| } |
| |
| private NetworkId networkId() { |
| return this.networkId; |
| } |
| |
| private Meter meter() { |
| return this.meter; |
| } |
| } |
| |
| /** |
| * Id generator for virtual meters to guarantee the uniqueness of its identifier |
| * among multiple virtual network meters. |
| * |
| * @return an ID generator |
| */ |
| private IdGenerator getIdGenerator() { |
| return new IdGenerator() { |
| private AtomicLong counter = new AtomicLong(0); |
| |
| @Override |
| public long getNewId() { |
| return counter.getAndIncrement(); |
| } |
| }; |
| } |
| } |