blob: 26462add11934425902063ede6f8768bf507b543 [file] [log] [blame]
/*
* 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();
}
};
}
}