blob: 20ad02c2efbbac85f0d632471761709b3dad7e72 [file] [log] [blame]
Pingping Linffa27d32015-04-30 14:41:03 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Pingping Linffa27d32015-04-30 14:41:03 -07003 *
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;
Jonathan Hartbbc352f2015-10-27 19:24:36 -070019import org.onlab.packet.IpAddress;
20import org.onlab.packet.IpPrefix;
21import org.onlab.packet.MacAddress;
22import org.onosproject.net.ConnectPoint;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070023import org.osgi.service.component.annotations.Activate;
24import org.osgi.service.component.annotations.Component;
25import org.osgi.service.component.annotations.Deactivate;
Jonathan Hartbbc352f2015-10-27 19:24:36 -070026import org.slf4j.Logger;
27import org.slf4j.LoggerFactory;
Pingping Linffa27d32015-04-30 14:41:03 -070028
29import java.io.File;
30import java.io.FileNotFoundException;
31import java.io.IOException;
Pingping Linde77ee52015-06-03 17:16:07 -070032import java.util.Collections;
Pingping Linffa27d32015-04-30 14:41:03 -070033import java.util.Iterator;
34import java.util.Map;
35import java.util.Map.Entry;
36import java.util.concurrent.ConcurrentHashMap;
37
Pingping Linffa27d32015-04-30 14:41:03 -070038/**
39 * Implementation of ConfigurationService which reads virtual BNG
40 * configuration from a file.
41 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070042@Component(immediate = true, service = VbngConfigurationService.class)
Pingping Linffa27d32015-04-30 14:41:03 -070043public class VbngConfigurationManager implements VbngConfigurationService {
44
45 private final Logger log = LoggerFactory.getLogger(getClass());
46
47 private static final String CONFIG_DIR = "../config";
48 private static final String DEFAULT_CONFIG_FILE = "virtualbng.json";
49 private String configFileName = DEFAULT_CONFIG_FILE;
50
51 // If all the IP addresses of one IP prefix are assigned, then we
52 // mark the value of this IP prefix as false, otherwise as true.
53 private Map<IpPrefix, Boolean> localPublicIpPrefixes =
54 new ConcurrentHashMap<>();
55
56 // Map from private IP address to public IP address
57 private Map<IpAddress, IpAddress> ipAddressMap =
58 new ConcurrentHashMap<>();
59
60 private IpAddress nextHopIpAddress;
Pingping Linbe126562015-05-06 17:57:10 -070061 private MacAddress macOfPublicIpAddresses;
Pingping Line10ece02015-06-11 19:26:24 -070062 private IpAddress xosIpAddress;
63 private int xosRestPort;
Jonathan Hartbbc352f2015-10-27 19:24:36 -070064 private Map<String, ConnectPoint> nodeToPort;
Pingping Linffa27d32015-04-30 14:41:03 -070065
66 @Activate
67 public void activate() {
68 readConfiguration();
69 log.info("vBNG configuration service started");
70 }
71
72 @Deactivate
73 public void deactivate() {
74 log.info("vBNG configuration service stopped");
75 }
76
77 /**
78 * Instructs the configuration reader to read the configuration from the
79 * file.
80 */
81 public void readConfiguration() {
82 readConfiguration(configFileName);
83 }
84
85 /**
86 * Reads virtual BNG information contained in configuration file.
87 *
88 * @param configFilename the name of the configuration file for the virtual
89 * BNG application
90 */
91 private void readConfiguration(String configFilename) {
92 File configFile = new File(CONFIG_DIR, configFilename);
93 ObjectMapper mapper = new ObjectMapper();
94
95 try {
96 log.info("Loading config: {}", configFile.getAbsolutePath());
97 VbngConfiguration config = mapper.readValue(configFile,
98 VbngConfiguration.class);
99 for (IpPrefix prefix : config.getLocalPublicIpPrefixes()) {
100 localPublicIpPrefixes.put(prefix, true);
101 }
102 nextHopIpAddress = config.getNextHopIpAddress();
Pingping Linbe126562015-05-06 17:57:10 -0700103 macOfPublicIpAddresses = config.getPublicFacingMac();
Pingping Line10ece02015-06-11 19:26:24 -0700104 xosIpAddress = config.getXosIpAddress();
105 xosRestPort = config.getXosRestPort();
Jonathan Hartbbc352f2015-10-27 19:24:36 -0700106 nodeToPort = config.getHosts();
107
Pingping Linffa27d32015-04-30 14:41:03 -0700108
109 } catch (FileNotFoundException e) {
110 log.warn("Configuration file not found: {}", configFileName);
111 } catch (IOException e) {
112 log.error("Error loading configuration", e);
113 }
114 }
115
116 @Override
117 public IpAddress getNextHopIpAddress() {
118 return nextHopIpAddress;
119 }
120
Pingping Linbe126562015-05-06 17:57:10 -0700121 @Override
122 public MacAddress getPublicFacingMac() {
123 return macOfPublicIpAddresses;
124 }
125
Pingping Line10ece02015-06-11 19:26:24 -0700126 @Override
127 public IpAddress getXosIpAddress() {
128 return xosIpAddress;
129 }
130
131 @Override
132 public int getXosRestPort() {
133 return xosRestPort;
134 }
135
Jonathan Hartbbc352f2015-10-27 19:24:36 -0700136 @Override
137 public Map<String, ConnectPoint> getNodeToPort() {
138 return nodeToPort;
139 }
140
Pingping Linffa27d32015-04-30 14:41:03 -0700141 // TODO handle the case: the number of public IP addresses is not enough
142 // for 1:1 mapping from public IP to private IP.
143 @Override
Pingping Lin99d0b202015-05-05 14:08:48 -0700144 public synchronized IpAddress getAvailablePublicIpAddress(IpAddress
145 privateIpAddress) {
Pingping Linffa27d32015-04-30 14:41:03 -0700146 // If there is already a mapping entry for the private IP address,
147 // then fetch the public IP address in the mapping entry and return it.
148 IpAddress publicIpAddress = ipAddressMap.get(privateIpAddress);
149 if (publicIpAddress != null) {
150 return publicIpAddress;
151 }
152 // There is no mapping for the private IP address.
153 Iterator<Entry<IpPrefix, Boolean>> prefixes =
154 localPublicIpPrefixes.entrySet().iterator();
155 while (prefixes.hasNext()) {
156 Entry<IpPrefix, Boolean> prefix = prefixes.next();
157 if (!prefix.getValue()) {
158 continue;
159 }
160
161 if (prefix.getKey().prefixLength() == 32) {
162 updateIpPrefixStatus(prefix.getKey(), false);
163 publicIpAddress = prefix.getKey().address();
164 ipAddressMap.put(privateIpAddress, publicIpAddress);
165 return publicIpAddress;
166 }
167
Ray Milkey3717e602018-02-01 13:49:47 -0800168 double prefixLen = prefix.getKey().prefixLength();
Pingping Linffa27d32015-04-30 14:41:03 -0700169 int availableIpNum = (int) Math.pow(2,
170 IpPrefix.MAX_INET_MASK_LENGTH - prefixLen) - 1;
171 for (int i = 1; i <= availableIpNum; i++) {
172 publicIpAddress =
173 increaseIpAddress(prefix.getKey().address(), i);
174 if (publicIpAddress == null) {
175 return null;
176 }
177 if (ipAddressMap.values().contains(publicIpAddress)) {
178 continue;
179 } else if (i == availableIpNum) {
180 // All the IP addresses are assigned out
181 // Update this IP prefix status to false
182 // Note: in this version we do not consider the
183 // IP recycling issue.
184 updateIpPrefixStatus(prefix.getKey(), false);
185 ipAddressMap.put(privateIpAddress, publicIpAddress);
186 return publicIpAddress;
187 } else {
188 ipAddressMap.put(privateIpAddress, publicIpAddress);
189 return publicIpAddress;
190 }
191 }
192 }
193 return null;
194 }
195
Pingping Lin4e0c73d2015-05-06 15:41:10 -0700196 @Override
197 public IpAddress getAssignedPublicIpAddress(IpAddress privateIpAddress) {
198 return ipAddressMap.get(privateIpAddress);
199 }
200
Pingping Linbe126562015-05-06 17:57:10 -0700201 @Override
202 public boolean isAssignedPublicIpAddress(IpAddress ipAddress) {
203 return ipAddressMap.containsValue(ipAddress);
204 }
205
Pingping Lind2afaf22015-06-02 10:46:29 -0700206 @Override
Pingping Lin53ae34f2015-06-09 10:07:08 -0700207 public synchronized IpAddress recycleAssignedPublicIpAddress(IpAddress
Pingping Lind2afaf22015-06-02 10:46:29 -0700208 privateIpAddress) {
209 IpAddress publicIpAddress = ipAddressMap.remove(privateIpAddress);
210 if (publicIpAddress == null) {
211 return null;
212 }
213
214 Iterator<Entry<IpPrefix, Boolean>> prefixes =
215 localPublicIpPrefixes.entrySet().iterator();
216 while (prefixes.hasNext()) {
217 Entry<IpPrefix, Boolean> prefixEntry = prefixes.next();
218 if (prefixEntry.getKey().contains(publicIpAddress)
219 && !prefixEntry.getValue()) {
220 updateIpPrefixStatus(prefixEntry.getKey(), true);
221 }
222 }
Pingping Linde77ee52015-06-03 17:16:07 -0700223 log.info("[DELETE] Private IP to Public IP mapping: {} --> {}",
224 privateIpAddress, publicIpAddress);
Pingping Lind2afaf22015-06-02 10:46:29 -0700225 return publicIpAddress;
226 }
227
Pingping Linde77ee52015-06-03 17:16:07 -0700228 @Override
229 public Map<IpAddress, IpAddress> getIpAddressMappings() {
230 return Collections.unmodifiableMap(ipAddressMap);
231 }
232
Pingping Lin53ae34f2015-06-09 10:07:08 -0700233 @Override
234 public synchronized boolean assignSpecifiedPublicIp(IpAddress publicIpAddress,
235 IpAddress privateIpAddress) {
236
237 // Judge whether this public IP address is in our public IP
238 // prefix/address list.
239 boolean isPublicIpExist = false;
240 for (Entry<IpPrefix, Boolean> prefix: localPublicIpPrefixes.entrySet()) {
241 if (prefix.getKey().contains(publicIpAddress)) {
242 isPublicIpExist = true;
243
244 // Judge whether this public IP address is already assigned
245 if (!prefix.getValue() ||
246 isAssignedPublicIpAddress(publicIpAddress)) {
247 log.info("The public IP address {} is already assigned, "
248 + "and not available.", publicIpAddress);
249 return false;
250 }
251
252 // The public IP address is still available
253 // Store the mapping from private IP address to public IP address
254 ipAddressMap.put(privateIpAddress, publicIpAddress);
255
256 // Update the prefix status
257 if (prefix.getKey().prefixLength() == 32) {
258 updateIpPrefixStatus(prefix.getKey(), false);
259 return true;
260 }
261
262 // Judge whether the prefix of this public IP address is used
263 // up, if so, update the IP prefix status.
Ray Milkey961b19f2018-02-05 13:47:55 -0800264 double prefixLen = prefix.getKey().prefixLength();
Pingping Lin53ae34f2015-06-09 10:07:08 -0700265 int availableIpNum = (int) Math.pow(2,
266 IpPrefix.MAX_INET_MASK_LENGTH - prefixLen) - 1;
267 int usedIpNum = 0;
268 for (Entry<IpAddress, IpAddress> ipAddressMapEntry:
269 ipAddressMap.entrySet()) {
270 if (prefix.getKey().contains(ipAddressMapEntry.getValue())) {
271 usedIpNum = usedIpNum + 1;
272 }
273 }
274 if (usedIpNum == availableIpNum) {
275 updateIpPrefixStatus(prefix.getKey(), false);
276 }
277
278 return true;
279 }
280 }
Ray Milkeyfe0e0852018-01-18 11:14:05 -0800281
282 log.info("The public IP address {} retrieved from XOS mapping does "
283 + "not exist", publicIpAddress);
284
Pingping Lin53ae34f2015-06-09 10:07:08 -0700285 return false;
286 }
287
Pingping Linffa27d32015-04-30 14:41:03 -0700288 /**
289 * Generates a new IP address base on a given IP address plus a number to
290 * increase.
291 *
292 * @param ipAddress the IP address to increase
293 * @param num the number for ipAddress to add
294 * @return the new IP address after increase
295 */
296 private IpAddress increaseIpAddress(IpAddress ipAddress, int num) {
297 if (ipAddress.isIp6()) {
298 log.info("vBNG currently does not handle IPv6");
299 return null;
300 }
301 return IpAddress.valueOf(ipAddress.getIp4Address().toInt() + num);
302 }
303
304 /**
305 * Updates the IP prefix status in the local public IP prefix table.
306 *
307 * @param ipPprefix the IP prefix to update
308 * @param b the new value for the IP prefix
309 */
310 private void updateIpPrefixStatus(IpPrefix ipPprefix, boolean b) {
311 localPublicIpPrefixes.replace(ipPprefix, b);
312 }
313
314}