blob: 417881c85f840d482faf92f2072e94c921ef762e [file] [log] [blame]
/*
* Copyright 2015 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.vtnrsc.service.impl;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
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.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.CoreService;
import org.onosproject.event.AbstractListenerManager;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.host.HostService;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.LogicalClockService;
import org.onosproject.store.service.StorageService;
import org.onosproject.vtnrsc.FixedIp;
import org.onosproject.vtnrsc.FloatingIp;
import org.onosproject.vtnrsc.FlowClassifier;
import org.onosproject.vtnrsc.PortChain;
import org.onosproject.vtnrsc.PortPair;
import org.onosproject.vtnrsc.PortPairGroup;
import org.onosproject.vtnrsc.PortPairId;
import org.onosproject.vtnrsc.Router;
import org.onosproject.vtnrsc.RouterInterface;
import org.onosproject.vtnrsc.SegmentationId;
import org.onosproject.vtnrsc.Subnet;
import org.onosproject.vtnrsc.SubnetId;
import org.onosproject.vtnrsc.TenantId;
import org.onosproject.vtnrsc.VirtualPort;
import org.onosproject.vtnrsc.VirtualPortId;
import org.onosproject.vtnrsc.event.VtnRscEvent;
import org.onosproject.vtnrsc.event.VtnRscEventFeedback;
import org.onosproject.vtnrsc.event.VtnRscListener;
import org.onosproject.vtnrsc.floatingip.FloatingIpEvent;
import org.onosproject.vtnrsc.floatingip.FloatingIpListener;
import org.onosproject.vtnrsc.floatingip.FloatingIpService;
import org.onosproject.vtnrsc.flowclassifier.FlowClassifierEvent;
import org.onosproject.vtnrsc.flowclassifier.FlowClassifierListener;
import org.onosproject.vtnrsc.flowclassifier.FlowClassifierService;
import org.onosproject.vtnrsc.portchain.PortChainEvent;
import org.onosproject.vtnrsc.portchain.PortChainListener;
import org.onosproject.vtnrsc.portchain.PortChainService;
import org.onosproject.vtnrsc.portpair.PortPairEvent;
import org.onosproject.vtnrsc.portpair.PortPairListener;
import org.onosproject.vtnrsc.portpair.PortPairService;
import org.onosproject.vtnrsc.portpairgroup.PortPairGroupEvent;
import org.onosproject.vtnrsc.portpairgroup.PortPairGroupListener;
import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService;
import org.onosproject.vtnrsc.router.RouterEvent;
import org.onosproject.vtnrsc.router.RouterListener;
import org.onosproject.vtnrsc.router.RouterService;
import org.onosproject.vtnrsc.routerinterface.RouterInterfaceEvent;
import org.onosproject.vtnrsc.routerinterface.RouterInterfaceListener;
import org.onosproject.vtnrsc.routerinterface.RouterInterfaceService;
import org.onosproject.vtnrsc.service.VtnRscService;
import org.onosproject.vtnrsc.subnet.SubnetService;
import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
import org.onosproject.vtnrsc.virtualport.VirtualPortService;
import org.slf4j.Logger;
/**
* Provides implementation of the VtnRsc service.
*/
@Component(immediate = true)
@Service
public class VtnRscManager extends AbstractListenerManager<VtnRscEvent, VtnRscListener>
implements VtnRscService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LogicalClockService clockService;
private final Logger log = getLogger(getClass());
private FloatingIpListener floatingIpListener = new InnerFloatingIpListener();
private RouterListener routerListener = new InnerRouterListener();
private RouterInterfaceListener routerInterfaceListener = new InnerRouterInterfaceListener();
private PortPairListener portPairListener = new InnerPortPairListener();
private PortPairGroupListener portPairGroupListener = new InnerPortPairGroupListener();
private FlowClassifierListener flowClassifierListener = new InnerFlowClassifierListener();
private PortChainListener portChainListener = new InnerPortChainListener();
private EventuallyConsistentMap<TenantId, SegmentationId> l3vniMap;
private EventuallyConsistentMap<TenantId, Set<DeviceId>> classifierOvsMap;
private EventuallyConsistentMap<TenantId, Set<DeviceId>> sffOvsMap;
private static final String IFACEID = "ifaceid";
private static final String RUNNELOPTOPOIC = "tunnel-ops-ids";
private static final String EVENT_NOT_NULL = "event cannot be null";
private static final String TENANTID_NOT_NULL = "tenantId cannot be null";
private static final String DEVICEID_NOT_NULL = "deviceId cannot be null";
private static final String VIRTUALPORTID_NOT_NULL = "virtualPortId cannot be null";
private static final String HOST_NOT_NULL = "host cannot be null";
private static final String L3VNIMAP = "l3vniMap";
private static final String CLASSIFIEROVSMAP = "classifierOvsMap";
private static final String SFFOVSMAP = "sffOvsMap";
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RouterService routerService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FloatingIpService floatingIpService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RouterInterfaceService routerInterfaceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected VirtualPortService virtualPortService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected SubnetService subnetService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TenantNetworkService tenantNetworkService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PortPairService portPairService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PortPairGroupService portPairGroupService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowClassifierService flowClassifierService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PortChainService portChainService;
@Activate
public void activate() {
eventDispatcher.addSink(VtnRscEvent.class, listenerRegistry);
floatingIpService.addListener(floatingIpListener);
routerService.addListener(routerListener);
routerInterfaceService.addListener(routerInterfaceListener);
portPairService.addListener(portPairListener);
portPairGroupService.addListener(portPairGroupListener);
flowClassifierService.addListener(flowClassifierListener);
portChainService.addListener(portChainListener);
KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
.register(KryoNamespaces.API)
.register(TenantId.class, DeviceId.class);
l3vniMap = storageService
.<TenantId, SegmentationId>eventuallyConsistentMapBuilder()
.withName(L3VNIMAP).withSerializer(serializer)
.withTimestampProvider((k, v) -> clockService.getTimestamp())
.build();
classifierOvsMap = storageService
.<TenantId, Set<DeviceId>>eventuallyConsistentMapBuilder()
.withName(CLASSIFIEROVSMAP).withSerializer(serializer)
.withTimestampProvider((k, v) -> clockService.getTimestamp())
.build();
sffOvsMap = storageService
.<TenantId, Set<DeviceId>>eventuallyConsistentMapBuilder()
.withName(SFFOVSMAP).withSerializer(serializer)
.withTimestampProvider((k, v) -> clockService.getTimestamp())
.build();
}
@Deactivate
public void deactivate() {
eventDispatcher.removeSink(VtnRscEvent.class);
floatingIpService.removeListener(floatingIpListener);
routerService.removeListener(routerListener);
routerInterfaceService.removeListener(routerInterfaceListener);
portPairService.removeListener(portPairListener);
portPairGroupService.removeListener(portPairGroupListener);
flowClassifierService.removeListener(flowClassifierListener);
portChainService.removeListener(portChainListener);
l3vniMap.destroy();
classifierOvsMap.destroy();
sffOvsMap.destroy();
log.info("Stopped");
}
@Override
public SegmentationId getL3vni(TenantId tenantId) {
checkNotNull(tenantId, "tenantId cannot be null");
SegmentationId l3vni = l3vniMap.get(tenantId);
if (l3vni == null) {
long segmentationId = coreService.getIdGenerator(RUNNELOPTOPOIC)
.getNewId();
l3vni = SegmentationId.segmentationId(String
.valueOf(segmentationId));
l3vniMap.put(tenantId, l3vni);
}
return l3vni;
}
private class InnerFloatingIpListener implements FloatingIpListener {
@Override
public void event(FloatingIpEvent event) {
checkNotNull(event, EVENT_NOT_NULL);
FloatingIp floatingIp = event.subject();
if (FloatingIpEvent.Type.FLOATINGIP_PUT == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.FLOATINGIP_PUT,
new VtnRscEventFeedback(
floatingIp)));
}
if (FloatingIpEvent.Type.FLOATINGIP_DELETE == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.FLOATINGIP_DELETE,
new VtnRscEventFeedback(
floatingIp)));
}
if (FloatingIpEvent.Type.FLOATINGIP_BIND == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.FLOATINGIP_BIND,
new VtnRscEventFeedback(
floatingIp)));
}
if (FloatingIpEvent.Type.FLOATINGIP_UNBIND == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.FLOATINGIP_UNBIND,
new VtnRscEventFeedback(
floatingIp)));
}
}
}
private class InnerRouterListener implements RouterListener {
@Override
public void event(RouterEvent event) {
checkNotNull(event, EVENT_NOT_NULL);
Router router = event.subject();
if (RouterEvent.Type.ROUTER_PUT == event.type()) {
notifyListeners(new VtnRscEvent(VtnRscEvent.Type.ROUTER_PUT,
new VtnRscEventFeedback(router)));
}
if (RouterEvent.Type.ROUTER_DELETE == event.type()) {
notifyListeners(new VtnRscEvent(VtnRscEvent.Type.ROUTER_DELETE,
new VtnRscEventFeedback(router)));
}
}
}
private class InnerRouterInterfaceListener
implements RouterInterfaceListener {
@Override
public void event(RouterInterfaceEvent event) {
checkNotNull(event, EVENT_NOT_NULL);
RouterInterface routerInterface = event.subject();
if (RouterInterfaceEvent.Type.ROUTER_INTERFACE_PUT == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.ROUTER_INTERFACE_PUT,
new VtnRscEventFeedback(
routerInterface)));
}
if (RouterInterfaceEvent.Type.ROUTER_INTERFACE_DELETE == event
.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.ROUTER_INTERFACE_DELETE,
new VtnRscEventFeedback(
routerInterface)));
}
}
}
private class InnerPortPairListener implements PortPairListener {
@Override
public void event(PortPairEvent event) {
checkNotNull(event, EVENT_NOT_NULL);
PortPair portPair = event.subject();
if (PortPairEvent.Type.PORT_PAIR_PUT == event.type()) {
notifyListeners(new VtnRscEvent(VtnRscEvent.Type.PORT_PAIR_PUT,
new VtnRscEventFeedback(portPair)));
} else if (PortPairEvent.Type.PORT_PAIR_DELETE == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.PORT_PAIR_DELETE,
new VtnRscEventFeedback(portPair)));
} else if (PortPairEvent.Type.PORT_PAIR_UPDATE == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.PORT_PAIR_UPDATE,
new VtnRscEventFeedback(portPair)));
}
}
}
private class InnerPortPairGroupListener implements PortPairGroupListener {
@Override
public void event(PortPairGroupEvent event) {
checkNotNull(event, EVENT_NOT_NULL);
PortPairGroup portPairGroup = event.subject();
if (PortPairGroupEvent.Type.PORT_PAIR_GROUP_PUT == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.PORT_PAIR_GROUP_PUT,
new VtnRscEventFeedback(portPairGroup)));
} else if (PortPairGroupEvent.Type.PORT_PAIR_GROUP_DELETE == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.PORT_PAIR_GROUP_DELETE,
new VtnRscEventFeedback(portPairGroup)));
} else if (PortPairGroupEvent.Type.PORT_PAIR_GROUP_UPDATE == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.PORT_PAIR_GROUP_UPDATE,
new VtnRscEventFeedback(portPairGroup)));
}
}
}
private class InnerFlowClassifierListener implements FlowClassifierListener {
@Override
public void event(FlowClassifierEvent event) {
checkNotNull(event, EVENT_NOT_NULL);
FlowClassifier flowClassifier = event.subject();
if (FlowClassifierEvent.Type.FLOW_CLASSIFIER_PUT == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.FLOW_CLASSIFIER_PUT,
new VtnRscEventFeedback(flowClassifier)));
} else if (FlowClassifierEvent.Type.FLOW_CLASSIFIER_DELETE == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.FLOW_CLASSIFIER_DELETE,
new VtnRscEventFeedback(flowClassifier)));
} else if (FlowClassifierEvent.Type.FLOW_CLASSIFIER_UPDATE == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.FLOW_CLASSIFIER_UPDATE,
new VtnRscEventFeedback(flowClassifier)));
}
}
}
private class InnerPortChainListener implements PortChainListener {
@Override
public void event(PortChainEvent event) {
checkNotNull(event, EVENT_NOT_NULL);
PortChain portChain = event.subject();
if (PortChainEvent.Type.PORT_CHAIN_PUT == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.PORT_CHAIN_PUT,
new VtnRscEventFeedback(portChain)));
} else if (PortChainEvent.Type.PORT_CHAIN_DELETE == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.PORT_CHAIN_DELETE,
new VtnRscEventFeedback(portChain)));
} else if (PortChainEvent.Type.PORT_CHAIN_UPDATE == event.type()) {
notifyListeners(new VtnRscEvent(
VtnRscEvent.Type.PORT_CHAIN_UPDATE,
new VtnRscEventFeedback(portChain)));
}
}
}
@Override
public Iterator<Device> getClassifierOfTenant(TenantId tenantId) {
checkNotNull(tenantId, TENANTID_NOT_NULL);
Set<DeviceId> deviceIdSet = classifierOvsMap.get(tenantId);
Set<Device> deviceSet = new HashSet<>();
if (deviceIdSet != null) {
for (DeviceId deviceId : deviceIdSet) {
deviceSet.add(deviceService.getDevice(deviceId));
}
}
return deviceSet.iterator();
}
@Override
public Iterator<Device> getSFFOfTenant(TenantId tenantId) {
checkNotNull(tenantId, TENANTID_NOT_NULL);
Set<DeviceId> deviceIdSet = sffOvsMap.get(tenantId);
Set<Device> deviceSet = new HashSet<>();
if (deviceIdSet != null) {
for (DeviceId deviceId : deviceIdSet) {
deviceSet.add(deviceService.getDevice(deviceId));
}
}
return deviceSet.iterator();
}
@Override
public MacAddress getGatewayMac(HostId hostId) {
checkNotNull(hostId, "hostId cannot be null");
Host host = hostService.getHost(hostId);
String ifaceId = host.annotations().value(IFACEID);
VirtualPortId hPortId = VirtualPortId.portId(ifaceId);
VirtualPort hPort = virtualPortService.getPort(hPortId);
SubnetId subnetId = hPort.fixedIps().iterator().next().subnetId();
Subnet subnet = subnetService.getSubnet(subnetId);
IpAddress gatewayIp = subnet.gatewayIp();
Iterable<VirtualPort> virtualPorts = virtualPortService.getPorts();
MacAddress macAddress = null;
for (VirtualPort port : virtualPorts) {
Set<FixedIp> fixedIpSet = port.fixedIps();
for (FixedIp fixedIp : fixedIpSet) {
if (fixedIp.ip().equals(gatewayIp)) {
macAddress = port.macAddress();
}
}
}
return macAddress;
}
@Override
public boolean isServiceFunction(VirtualPortId portId) {
return portPairService.exists(PortPairId.of(portId.portId()));
}
@Override
public DeviceId getSFToSFFMaping(VirtualPortId portId) {
checkNotNull(portId, "portId cannot be null");
VirtualPort vmPort = virtualPortService.getPort(portId);
Set<Host> hostSet = hostService.getHostsByMac(vmPort.macAddress());
for (Host host : hostSet) {
if (host.annotations().value(IFACEID).equals(vmPort.portId().portId())) {
return host.location().deviceId();
}
}
return null;
}
@Override
public void addDeviceIdOfOvsMap(VirtualPortId virtualPortId,
TenantId tenantId, DeviceId deviceId) {
checkNotNull(virtualPortId, VIRTUALPORTID_NOT_NULL);
checkNotNull(tenantId, TENANTID_NOT_NULL);
checkNotNull(deviceId, DEVICEID_NOT_NULL);
if (isServiceFunction(virtualPortId)) {
addDeviceIdToSpecificMap(tenantId, deviceId, sffOvsMap);
} else {
addDeviceIdToSpecificMap(tenantId, deviceId, classifierOvsMap);
}
}
@Override
public void removeDeviceIdOfOvsMap(Host host, TenantId tenantId, DeviceId deviceId) {
checkNotNull(host, HOST_NOT_NULL);
checkNotNull(tenantId, TENANTID_NOT_NULL);
checkNotNull(deviceId, DEVICEID_NOT_NULL);
if (isLastSFHostOfTenant(host, deviceId, tenantId)) {
removeDeviceIdToSpecificMap(tenantId, deviceId, sffOvsMap);
}
if (isLastClassifierHostOfTenant(host, deviceId, tenantId)) {
removeDeviceIdToSpecificMap(tenantId, deviceId, classifierOvsMap);
}
}
/**
* Checks whether the last Service Function host of a specific tenant in
* this device.
*
* @param host the host on device
* @param deviceId the device identifier
* @param tenantId the tenant identifier
* @return true or false
*/
private boolean isLastSFHostOfTenant(Host host, DeviceId deviceId,
TenantId tenantId) {
Set<Host> hostSet = hostService.getConnectedHosts(deviceId);
if (hostSet != null) {
for (Host h : hostSet) {
String ifaceId = h.annotations().value(IFACEID);
if (ifaceId != null) {
VirtualPortId hPortId = VirtualPortId.portId(ifaceId);
if (virtualPortService.getPort(hPortId).tenantId().tenantId()
.equals(tenantId.tenantId())
&& isServiceFunction(hPortId)) {
if (!h.equals(host)) {
return false;
}
}
}
}
}
return true;
}
/**
* Checks whether the last Classifier host of a specific tenant in this
* device.
*
* @param host the host on device
* @param deviceId the device identifier
* @param tenantId the tenant identifier
* @return true or false
*/
private boolean isLastClassifierHostOfTenant(Host host, DeviceId deviceId,
TenantId tenantId) {
Set<Host> hostSet = hostService.getConnectedHosts(deviceId);
if (hostSet != null) {
for (Host h : hostSet) {
String ifaceId = h.annotations().value(IFACEID);
if (ifaceId != null) {
VirtualPortId hPortId = VirtualPortId.portId(ifaceId);
if (virtualPortService.getPort(hPortId).tenantId().tenantId()
.equals(tenantId.tenantId())
&& !isServiceFunction(hPortId)) {
if (!h.equals(host)) {
return false;
}
}
}
}
}
return true;
}
/**
* Adds specify Device identifier to OvsMap.
*
* @param tenantId the tenant identifier
* @param deviceId the device identifier
* @param ovsMap the instance of map to store device identifier
*/
private void addDeviceIdToSpecificMap(TenantId tenantId,
DeviceId deviceId,
EventuallyConsistentMap<TenantId, Set<DeviceId>> ovsMap) {
if (ovsMap.containsKey(tenantId)) {
Set<DeviceId> deviceIdSet = ovsMap.get(tenantId);
deviceIdSet.add(deviceId);
ovsMap.put(tenantId, deviceIdSet);
} else {
Set<DeviceId> deviceIdSet = new HashSet<>();
deviceIdSet.add(deviceId);
ovsMap.put(tenantId, deviceIdSet);
}
}
/**
* Removes specify Device identifier from OvsMap.
*
* @param tenantId the tenant identifier
* @param deviceId the device identifier
* @param ovsMap the instance of map to store device identifier
*/
private void removeDeviceIdToSpecificMap(TenantId tenantId,
DeviceId deviceId,
EventuallyConsistentMap<TenantId, Set<DeviceId>> ovsMap) {
Set<DeviceId> deviceIdSet = ovsMap.get(tenantId);
if (deviceIdSet != null && deviceIdSet.size() > 1) {
deviceIdSet.remove(deviceId);
ovsMap.put(tenantId, deviceIdSet);
} else {
ovsMap.remove(tenantId);
}
}
/**
* Notifies specify event to all listeners.
*
* @param event VtnRsc event
*/
private void notifyListeners(VtnRscEvent event) {
checkNotNull(event, EVENT_NOT_NULL);
post(event);
}
}