2 * Copyright 2015 Open Networking Laboratory
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.onosproject.virtualbng;
18 import com.fasterxml.jackson.databind.ObjectMapper;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.util.Collections;
24 import java.util.Iterator;
26 import java.util.Map.Entry;
27 import java.util.concurrent.ConcurrentHashMap;
29 import org.apache.felix.scr.annotations.Activate;
30 import org.apache.felix.scr.annotations.Component;
31 import org.apache.felix.scr.annotations.Deactivate;
32 import org.apache.felix.scr.annotations.Service;
33 import org.onlab.packet.IpAddress;
34 import org.onlab.packet.IpPrefix;
35 import org.onlab.packet.MacAddress;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * Implementation of ConfigurationService which reads virtual BNG
41 * configuration from a file.
43 @Component(immediate = true)
45 public class VbngConfigurationManager implements VbngConfigurationService {
47 private final Logger log = LoggerFactory.getLogger(getClass());
49 private static final String CONFIG_DIR = "../config";
50 private static final String DEFAULT_CONFIG_FILE = "virtualbng.json";
51 private String configFileName = DEFAULT_CONFIG_FILE;
53 // If all the IP addresses of one IP prefix are assigned, then we
54 // mark the value of this IP prefix as false, otherwise as true.
55 private Map<IpPrefix, Boolean> localPublicIpPrefixes =
56 new ConcurrentHashMap<>();
58 // Map from private IP address to public IP address
59 private Map<IpAddress, IpAddress> ipAddressMap =
60 new ConcurrentHashMap<>();
62 private IpAddress nextHopIpAddress;
63 private MacAddress macOfPublicIpAddresses;
64 private IpAddress xosIpAddress;
65 private int xosRestPort;
68 public void activate() {
70 log.info("vBNG configuration service started");
74 public void deactivate() {
75 log.info("vBNG configuration service stopped");
79 * Instructs the configuration reader to read the configuration from the
82 public void readConfiguration() {
83 readConfiguration(configFileName);
87 * Reads virtual BNG information contained in configuration file.
89 * @param configFilename the name of the configuration file for the virtual
92 private void readConfiguration(String configFilename) {
93 File configFile = new File(CONFIG_DIR, configFilename);
94 ObjectMapper mapper = new ObjectMapper();
97 log.info("Loading config: {}", configFile.getAbsolutePath());
98 VbngConfiguration config = mapper.readValue(configFile,
99 VbngConfiguration.class);
100 for (IpPrefix prefix : config.getLocalPublicIpPrefixes()) {
101 localPublicIpPrefixes.put(prefix, true);
103 nextHopIpAddress = config.getNextHopIpAddress();
104 macOfPublicIpAddresses = config.getPublicFacingMac();
105 xosIpAddress = config.getXosIpAddress();
106 xosRestPort = config.getXosRestPort();
108 } catch (FileNotFoundException e) {
109 log.warn("Configuration file not found: {}", configFileName);
110 } catch (IOException e) {
111 log.error("Error loading configuration", e);
116 public IpAddress getNextHopIpAddress() {
117 return nextHopIpAddress;
121 public MacAddress getPublicFacingMac() {
122 return macOfPublicIpAddresses;
126 public IpAddress getXosIpAddress() {
131 public int getXosRestPort() {
135 // TODO handle the case: the number of public IP addresses is not enough
136 // for 1:1 mapping from public IP to private IP.
138 public synchronized IpAddress getAvailablePublicIpAddress(IpAddress
140 // If there is already a mapping entry for the private IP address,
141 // then fetch the public IP address in the mapping entry and return it.
142 IpAddress publicIpAddress = ipAddressMap.get(privateIpAddress);
143 if (publicIpAddress != null) {
144 return publicIpAddress;
146 // There is no mapping for the private IP address.
147 Iterator<Entry<IpPrefix, Boolean>> prefixes =
148 localPublicIpPrefixes.entrySet().iterator();
149 while (prefixes.hasNext()) {
150 Entry<IpPrefix, Boolean> prefix = prefixes.next();
151 if (!prefix.getValue()) {
155 if (prefix.getKey().prefixLength() == 32) {
156 updateIpPrefixStatus(prefix.getKey(), false);
157 publicIpAddress = prefix.getKey().address();
158 ipAddressMap.put(privateIpAddress, publicIpAddress);
159 return publicIpAddress;
162 int prefixLen = prefix.getKey().prefixLength();
163 int availableIpNum = (int) Math.pow(2,
164 IpPrefix.MAX_INET_MASK_LENGTH - prefixLen) - 1;
165 for (int i = 1; i <= availableIpNum; i++) {
167 increaseIpAddress(prefix.getKey().address(), i);
168 if (publicIpAddress == null) {
171 if (ipAddressMap.values().contains(publicIpAddress)) {
173 } else if (i == availableIpNum) {
174 // All the IP addresses are assigned out
175 // Update this IP prefix status to false
176 // Note: in this version we do not consider the
177 // IP recycling issue.
178 updateIpPrefixStatus(prefix.getKey(), false);
179 ipAddressMap.put(privateIpAddress, publicIpAddress);
180 return publicIpAddress;
182 ipAddressMap.put(privateIpAddress, publicIpAddress);
183 return publicIpAddress;
191 public IpAddress getAssignedPublicIpAddress(IpAddress privateIpAddress) {
192 return ipAddressMap.get(privateIpAddress);
196 public boolean isAssignedPublicIpAddress(IpAddress ipAddress) {
197 return ipAddressMap.containsValue(ipAddress);
201 public synchronized IpAddress recycleAssignedPublicIpAddress(IpAddress
203 IpAddress publicIpAddress = ipAddressMap.remove(privateIpAddress);
204 if (publicIpAddress == null) {
208 Iterator<Entry<IpPrefix, Boolean>> prefixes =
209 localPublicIpPrefixes.entrySet().iterator();
210 while (prefixes.hasNext()) {
211 Entry<IpPrefix, Boolean> prefixEntry = prefixes.next();
212 if (prefixEntry.getKey().contains(publicIpAddress)
213 && !prefixEntry.getValue()) {
214 updateIpPrefixStatus(prefixEntry.getKey(), true);
217 log.info("[DELETE] Private IP to Public IP mapping: {} --> {}",
218 privateIpAddress, publicIpAddress);
219 return publicIpAddress;
223 public Map<IpAddress, IpAddress> getIpAddressMappings() {
224 return Collections.unmodifiableMap(ipAddressMap);
228 public synchronized boolean assignSpecifiedPublicIp(IpAddress publicIpAddress,
229 IpAddress privateIpAddress) {
231 // Judge whether this public IP address is in our public IP
232 // prefix/address list.
233 boolean isPublicIpExist = false;
234 for (Entry<IpPrefix, Boolean> prefix: localPublicIpPrefixes.entrySet()) {
235 if (prefix.getKey().contains(publicIpAddress)) {
236 isPublicIpExist = true;
238 // Judge whether this public IP address is already assigned
239 if (!prefix.getValue() ||
240 isAssignedPublicIpAddress(publicIpAddress)) {
241 log.info("The public IP address {} is already assigned, "
242 + "and not available.", publicIpAddress);
246 // The public IP address is still available
247 // Store the mapping from private IP address to public IP address
248 ipAddressMap.put(privateIpAddress, publicIpAddress);
250 // Update the prefix status
251 if (prefix.getKey().prefixLength() == 32) {
252 updateIpPrefixStatus(prefix.getKey(), false);
256 // Judge whether the prefix of this public IP address is used
257 // up, if so, update the IP prefix status.
258 int prefixLen = prefix.getKey().prefixLength();
259 int availableIpNum = (int) Math.pow(2,
260 IpPrefix.MAX_INET_MASK_LENGTH - prefixLen) - 1;
262 for (Entry<IpAddress, IpAddress> ipAddressMapEntry:
263 ipAddressMap.entrySet()) {
264 if (prefix.getKey().contains(ipAddressMapEntry.getValue())) {
265 usedIpNum = usedIpNum + 1;
268 if (usedIpNum == availableIpNum) {
269 updateIpPrefixStatus(prefix.getKey(), false);
275 if (!isPublicIpExist) {
276 log.info("The public IP address {} retrieved from XOS mapping does "
277 + "not exist", publicIpAddress);
283 * Generates a new IP address base on a given IP address plus a number to
286 * @param ipAddress the IP address to increase
287 * @param num the number for ipAddress to add
288 * @return the new IP address after increase
290 private IpAddress increaseIpAddress(IpAddress ipAddress, int num) {
291 if (ipAddress.isIp6()) {
292 log.info("vBNG currently does not handle IPv6");
295 return IpAddress.valueOf(ipAddress.getIp4Address().toInt() + num);
299 * Updates the IP prefix status in the local public IP prefix table.
301 * @param ipPprefix the IP prefix to update
302 * @param b the new value for the IP prefix
304 private void updateIpPrefixStatus(IpPrefix ipPprefix, boolean b) {
305 localPublicIpPrefixes.replace(ipPprefix, b);