aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java')
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java308
1 files changed, 308 insertions, 0 deletions
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
new file mode 100644
index 00000000..d27d6904
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
@@ -0,0 +1,308 @@
+/*
+ * 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.Collections;
+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;
+ private IpAddress xosIpAddress;
+ private int xosRestPort;
+
+ @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();
+ xosIpAddress = config.getXosIpAddress();
+ xosRestPort = config.getXosRestPort();
+
+ } 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;
+ }
+
+ @Override
+ public IpAddress getXosIpAddress() {
+ return xosIpAddress;
+ }
+
+ @Override
+ public int getXosRestPort() {
+ return xosRestPort;
+ }
+
+ // 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);
+ }
+
+ @Override
+ public synchronized IpAddress recycleAssignedPublicIpAddress(IpAddress
+ privateIpAddress) {
+ IpAddress publicIpAddress = ipAddressMap.remove(privateIpAddress);
+ if (publicIpAddress == null) {
+ return null;
+ }
+
+ Iterator<Entry<IpPrefix, Boolean>> prefixes =
+ localPublicIpPrefixes.entrySet().iterator();
+ while (prefixes.hasNext()) {
+ Entry<IpPrefix, Boolean> prefixEntry = prefixes.next();
+ if (prefixEntry.getKey().contains(publicIpAddress)
+ && !prefixEntry.getValue()) {
+ updateIpPrefixStatus(prefixEntry.getKey(), true);
+ }
+ }
+ log.info("[DELETE] Private IP to Public IP mapping: {} --> {}",
+ privateIpAddress, publicIpAddress);
+ return publicIpAddress;
+ }
+
+ @Override
+ public Map<IpAddress, IpAddress> getIpAddressMappings() {
+ return Collections.unmodifiableMap(ipAddressMap);
+ }
+
+ @Override
+ public synchronized boolean assignSpecifiedPublicIp(IpAddress publicIpAddress,
+ IpAddress privateIpAddress) {
+
+ // Judge whether this public IP address is in our public IP
+ // prefix/address list.
+ boolean isPublicIpExist = false;
+ for (Entry<IpPrefix, Boolean> prefix: localPublicIpPrefixes.entrySet()) {
+ if (prefix.getKey().contains(publicIpAddress)) {
+ isPublicIpExist = true;
+
+ // Judge whether this public IP address is already assigned
+ if (!prefix.getValue() ||
+ isAssignedPublicIpAddress(publicIpAddress)) {
+ log.info("The public IP address {} is already assigned, "
+ + "and not available.", publicIpAddress);
+ return false;
+ }
+
+ // The public IP address is still available
+ // Store the mapping from private IP address to public IP address
+ ipAddressMap.put(privateIpAddress, publicIpAddress);
+
+ // Update the prefix status
+ if (prefix.getKey().prefixLength() == 32) {
+ updateIpPrefixStatus(prefix.getKey(), false);
+ return true;
+ }
+
+ // Judge whether the prefix of this public IP address is used
+ // up, if so, update the IP prefix status.
+ int prefixLen = prefix.getKey().prefixLength();
+ int availableIpNum = (int) Math.pow(2,
+ IpPrefix.MAX_INET_MASK_LENGTH - prefixLen) - 1;
+ int usedIpNum = 0;
+ for (Entry<IpAddress, IpAddress> ipAddressMapEntry:
+ ipAddressMap.entrySet()) {
+ if (prefix.getKey().contains(ipAddressMapEntry.getValue())) {
+ usedIpNum = usedIpNum + 1;
+ }
+ }
+ if (usedIpNum == availableIpNum) {
+ updateIpPrefixStatus(prefix.getKey(), false);
+ }
+
+ return true;
+ }
+ }
+ if (!isPublicIpExist) {
+ log.info("The public IP address {} retrieved from XOS mapping does "
+ + "not exist", publicIpAddress);
+ }
+ return false;
+ }
+
+ /**
+ * 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);
+ }
+
+}