blob: 753b2e3b0d7be14627393876fd934df775f1f1ea [file] [log] [blame]
/*
* 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.incubator.net.virtual.impl;
import com.google.common.collect.Iterators;
import org.onlab.osgi.ServiceDirectory;
import org.onosproject.event.AbstractListenerManager;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentEvent;
import org.onosproject.net.intent.IntentListener;
import org.onosproject.net.intent.IntentPartitionService;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.Key;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static com.google.common.base.Preconditions.*;
/**
* Intent service implementation built on the virtual network service.
*/
public class VirtualNetworkIntentService extends AbstractListenerManager<IntentEvent, IntentListener>
implements IntentService, VnetService {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String NETWORK_NULL = "Network cannot be null";
private static final String NETWORK_ID_NULL = "Network ID cannot be null";
private static final String DEVICE_NULL = "Device cannot be null";
private static final String INTENT_NULL = "Intent cannot be null";
private static final String KEY_NULL = "Key cannot be null";
private static final String APP_ID_NULL = "Intent app identifier cannot be null";
private static final String INTENT_KEY_NULL = "Intent key cannot be null";
private static final String CP_NULL = "Connect Point cannot be null";
protected IntentService intentService;
protected VirtualNetworkStore store;
protected IntentPartitionService partitionService;
private final VirtualNetwork network;
private final VirtualNetworkService manager;
/**
* Creates a new VirtualNetworkIntentService object.
*
* @param virtualNetworkManager virtual network manager service
* @param network virtual network
* @param serviceDirectory service directory
*/
public VirtualNetworkIntentService(VirtualNetworkService virtualNetworkManager, VirtualNetwork network,
ServiceDirectory serviceDirectory) {
checkNotNull(network, NETWORK_NULL);
this.network = network;
this.manager = virtualNetworkManager;
this.store = serviceDirectory.get(VirtualNetworkStore.class);
this.intentService = serviceDirectory.get(IntentService.class);
this.partitionService = serviceDirectory.get(IntentPartitionService.class);
}
@Override
public void submit(Intent intent) {
checkNotNull(intent, INTENT_NULL);
checkState(intent instanceof VirtualNetworkIntent, "Only VirtualNetworkIntent is supported.");
checkArgument(validateIntent((VirtualNetworkIntent) intent), "Invalid Intent");
intentService.submit(intent);
}
/**
* Returns true if the virtual network intent is valid.
*
* @param intent virtual network intent
* @return true if intent is valid
*/
private boolean validateIntent(VirtualNetworkIntent intent) {
checkNotNull(intent, INTENT_NULL);
checkNotNull(intent.networkId(), NETWORK_ID_NULL);
checkNotNull(intent.appId(), APP_ID_NULL);
checkNotNull(intent.key(), INTENT_KEY_NULL);
ConnectPoint ingressPoint = intent.ingressPoint();
ConnectPoint egressPoint = intent.egressPoint();
return (validateConnectPoint(ingressPoint) && validateConnectPoint(egressPoint));
}
/**
* Returns true if the connect point is valid.
*
* @param connectPoint connect point
* @return true if connect point is valid
*/
private boolean validateConnectPoint(ConnectPoint connectPoint) {
checkNotNull(connectPoint, CP_NULL);
Port port = getPort(connectPoint.deviceId(), connectPoint.port());
return port == null ? false : true;
}
/**
* Returns the virtual port for the given device identifier and port number.
*
* @param deviceId virtual device identifier
* @param portNumber virtual port number
* @return virtual port
*/
private Port getPort(DeviceId deviceId, PortNumber portNumber) {
checkNotNull(deviceId, DEVICE_NULL);
Optional<VirtualPort> foundPort = manager.getVirtualPorts(this.network.id(), deviceId)
.stream()
.filter(port -> port.number().equals(portNumber))
.findFirst();
if (foundPort.isPresent()) {
return foundPort.get();
}
return null;
}
@Override
public void withdraw(Intent intent) {
checkNotNull(intent, INTENT_NULL);
// Withdraws the physical intents created due to the virtual intents.
store.getTunnelIds(intent).forEach(tunnelId -> {
Key intentKey = Key.of(tunnelId.id(), intent.appId());
Intent physicalIntent = intentService.getIntent(intentKey);
checkNotNull(physicalIntent, INTENT_NULL);
// Withdraw the physical intent(s)
log.debug("Withdrawing pt-pt intent: " + physicalIntent);
intentService.withdraw(physicalIntent);
});
// Now withdraw the virtual intent
log.debug("Withdrawing virtual intent: " + intent);
intentService.withdraw(intent);
}
@Override
public void purge(Intent intent) {
checkNotNull(intent, INTENT_NULL);
// Purges the physical intents created for each tunnelId.
store.getTunnelIds(intent)
.forEach(tunnelId -> {
Key intentKey = Key.of(tunnelId.id(), intent.appId());
Intent physicalIntent = intentService.getIntent(intentKey);
checkNotNull(physicalIntent, INTENT_NULL);
// Purge the physical intent(s)
intentService.purge(physicalIntent);
store.removeTunnelId(intent, tunnelId);
});
// Now purge the virtual intent
intentService.purge(intent);
}
@Override
public Intent getIntent(Key key) {
checkNotNull(key, KEY_NULL);
return store.getIntent(key);
}
@Override
public Iterable<Intent> getIntents() {
return store.getIntents();
}
@Override
public Iterable<IntentData> getIntentData() {
return store.getIntentData();
}
@Override
public long getIntentCount() {
return Iterators.size(getIntents().iterator());
}
@Override
public IntentState getIntentState(Key intentKey) {
checkNotNull(intentKey, KEY_NULL);
return Optional.ofNullable(store.getIntentData(intentKey))
.map(IntentData::state)
.orElse(null);
}
@Override
public List<Intent> getInstallableIntents(Key intentKey) {
List<Intent> intents = new ArrayList<>();
getIntentData().forEach(intentData -> {
if (intentData.intent().key().equals(intentKey)) {
intents.addAll(intentData.installables());
}
});
return intents;
}
@Override
public boolean isLocal(Key intentKey) {
checkNotNull(intentKey, INTENT_KEY_NULL);
Intent intent = getIntent(intentKey);
checkNotNull(intent, INTENT_NULL);
return partitionService.isMine(intentKey);
}
@Override
public Iterable<Intent> getPending() {
return null;
}
@Override
public VirtualNetwork network() {
return network;
}
}