Pingping Lin
Committed by Gerrit Code Review

restart vBNG based on XOS's record

re-set up the private IP address to public IP address mapping
based on the mapping record in XOS.

re-calculates and re-installs all the intents.

Change-Id: I89aa75662da596b9793e02ba41398a43517ccecf
......@@ -18,6 +18,7 @@
<repository>mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features</repository>
<feature name="${project.artifactId}" version="${project.version}"
description="${project.description}">
<bundle>mvn:com.sun.jersey/jersey-client/1.19</bundle>
<bundle>mvn:${project.groupId}/onos-app-virtualbng/${project.version}</bundle>
<feature>onos-thirdparty-web</feature>
</feature>
......
......@@ -38,6 +38,11 @@
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-cli</artifactId>
<version>${project.version}</version>
......@@ -75,6 +80,7 @@
javax.ws.rs,
javax.ws.rs.core,
com.sun.jersey.api.core,
com.sun.jersey.api.client,
com.sun.jersey.spi.container.servlet,
com.sun.jersey.server.impl.container.servlet,
com.fasterxml.jackson.databind,
......
/*
* 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 static com.google.common.net.MediaType.JSON_UTF_8;
import static java.net.HttpURLConnection.HTTP_OK;
import static org.slf4j.LoggerFactory.getLogger;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import java.io.IOException;
import org.slf4j.Logger;
public class RestClient {
private final Logger log = getLogger(getClass());
private final String hostName = "10.254.1.22";
private final int xosServerPort = 8000;
private static final String UTF_8 = JSON_UTF_8.toString();
private static final ObjectMapper MAPPER = new ObjectMapper();
private final String url = "http://" + hostName + ":" + xosServerPort
+ "/xoslib/rs/vbng_mapping/";
/**
* Gets a client web resource builder.
*
* @param url the URL to access remote resource
* @return web resource builder
*/
public WebResource.Builder getClientBuilder(String url) {
log.info("URL: {}", url);
Client client = Client.create();
WebResource resource = client.resource(url);
return resource.accept(UTF_8).type(UTF_8);
}
/**
* Builds a REST client and fetches XOS mapping data in JSON format.
*
* @return the vBNG map if REST GET succeeds, otherwise return null
*/
public ObjectNode getRest() {
WebResource.Builder builder = getClientBuilder(url);
ClientResponse response = builder.get(ClientResponse.class);
if (response.getStatus() != HTTP_OK) {
log.info("REST GET request returned error code {}",
response.getStatus());
return null;
}
String jsonString = response.getEntity(String.class);
log.info("Fetched JSON string: {}", jsonString);
JsonNode node;
try {
node = MAPPER.readTree(jsonString);
} catch (IOException e) {
log.error("Failed to read JSON string", e);
return null;
}
return (ObjectNode) node;
}
}
......@@ -184,7 +184,7 @@ public class VbngConfigurationManager implements VbngConfigurationService {
}
@Override
public IpAddress recycleAssignedPublicIpAddress(IpAddress
public synchronized IpAddress recycleAssignedPublicIpAddress(IpAddress
privateIpAddress) {
IpAddress publicIpAddress = ipAddressMap.remove(privateIpAddress);
if (publicIpAddress == null) {
......@@ -210,6 +210,61 @@ public class VbngConfigurationManager implements VbngConfigurationService {
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.
......
......@@ -81,4 +81,16 @@ public interface VbngConfigurationService {
* @return the address map from private IP address to public IP address
*/
Map<IpAddress, IpAddress> getIpAddressMappings();
/**
* Tries to assign a given public IP address to a private IP address. If
* success, then sets up the mapping from this private IP address to the
* public IP address, and stores the mapping.
*
* @param publicIpAddress the public IP address try to assign
* @param privateIpAddress a private IP address
* @return true if this public IP address is available, otherwise false
*/
boolean assignSpecifiedPublicIp(IpAddress publicIpAddress,
IpAddress privateIpAddress);
}
......
......@@ -17,8 +17,12 @@ package org.onosproject.virtualbng;
import static com.google.common.base.Preconditions.checkNotNull;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Maps;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
......@@ -66,6 +70,7 @@ import org.slf4j.LoggerFactory;
public class VbngManager implements VbngService {
private static final String APP_NAME = "org.onosproject.virtualbng";
private static final String VBNG_MAP_NAME = "vbng_mapping";
private final Logger log = LoggerFactory.getLogger(getClass());
......@@ -113,6 +118,9 @@ public class VbngManager implements VbngService {
hostService.addListener(hostListener);
log.info("vBNG Started");
// Recover the status before vBNG restarts
statusRecovery();
}
@Deactivate
......@@ -122,6 +130,42 @@ public class VbngManager implements VbngService {
}
/**
* Recovers from XOS record. Re-sets up the mapping between private IP
* address and public IP address, re-calculates intents and re-installs
* those intents.
*/
private void statusRecovery() {
log.info("vBNG starts to recover from XOS record......");
RestClient restClient = new RestClient();
ObjectNode map = restClient.getRest();
if (map == null) {
log.info("Stop to recover vBNG status due to the vBNG map "
+ "is null!");
return;
}
log.info("Get record from XOS: {}", map);
ArrayNode array = (ArrayNode) map.get(VBNG_MAP_NAME);
Iterator<JsonNode> entries = array.elements();
while (entries.hasNext()) {
ObjectNode entry = (ObjectNode) entries.next();
IpAddress hostIpAdddress =
IpAddress.valueOf(entry.get("private_ip").asText());
IpAddress publicIpAddress =
IpAddress.valueOf(entry.get("routeable_subnet").asText());
MacAddress macAddress =
MacAddress.valueOf(entry.get("mac").asText());
String hostName = entry.get("hostname").asText();
// Create vBNG
createVbng(hostIpAdddress, publicIpAddress, macAddress, hostName);
}
}
/**
* Sets up mapping from hostname to connect point.
*/
private void setupMap() {
......@@ -136,6 +180,39 @@ public class VbngManager implements VbngService {
PortNumber.portNumber(47)));
}
/**
* Creates a new vBNG.
*
* @param privateIpAddress a private IP address
* @param publicIpAddress the public IP address for the private IP address
* @param hostMacAddress the MAC address for the private IP address
* @param hostName the host name for the private IP address
*/
private void createVbng(IpAddress privateIpAddress,
IpAddress publicIpAddress,
MacAddress hostMacAddress,
String hostName) {
boolean result = vbngConfigurationService
.assignSpecifiedPublicIp(publicIpAddress, privateIpAddress);
if (!result) {
log.info("Assign public IP address {} for private IP address {} "
+ "failed!", publicIpAddress, privateIpAddress);
log.info("Failed to create vBNG for private IP address {}",
privateIpAddress);
return;
}
log.info("[ADD] Private IP to Public IP mapping: {} --> {}",
privateIpAddress, publicIpAddress);
// Setup paths between the host configured with private IP and
// next hop
if (!setupForwardingPaths(privateIpAddress, publicIpAddress,
hostMacAddress, hostName)) {
privateIpAddressMap.put(privateIpAddress,
new VcpeHost(hostMacAddress, hostName));
}
}
@Override
public IpAddress createVbng(IpAddress privateIpAddress,
MacAddress hostMacAddress,
......