blob: 3a8dacebdea0787735cddc36e5efb1d1ff95451a [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.virtualbng;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
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.Service;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of ConfigurationService which reads virtual BNG
* configuration from a file.
*/
@Component(immediate = true)
@Service
public class VbngConfigurationManager implements VbngConfigurationService {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String CONFIG_DIR = "../config";
private static final String DEFAULT_CONFIG_FILE = "virtualbng.json";
private String configFileName = DEFAULT_CONFIG_FILE;
// If all the IP addresses of one IP prefix are assigned, then we
// mark the value of this IP prefix as false, otherwise as true.
private Map<IpPrefix, Boolean> localPublicIpPrefixes =
new ConcurrentHashMap<>();
// Map from private IP address to public IP address
private Map<IpAddress, IpAddress> ipAddressMap =
new ConcurrentHashMap<>();
private IpAddress nextHopIpAddress;
private MacAddress macOfPublicIpAddresses;
@Activate
public void activate() {
readConfiguration();
log.info("vBNG configuration service started");
}
@Deactivate
public void deactivate() {
log.info("vBNG configuration service stopped");
}
/**
* Instructs the configuration reader to read the configuration from the
* file.
*/
public void readConfiguration() {
readConfiguration(configFileName);
}
/**
* Reads virtual BNG information contained in configuration file.
*
* @param configFilename the name of the configuration file for the virtual
* BNG application
*/
private void readConfiguration(String configFilename) {
File configFile = new File(CONFIG_DIR, configFilename);
ObjectMapper mapper = new ObjectMapper();
try {
log.info("Loading config: {}", configFile.getAbsolutePath());
VbngConfiguration config = mapper.readValue(configFile,
VbngConfiguration.class);
for (IpPrefix prefix : config.getLocalPublicIpPrefixes()) {
localPublicIpPrefixes.put(prefix, true);
}
nextHopIpAddress = config.getNextHopIpAddress();
macOfPublicIpAddresses = config.getPublicFacingMac();
} catch (FileNotFoundException e) {
log.warn("Configuration file not found: {}", configFileName);
} catch (IOException e) {
log.error("Error loading configuration", e);
}
}
@Override
public IpAddress getNextHopIpAddress() {
return nextHopIpAddress;
}
@Override
public MacAddress getPublicFacingMac() {
return macOfPublicIpAddresses;
}
// TODO handle the case: the number of public IP addresses is not enough
// for 1:1 mapping from public IP to private IP.
@Override
public synchronized IpAddress getAvailablePublicIpAddress(IpAddress
privateIpAddress) {
// If there is already a mapping entry for the private IP address,
// then fetch the public IP address in the mapping entry and return it.
IpAddress publicIpAddress = ipAddressMap.get(privateIpAddress);
if (publicIpAddress != null) {
return publicIpAddress;
}
// There is no mapping for the private IP address.
Iterator<Entry<IpPrefix, Boolean>> prefixes =
localPublicIpPrefixes.entrySet().iterator();
while (prefixes.hasNext()) {
Entry<IpPrefix, Boolean> prefix = prefixes.next();
if (!prefix.getValue()) {
continue;
}
if (prefix.getKey().prefixLength() == 32) {
updateIpPrefixStatus(prefix.getKey(), false);
publicIpAddress = prefix.getKey().address();
ipAddressMap.put(privateIpAddress, publicIpAddress);
return publicIpAddress;
}
int prefixLen = prefix.getKey().prefixLength();
int availableIpNum = (int) Math.pow(2,
IpPrefix.MAX_INET_MASK_LENGTH - prefixLen) - 1;
for (int i = 1; i <= availableIpNum; i++) {
publicIpAddress =
increaseIpAddress(prefix.getKey().address(), i);
if (publicIpAddress == null) {
return null;
}
if (ipAddressMap.values().contains(publicIpAddress)) {
continue;
} else if (i == availableIpNum) {
// All the IP addresses are assigned out
// Update this IP prefix status to false
// Note: in this version we do not consider the
// IP recycling issue.
updateIpPrefixStatus(prefix.getKey(), false);
ipAddressMap.put(privateIpAddress, publicIpAddress);
return publicIpAddress;
} else {
ipAddressMap.put(privateIpAddress, publicIpAddress);
return publicIpAddress;
}
}
}
return null;
}
@Override
public IpAddress getAssignedPublicIpAddress(IpAddress privateIpAddress) {
return ipAddressMap.get(privateIpAddress);
}
@Override
public boolean isAssignedPublicIpAddress(IpAddress ipAddress) {
return ipAddressMap.containsValue(ipAddress);
}
/**
* Generates a new IP address base on a given IP address plus a number to
* increase.
*
* @param ipAddress the IP address to increase
* @param num the number for ipAddress to add
* @return the new IP address after increase
*/
private IpAddress increaseIpAddress(IpAddress ipAddress, int num) {
if (ipAddress.isIp6()) {
log.info("vBNG currently does not handle IPv6");
return null;
}
return IpAddress.valueOf(ipAddress.getIp4Address().toInt() + num);
}
/**
* Updates the IP prefix status in the local public IP prefix table.
*
* @param ipPprefix the IP prefix to update
* @param b the new value for the IP prefix
*/
private void updateIpPrefixStatus(IpPrefix ipPprefix, boolean b) {
localPublicIpPrefixes.replace(ipPprefix, b);
}
}