blob: d27d6904f08e2e1f877452622cd8bfef5fef00a6 [file] [log] [blame]
Pingping Linffa27d32015-04-30 14:41:03 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16package org.onosproject.virtualbng;
17
18import com.fasterxml.jackson.databind.ObjectMapper;
19
20import java.io.File;
21import java.io.FileNotFoundException;
22import java.io.IOException;
Pingping Linde77ee52015-06-03 17:16:07 -070023import java.util.Collections;
Pingping Linffa27d32015-04-30 14:41:03 -070024import java.util.Iterator;
25import java.util.Map;
26import java.util.Map.Entry;
27import java.util.concurrent.ConcurrentHashMap;
28
29import org.apache.felix.scr.annotations.Activate;
30import org.apache.felix.scr.annotations.Component;
31import org.apache.felix.scr.annotations.Deactivate;
32import org.apache.felix.scr.annotations.Service;
33import org.onlab.packet.IpAddress;
34import org.onlab.packet.IpPrefix;
Pingping Linbe126562015-05-06 17:57:10 -070035import org.onlab.packet.MacAddress;
Pingping Linffa27d32015-04-30 14:41:03 -070036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39/**
40 * Implementation of ConfigurationService which reads virtual BNG
41 * configuration from a file.
42 */
43@Component(immediate = true)
44@Service
45public class VbngConfigurationManager implements VbngConfigurationService {
46
47 private final Logger log = LoggerFactory.getLogger(getClass());
48
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;
52
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<>();
57
58 // Map from private IP address to public IP address
59 private Map<IpAddress, IpAddress> ipAddressMap =
60 new ConcurrentHashMap<>();
61
62 private IpAddress nextHopIpAddress;
Pingping Linbe126562015-05-06 17:57:10 -070063 private MacAddress macOfPublicIpAddresses;
Pingping Line10ece02015-06-11 19:26:24 -070064 private IpAddress xosIpAddress;
65 private int xosRestPort;
Pingping Linffa27d32015-04-30 14:41:03 -070066
67 @Activate
68 public void activate() {
69 readConfiguration();
70 log.info("vBNG configuration service started");
71 }
72
73 @Deactivate
74 public void deactivate() {
75 log.info("vBNG configuration service stopped");
76 }
77
78 /**
79 * Instructs the configuration reader to read the configuration from the
80 * file.
81 */
82 public void readConfiguration() {
83 readConfiguration(configFileName);
84 }
85
86 /**
87 * Reads virtual BNG information contained in configuration file.
88 *
89 * @param configFilename the name of the configuration file for the virtual
90 * BNG application
91 */
92 private void readConfiguration(String configFilename) {
93 File configFile = new File(CONFIG_DIR, configFilename);
94 ObjectMapper mapper = new ObjectMapper();
95
96 try {
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);
102 }
103 nextHopIpAddress = config.getNextHopIpAddress();
Pingping Linbe126562015-05-06 17:57:10 -0700104 macOfPublicIpAddresses = config.getPublicFacingMac();
Pingping Line10ece02015-06-11 19:26:24 -0700105 xosIpAddress = config.getXosIpAddress();
106 xosRestPort = config.getXosRestPort();
Pingping Linffa27d32015-04-30 14:41:03 -0700107
108 } catch (FileNotFoundException e) {
109 log.warn("Configuration file not found: {}", configFileName);
110 } catch (IOException e) {
111 log.error("Error loading configuration", e);
112 }
113 }
114
115 @Override
116 public IpAddress getNextHopIpAddress() {
117 return nextHopIpAddress;
118 }
119
Pingping Linbe126562015-05-06 17:57:10 -0700120 @Override
121 public MacAddress getPublicFacingMac() {
122 return macOfPublicIpAddresses;
123 }
124
Pingping Line10ece02015-06-11 19:26:24 -0700125 @Override
126 public IpAddress getXosIpAddress() {
127 return xosIpAddress;
128 }
129
130 @Override
131 public int getXosRestPort() {
132 return xosRestPort;
133 }
134
Pingping Linffa27d32015-04-30 14:41:03 -0700135 // TODO handle the case: the number of public IP addresses is not enough
136 // for 1:1 mapping from public IP to private IP.
137 @Override
Pingping Lin99d0b202015-05-05 14:08:48 -0700138 public synchronized IpAddress getAvailablePublicIpAddress(IpAddress
139 privateIpAddress) {
Pingping Linffa27d32015-04-30 14:41:03 -0700140 // 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;
145 }
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()) {
152 continue;
153 }
154
155 if (prefix.getKey().prefixLength() == 32) {
156 updateIpPrefixStatus(prefix.getKey(), false);
157 publicIpAddress = prefix.getKey().address();
158 ipAddressMap.put(privateIpAddress, publicIpAddress);
159 return publicIpAddress;
160 }
161
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++) {
166 publicIpAddress =
167 increaseIpAddress(prefix.getKey().address(), i);
168 if (publicIpAddress == null) {
169 return null;
170 }
171 if (ipAddressMap.values().contains(publicIpAddress)) {
172 continue;
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;
181 } else {
182 ipAddressMap.put(privateIpAddress, publicIpAddress);
183 return publicIpAddress;
184 }
185 }
186 }
187 return null;
188 }
189
Pingping Lin4e0c73d2015-05-06 15:41:10 -0700190 @Override
191 public IpAddress getAssignedPublicIpAddress(IpAddress privateIpAddress) {
192 return ipAddressMap.get(privateIpAddress);
193 }
194
Pingping Linbe126562015-05-06 17:57:10 -0700195 @Override
196 public boolean isAssignedPublicIpAddress(IpAddress ipAddress) {
197 return ipAddressMap.containsValue(ipAddress);
198 }
199
Pingping Lind2afaf22015-06-02 10:46:29 -0700200 @Override
Pingping Lin53ae34f2015-06-09 10:07:08 -0700201 public synchronized IpAddress recycleAssignedPublicIpAddress(IpAddress
Pingping Lind2afaf22015-06-02 10:46:29 -0700202 privateIpAddress) {
203 IpAddress publicIpAddress = ipAddressMap.remove(privateIpAddress);
204 if (publicIpAddress == null) {
205 return null;
206 }
207
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);
215 }
216 }
Pingping Linde77ee52015-06-03 17:16:07 -0700217 log.info("[DELETE] Private IP to Public IP mapping: {} --> {}",
218 privateIpAddress, publicIpAddress);
Pingping Lind2afaf22015-06-02 10:46:29 -0700219 return publicIpAddress;
220 }
221
Pingping Linde77ee52015-06-03 17:16:07 -0700222 @Override
223 public Map<IpAddress, IpAddress> getIpAddressMappings() {
224 return Collections.unmodifiableMap(ipAddressMap);
225 }
226
Pingping Lin53ae34f2015-06-09 10:07:08 -0700227 @Override
228 public synchronized boolean assignSpecifiedPublicIp(IpAddress publicIpAddress,
229 IpAddress privateIpAddress) {
230
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;
237
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);
243 return false;
244 }
245
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);
249
250 // Update the prefix status
251 if (prefix.getKey().prefixLength() == 32) {
252 updateIpPrefixStatus(prefix.getKey(), false);
253 return true;
254 }
255
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;
261 int usedIpNum = 0;
262 for (Entry<IpAddress, IpAddress> ipAddressMapEntry:
263 ipAddressMap.entrySet()) {
264 if (prefix.getKey().contains(ipAddressMapEntry.getValue())) {
265 usedIpNum = usedIpNum + 1;
266 }
267 }
268 if (usedIpNum == availableIpNum) {
269 updateIpPrefixStatus(prefix.getKey(), false);
270 }
271
272 return true;
273 }
274 }
275 if (!isPublicIpExist) {
276 log.info("The public IP address {} retrieved from XOS mapping does "
277 + "not exist", publicIpAddress);
278 }
279 return false;
280 }
281
Pingping Linffa27d32015-04-30 14:41:03 -0700282 /**
283 * Generates a new IP address base on a given IP address plus a number to
284 * increase.
285 *
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
289 */
290 private IpAddress increaseIpAddress(IpAddress ipAddress, int num) {
291 if (ipAddress.isIp6()) {
292 log.info("vBNG currently does not handle IPv6");
293 return null;
294 }
295 return IpAddress.valueOf(ipAddress.getIp4Address().toInt() + num);
296 }
297
298 /**
299 * Updates the IP prefix status in the local public IP prefix table.
300 *
301 * @param ipPprefix the IP prefix to update
302 * @param b the new value for the IP prefix
303 */
304 private void updateIpPrefixStatus(IpPrefix ipPprefix, boolean b) {
305 localPublicIpPrefixes.replace(ipPprefix, b);
306 }
307
308}