blob: 36da63c5c980018e22d452727ada02a68a2ee57c [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.vpls.config.impl;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
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.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.EncapsulationType;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.basics.SubjectFactories;
import org.onosproject.vpls.config.VplsAppConfig;
import org.onosproject.vpls.config.VplsConfig;
import org.onosproject.vpls.config.VplsConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Implementation of VPLSConfigurationService which reads VPLS configuration
* from the network configuration service.
*/
@Component(immediate = true)
@Service
public class VplsConfigImpl implements VplsConfigService {
private static final String VPLS_APP = "org.onosproject.vpls";
private static final String VPLS = "vpls";
private static final String EMPTY = "";
private static final String CONFIG_NULL = "VPLS configuration not defined";
private static final String APP_ID_NULL = "VPLS application ID is null";
private static final String CONFIG_CHANGED = "VPLS configuration changed: {}";
private static final String CHECK_CONFIG =
"Checking the interface configuration";
private static final String NET_CONF_EVENT =
"Received NetworkConfigEvent {}";
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry registry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected InterfaceService interfaceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService configService;
private final Set<String> vplsAffectedByApi = new HashSet<>();
private VplsAppConfig vplsAppConfig = null;
private SetMultimap<String, String> ifacesOfVpls = HashMultimap.create();
private SetMultimap<String, String> oldIfacesOfVpls = HashMultimap.create();
private SetMultimap<String, Interface> vplsIfaces = HashMultimap.create();
private Map<String, EncapsulationType> vplsEncaps = Maps.newHashMap();
private final InternalNetworkConfigListener configListener =
new InternalNetworkConfigListener();
private ConfigFactory<ApplicationId, VplsAppConfig> vplsConfigFactory =
new ConfigFactory<ApplicationId, VplsAppConfig>(
SubjectFactories.APP_SUBJECT_FACTORY, VplsAppConfig.class, VPLS) {
@Override
public VplsAppConfig createConfig() {
return new VplsAppConfig();
}
};
private ApplicationId vplsAppId;
@Activate
protected void active() {
configService.addListener(configListener);
registry.registerConfigFactory(vplsConfigFactory);
loadConfiguration();
log.info("Started");
}
@Deactivate
protected void deactive() {
registry.unregisterConfigFactory(vplsConfigFactory);
configService.removeListener(configListener);
log.info("Stopped");
}
@Override
public void addVpls(String vplsName, Set<String> ifaces, String encap) {
EncapsulationType encapType = EncapsulationType.enumFromString(encap);
if (ifacesOfVpls.containsKey(vplsName)) {
if (ifaces.isEmpty()) {
return;
}
ifaces.forEach(iface -> vplsAppConfig.addIface(vplsName, iface));
vplsAppConfig.setEncap(vplsName, encapType);
} else {
vplsAppConfig.addVpls(new VplsConfig(vplsName, ifaces, encapType));
}
vplsAffectedByApi.add(vplsName);
applyConfig(vplsAppConfig);
}
@Override
public void removeVpls(String vplsName) {
if (ifacesOfVpls.containsKey(vplsName)) {
vplsAppConfig.removeVpls(vplsName);
vplsAffectedByApi.add(vplsName);
applyConfig(vplsAppConfig);
}
}
@Override
public void addIface(String vplsName, String iface) {
if (ifacesOfVpls.containsKey(vplsName)) {
vplsAppConfig.addIface(vplsName, iface);
vplsAffectedByApi.add(vplsName);
applyConfig(vplsAppConfig);
}
}
@Override
public void setEncap(String vplsName, String encap) {
EncapsulationType encapType = EncapsulationType.enumFromString(encap);
if (ifacesOfVpls.containsKey(vplsName)) {
vplsAppConfig.setEncap(vplsName, encapType);
vplsAffectedByApi.add(vplsName);
applyConfig(vplsAppConfig);
}
}
@Override
public void removeIface(String iface) {
if (ifacesOfVpls.containsValue(iface)) {
VplsConfig vpls = vplsAppConfig.vplsFromIface(iface);
vplsAppConfig.removeIface(vpls, iface);
vplsAffectedByApi.add(vpls.name());
applyConfig(vplsAppConfig);
}
}
@Override
public void cleanVplsConfig() {
ifacesOfVpls.entries().forEach(e -> {
vplsAppConfig.removeVpls(e.getKey());
vplsAffectedByApi.add(e.getKey());
});
applyConfig(vplsAppConfig);
}
@Override
public EncapsulationType encap(String vplsName) {
EncapsulationType encap = null;
if (vplsEncaps.containsKey(vplsName)) {
encap = vplsEncaps.get(vplsName);
}
return encap;
}
@Override
public Set<String> vplsAffectedByApi() {
Set<String> vplsNames = ImmutableSet.copyOf(vplsAffectedByApi);
vplsAffectedByApi.clear();
return vplsNames;
}
@Override
public Set<Interface> allIfaces() {
Set<Interface> interfaces = new HashSet<>();
interfaceService.getInterfaces().stream()
.filter(iface -> iface.ipAddressesList() == null ||
iface.ipAddressesList().isEmpty())
.forEach(interfaces::add);
return interfaces;
}
@Override
public Set<Interface> ifaces() {
Set<Interface> interfaces = new HashSet<>();
vplsIfaces.values().forEach(interfaces::add);
return interfaces;
}
@Override
public Set<Interface> ifaces(String vplsName) {
Set<Interface> vplsInterfaces = new HashSet<>();
vplsIfaces.get(vplsName).forEach(vplsInterfaces::add);
return vplsInterfaces;
}
@Override
public Set<String> vplsNames() {
return ifacesOfVpls.keySet();
}
@Override
public Set<String> vplsNamesOld() {
return oldIfacesOfVpls.keySet();
}
@Override
public SetMultimap<String, Interface> ifacesByVplsName() {
return ImmutableSetMultimap.copyOf(vplsIfaces);
}
@Override
public SetMultimap<String, Interface> ifacesByVplsName(VlanId vlan,
ConnectPoint connectPoint) {
String vplsName =
vplsIfaces.entries().stream()
.filter(e -> e.getValue().connectPoint().equals(connectPoint))
.filter(e -> e.getValue().vlan().equals(vlan))
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
SetMultimap<String, Interface> result = HashMultimap.create();
if (vplsName != null && vplsIfaces.containsKey(vplsName)) {
vplsIfaces.get(vplsName)
.forEach(intf -> result.put(vplsName, intf));
return result;
}
return null;
}
@Override
public Map<String, EncapsulationType> encapByVplsName() {
return ImmutableMap.copyOf(vplsEncaps);
}
/**
* Retrieves the VPLS configuration from network configuration.
*/
private void loadConfiguration() {
loadAppId();
vplsAppConfig = configService.getConfig(vplsAppId, VplsAppConfig.class);
if (vplsAppConfig == null) {
log.warn(CONFIG_NULL);
vplsAppConfig = configService.addConfig(vplsAppId, VplsAppConfig.class);
}
oldIfacesOfVpls = ifacesOfVpls;
ifacesOfVpls = getConfigInterfaces();
vplsIfaces = getConfigCPointsFromIfaces();
vplsEncaps = getConfigEncap();
log.debug(CONFIG_CHANGED, ifacesOfVpls);
}
/**
* Retrieves the application identifier from core service.
*/
private void loadAppId() {
vplsAppId = coreService.getAppId(VPLS_APP);
if (vplsAppId == null) {
log.warn(APP_ID_NULL);
}
}
/**
* Applies a given configuration to the VPLS application.
*/
private void applyConfig(VplsAppConfig vplsAppConfig) {
loadAppId();
configService.applyConfig(vplsAppId, VplsAppConfig.class, vplsAppConfig.node());
}
/**
* Retrieves the VPLS names and related encapsulation types from the
* configuration.
*
* @return a map of VPLS names and associated encapsulation types
*/
private Map<String, EncapsulationType> getConfigEncap() {
Map<String, EncapsulationType> configEncap = new HashMap<>();
vplsAppConfig.vplss().forEach(vpls -> {
configEncap.put(vpls.name(), vpls.encap());
});
return configEncap;
}
/**
* Retrieves the VPLS names and related interfaces names from the configuration.
*
* @return a map of VPLS names and related interface names
*/
private SetMultimap<String, String> getConfigInterfaces() {
SetMultimap<String, String> confIntfByVpls =
HashMultimap.create();
vplsAppConfig.vplss().forEach(vpls -> {
if (vpls.ifaces().isEmpty()) {
confIntfByVpls.put(vpls.name(), EMPTY);
} else {
vpls.ifaces().forEach(iface -> confIntfByVpls.put(vpls.name(), iface));
}
});
return confIntfByVpls;
}
/**
* Retrieves the VPLS names and related interfaces from the configuration.
*
* @return a map of VPLS names and related interfaces
*/
private SetMultimap<String, Interface> getConfigCPointsFromIfaces() {
log.debug(CHECK_CONFIG);
SetMultimap<String, Interface> confCPointsByIntf =
HashMultimap.create();
ifacesOfVpls.entries().forEach(vpls -> {
interfaceService.getInterfaces()
.stream()
.filter(intf -> intf.ipAddressesList().isEmpty())
.filter(intf -> intf.name().equals(vpls.getValue()))
.forEach(intf -> confCPointsByIntf.put(vpls.getKey(), intf));
});
return confCPointsByIntf;
}
/**
* Listener for VPLS configuration events.
*/
private class InternalNetworkConfigListener implements NetworkConfigListener {
@Override
public void event(NetworkConfigEvent event) {
if (event.configClass() == VplsConfigService.CONFIG_CLASS) {
log.debug(NET_CONF_EVENT, event.configClass());
switch (event.type()) {
case CONFIG_ADDED:
case CONFIG_UPDATED:
case CONFIG_REMOVED:
loadConfiguration();
break;
default:
break;
}
}
}
}
}