sanghoshin
Committed by Gerrit Code Review

SONA : OpenstackSwitching

 - Stateless Neutron data handling
 - Supports Nicira ext.

Change-Id: I31db161bbd06a03e2d8e6ee6abfb033215898ee7
Showing 16 changed files with 629 additions and 401 deletions
......@@ -32,7 +32,8 @@ public final class OpenstackPort {
public enum PortStatus {
UP,
DOWN
DOWN,
ACTIVE
}
private PortStatus status;
......
......@@ -15,6 +15,8 @@
*/
package org.onosproject.openstackswitching;
import org.onosproject.net.Port;
import java.util.Collection;
/**
......@@ -64,6 +66,14 @@ public interface OpenstackSwitchingService {
Collection<OpenstackPort> ports(String networkId);
/**
* Returns port information for the port given.
*
* @param port port reference
* @return port information
*/
OpenstackPort port(Port port);
/**
* Returns port information for the port ID given.
*
* @param portId Port ID
......
......@@ -16,11 +16,13 @@
-->
<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
<repository>mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features</repository>
<feature name="onos-app-openstackswitching" version="${project.version}"
<feature name="${project.artifactId}" version="${project.version}"
description="${project.description}">
<feature>onos-api</feature>
<bundle>mvn:${project.groupId}/onos-app-openstackswitching/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-app-dhcp-api/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-app-dhcp/${project.version}</bundle>
<bundle>mvn:com.sun.jersey/jersey-client/1.19</bundle>
<bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
</feature>
</features>
......
......@@ -90,6 +90,11 @@
<artifactId>onos-app-dhcp-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19</version>
</dependency>
</dependencies>
<build>
......@@ -110,6 +115,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,
......
......@@ -28,7 +28,8 @@ import org.onosproject.net.packet.PacketService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Handles ARP packet from VMs.
......@@ -38,16 +39,16 @@ public class OpenstackArpHandler {
private static Logger log = LoggerFactory
.getLogger(OpenstackArpHandler.class);
private PacketService packetService;
private Map<String, OpenstackPort> openstackPortMap;
private OpenstackRestHandler restHandler;
/**
* Returns OpenstackArpHandler reference.
*
* @param openstackPortMap
* @param packetService
* @param restHandler rest API handler reference
* @param packetService PacketService reference
*/
public OpenstackArpHandler(Map<String, OpenstackPort> openstackPortMap, PacketService packetService) {
this.openstackPortMap = openstackPortMap;
public OpenstackArpHandler(OpenstackRestHandler restHandler, PacketService packetService) {
this.restHandler = checkNotNull(restHandler);
this.packetService = packetService;
}
......@@ -68,8 +69,9 @@ public class OpenstackArpHandler {
//Searches the Dst MAC Address based on openstackPortMap
MacAddress macAddress = null;
OpenstackPort openstackPort = openstackPortMap.values().stream().filter(e -> e.fixedIps().
containsValue(Ip4Address.valueOf(dstIPAddress))).findAny().orElse(null);
OpenstackPort openstackPort = restHandler.getPorts().stream().
filter(e -> e.fixedIps().containsValue(Ip4Address.valueOf(
dstIPAddress))).findAny().orElse(null);
if (openstackPort != null) {
macAddress = openstackPort.macAddress();
......
/*
* 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.openstackswitching;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.onosproject.openstackswitching.web.OpenstackNetworkCodec;
import org.onosproject.openstackswitching.web.OpenstackPortCodec;
import org.onosproject.openstackswitching.web.OpenstackSubnetCodec;
import org.slf4j.Logger;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.net.MediaType.JSON_UTF_8;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Handles REST Calls to Openstack Neutron.
*
*/
public class OpenstackRestHandler {
private final Logger log = getLogger(getClass());
private String neutronUrl;
private String keystoneUrl;
private String tokenId;
private String userName;
private String pass;
/**
* Creates OpenstackRestHandler instance.
*
* @param cfg OpenstackSwitchingConfig reference
*/
public OpenstackRestHandler(OpenstackSwitchingConfig cfg) {
this.neutronUrl = checkNotNull(cfg.neutronServer());
this.keystoneUrl = checkNotNull(cfg.keystoneServer());
this.userName = checkNotNull(cfg.userName());
this.pass = checkNotNull(cfg.password());
}
/**
* Returns network information stored in Neutron.
*
* @return List of OpenstackNetwork
*/
public Collection<OpenstackNetwork> getNetworks() {
WebResource.Builder builder = getClientBuilder(neutronUrl + "networks");
String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
header("X-Auth-Token", getToken()).get(String.class);
ObjectMapper mapper = new ObjectMapper();
List<OpenstackNetwork> openstackNetworks = Lists.newArrayList();
try {
ObjectNode node = (ObjectNode) mapper.readTree(response);
ArrayNode networkList = (ArrayNode) node.path("networks");
OpenstackNetworkCodec networkCodec = new OpenstackNetworkCodec();
networkList.forEach(n -> openstackNetworks.add(networkCodec.decode((ObjectNode) n, null)));
} catch (IOException e) {
e.printStackTrace();
}
log.debug("networks response:" + response);
openstackNetworks.forEach(n -> log.debug("network ID: {}", n.id()));
return openstackNetworks;
}
/**
* Returns port information stored in Neutron.
*
* @return List of OpenstackPort
*/
public Collection<OpenstackPort> getPorts() {
WebResource.Builder builder = getClientBuilder(neutronUrl + "ports");
String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
header("X-Auth-Token", getToken()).get(String.class);
ObjectMapper mapper = new ObjectMapper();
List<OpenstackPort> openstackPorts = Lists.newArrayList();
try {
ObjectNode node = (ObjectNode) mapper.readTree(response);
ArrayNode portList = (ArrayNode) node.path("ports");
OpenstackPortCodec portCodec = new OpenstackPortCodec();
portList.forEach(p -> openstackPorts.add(portCodec.decode((ObjectNode) p, null)));
} catch (IOException e) {
e.printStackTrace();
}
log.debug("port response:" + response);
openstackPorts.forEach(n -> log.debug("port ID: {}", n.id()));
return openstackPorts;
}
/**
* Returns Subnet information in Neutron.
*
* @return List of OpenstackSubnet
*/
public Collection<OpenstackSubnet> getSubnets() {
WebResource.Builder builder = getClientBuilder(neutronUrl + "subnets");
String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
header("X-Auth-Token", getToken()).get(String.class);
ObjectMapper mapper = new ObjectMapper();
List<OpenstackSubnet> subnets = Lists.newArrayList();
try {
ObjectNode node = (ObjectNode) mapper.readTree(response);
ArrayNode subnetList = (ArrayNode) node.path("subnets");
OpenstackSubnetCodec subnetCodec = new OpenstackSubnetCodec();
subnetList.forEach(s -> subnets.add(subnetCodec.decode((ObjectNode) s, null)));
} catch (IOException e) {
e.printStackTrace();
}
log.debug("subnets response:" + response);
subnets.forEach(s -> log.debug("subnet ID: {}", s.id()));
return subnets;
}
private WebResource.Builder getClientBuilder(String uri) {
Client client = Client.create();
WebResource resource = client.resource(uri);
return resource.accept(JSON_UTF_8.toString())
.type(JSON_UTF_8.toString());
}
private String getToken() {
if (isTokenInvalid()) {
String request = "{\"auth\": {\"tenantName\": \"admin\", " +
"\"passwordCredentials\": {\"username\": \"" +
userName + "\",\"password\": \"" + pass + "\"}}}";
WebResource.Builder builder = getClientBuilder(keystoneUrl + "tokens");
String response = builder.accept(MediaType.APPLICATION_JSON).post(String.class, request);
ObjectMapper mapper = new ObjectMapper();
try {
ObjectNode node = (ObjectNode) mapper.readTree(response);
tokenId = node.path("access").path("token").path("id").asText();
} catch (IOException e) {
e.printStackTrace();
}
log.debug("token response:" + response);
}
return tokenId;
}
private boolean isTokenInvalid() {
//TODO: validation check for the existing token
return true;
}
}
......@@ -24,6 +24,10 @@ import org.onosproject.net.config.basics.BasicElementConfig;
*/
public class OpenstackSwitchingConfig extends Config<ApplicationId> {
public static final String DONOTPUSH = "do_not_push_flows";
public static final String NEUTRON_SERVER = "neutron_server";
public static final String KEYSTONE_SERVER = "keystone_server";
public static final String USER_NAME = "user_name";
public static final String PASSWORD = "password";
/**
* Returns the flag whether the app pushes flows or not.
......@@ -36,6 +40,42 @@ public class OpenstackSwitchingConfig extends Config<ApplicationId> {
}
/**
* Returns the Neutron server IP address.
*
* @return Neutron server IP
*/
public String neutronServer() {
return get(NEUTRON_SERVER, "");
}
/**
* Returns the Keystone server IP address.
*
* @return Keystone server IP
*/
public String keystoneServer() {
return get(KEYSTONE_SERVER, "");
}
/**
* Returns the username for openstack.
*
* @return username for openstack
*/
public String userName() {
return get(USER_NAME, "");
}
/**
* Returns the password for openstack.
*
* @return password for openstack
*/
public String password() {
return get(PASSWORD, "");
}
/**
* Sets the flag whether the app pushes flows or not.
*
* @param flag the flag whether the app pushes flows or not
......@@ -44,4 +84,44 @@ public class OpenstackSwitchingConfig extends Config<ApplicationId> {
public BasicElementConfig doNotPushFlows(boolean flag) {
return (BasicElementConfig) setOrClear(DONOTPUSH, flag);
}
/**
* Sets the neutron server IP address.
*
* @param url neutron server IP address
* @return itself
*/
public BasicElementConfig neutronServer(String url) {
return (BasicElementConfig) setOrClear(NEUTRON_SERVER, url);
}
/**
* Sets the keystone server IP address.
*
* @param url keystone server IP address
* @return itself
*/
public BasicElementConfig keystoneServer(String url) {
return (BasicElementConfig) setOrClear(KEYSTONE_SERVER, url);
}
/**
* Sets the username for openstack.
*
* @param username user name for openstack
* @return itself
*/
public BasicElementConfig userName(String username) {
return (BasicElementConfig) setOrClear(USER_NAME, username);
}
/**
* Sets the password for openstack.
*
* @param password password for openstack
* @return itself
*/
public BasicElementConfig password(String password) {
return (BasicElementConfig) setOrClear(PASSWORD, password);
}
}
......
......@@ -17,7 +17,6 @@ package org.onosproject.openstackswitching;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -26,8 +25,6 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.dhcp.DhcpService;
......@@ -41,6 +38,7 @@ import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.PacketContext;
......@@ -49,7 +47,6 @@ import org.onosproject.net.packet.PacketService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.ExecutorService;
......@@ -82,18 +79,23 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
protected FlowObjectiveService flowObjectiveService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry cfgService;
protected DhcpService dhcpService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DhcpService dhcpService;
protected NetworkConfigRegistry cfgService;
public static final int DHCP_PORT = 67;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DriverService driverService;
private ApplicationId appId;
private boolean doNotPushFlows;
private Ip4Address neutronServer;
private Ip4Address keystoneServer;
private String userName;
private String password;
private OpenstackArpHandler arpHandler;
private OpenstackRestHandler restHandler;
private OpenstackSwitchingRulePopulator rulePopulator;
private ExecutorService deviceEventExcutorService = Executors.newFixedThreadPool(10);
private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
......@@ -109,38 +111,18 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
}
}
);
// Map <port_id, OpenstackPort>
private Map<String, OpenstackPort> openstackPortMap;
// Map <network_id, OpenstackNetwork>
private Map<String, OpenstackNetwork> openstackNetworkMap;
// Map <subnet_id, OpenstackSubner>
private Map<String, OpenstackSubnet> openstackSubnetMap;
// Map <vni, List <Entry <portName, host ip>>
private Map<String, List<PortInfo>> vniPortMap;
private Map<Ip4Address, Port> tunnelPortMap;
@Activate
protected void activate() {
appId = coreService
.registerApplication("org.onosproject.openstackswitching");
factories.forEach(cfgService::registerConfigFactory);
packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
deviceService.addListener(internalDeviceListener);
cfgService.addListener(internalConfigListener);
factories.forEach(cfgService::registerConfigFactory);
OpenstackSwitchingConfig cfg =
cfgService.getConfig(appId, OpenstackSwitchingConfig.class);
if (cfg != null) {
doNotPushFlows = cfg.doNotPushFlows();
}
openstackPortMap = Maps.newHashMap();
openstackNetworkMap = Maps.newHashMap();
openstackSubnetMap = Maps.newHashMap();
vniPortMap = Maps.newHashMap();
tunnelPortMap = Maps.newHashMap();
arpHandler = new OpenstackArpHandler(openstackPortMap, packetService);
internalConfigListener.configureNetwork();
log.info("Started");
}
......@@ -159,7 +141,6 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
@Override
public void createPorts(OpenstackPort openstackPort) {
registerDhcpInfo(openstackPort);
openstackPortMap.put(openstackPort.id(), openstackPort);
}
@Override
......@@ -174,19 +155,16 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
@Override
public void createNetwork(OpenstackNetwork openstackNetwork) {
openstackNetworkMap.put(openstackNetwork.id(), openstackNetwork);
}
@Override
public void createSubnet(OpenstackSubnet openstackSubnet) {
openstackSubnetMap.put(openstackSubnet.id(), openstackSubnet);
log.debug("Added Subnet Info {}", openstackNetworkMap.get(openstackSubnet.id()));
}
@Override
public Collection<OpenstackPort> ports(String networkId) {
List<OpenstackPort> portList = openstackPortMap.values().stream()
Collection<OpenstackPort> ports = restHandler.getPorts();
List<OpenstackPort> portList = ports.stream()
.filter(p -> p.networkId().equals(networkId))
.collect(Collectors.toList());
......@@ -194,47 +172,46 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
}
@Override
public OpenstackPort port(String portName) {
String uuid = portName.substring(3);
return (OpenstackPort) openstackPortMap.values().stream()
public OpenstackPort port(Port port) {
Collection<OpenstackPort> ports = restHandler.getPorts();
String uuid = port.annotations().value("portName").substring(3);
return ports.stream()
.filter(p -> p.id().startsWith(uuid))
.findFirst().get().clone();
.findFirst().orElse(null);
}
@Override
public OpenstackNetwork network(String networkId) {
OpenstackNetwork on = null;
try {
on = (OpenstackNetwork) openstackNetworkMap.get(networkId).clone();
} catch (CloneNotSupportedException e) {
log.error("Cloning is not supported {}", e);
public OpenstackPort port(String portId) {
Collection<OpenstackPort> ports = restHandler.getPorts();
return ports.stream()
.filter(p -> p.id().equals(portId))
.findFirst().orElse(null);
}
return on;
@Override
public OpenstackNetwork network(String networkId) {
Collection<OpenstackNetwork> networks = restHandler.getNetworks();
return networks.stream()
.filter(n -> n.id().equals(networkId))
.findFirst().orElse(null);
}
private void processDeviceAdded(Device device) {
log.debug("device {} is added", device.id());
rulePopulator.populateDefaultRules(device.id());
}
private void processPortAdded(Device device, Port port) {
// TODO: Simplify the data structure to store the network info
// TODO: Make it stateless
// TODO: All the logics need to be processed inside of the rulePopulator class
synchronized (vniPortMap) {
log.debug("port {} is updated", port.toString());
updatePortMaps(device, port);
if (!port.annotations().value("portName").equals("vxlan")) {
populateFlowRulesForTrafficToSameCnode(device, port);
populateFlowRulesForTrafficToDifferentCnode(device, port);
}
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
deviceService, restHandler, driverService);
rulePopulator.populateSwitchingRules(device, port);
}
}
private void processPortRemoved(Device device, Port port) {
// TODO: Remove flow rules for the VM removed
log.debug("port {} is removed", port.toString());
// TODO: need to update the vniPortMap
}
private void registerDhcpInfo(OpenstackPort openstackPort) {
......@@ -247,7 +224,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
ip4Address = (Ip4Address) openstackPort.fixedIps().values().toArray()[0];
openstackSubnet = openstackSubnetMap.values().stream()
openstackSubnet = restHandler.getSubnets().stream()
.filter(n -> n.networkId().equals(openstackPort.networkId()))
.findFirst().get();
......@@ -280,180 +257,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
return bytes;
}
/**
* Populates the flow rules for traffic to VMs in different Cnode using
* Nicira extention.
*
* @param device device to put rules
* @param port port information of the VM
*/
private void populateFlowRulesForTrafficToDifferentCnode(Device device, Port port) {
String portName = port.annotations().value("portName");
String channelId = device.annotations().value("channelId");
Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]);
Ip4Address fixedIp = getFixedIpAddressForPort(portName);
// TODO: Avoid duplicate flow rule set up for VMs in other Cnode
// (possibly avoided by flowrule subsystem?)
if (tunnelPortMap.get(hostIpAddress) == null) {
log.debug("There is no tunnel port information");
return;
}
String vni = getVniForPort(portName);
MacAddress vmMac = getVmMacAddressForPort(portName);
if (!vniPortMap.isEmpty() && vniPortMap.get(vni) != null) {
for (PortInfo portInfo : vniPortMap.get(vni)) {
if (!portInfo.portName.equals(portName) &&
!portInfo.hostIp.equals(hostIpAddress)) {
MacAddress vmMacx = getVmMacAddressForPort(portInfo.portName);
rulePopulator.populateForwardingRuleForOtherCnode(vni,
device.id(), portInfo.hostIp, portInfo.fixedIp, vmMacx,
tunnelPortMap.get(hostIpAddress).number(),
portInfo.deviceId, hostIpAddress, fixedIp, vmMac,
tunnelPortMap.get(portInfo.hostIp).number());
}
}
}
}
/**
* Populates the flow rules for traffic to VMs in the same Cnode as the sender.
*
* @param device device to put the rules
* @param port port info of the VM
*/
private void populateFlowRulesForTrafficToSameCnode(Device device, Port port) {
Ip4Prefix cidr = getCidrForPort(port.annotations().value("portName"));
Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName"));
if (vmIp != null) {
rulePopulator.populateForwardingRule(vmIp, device.id(), port, cidr);
}
}
/**
* Updates the port maps using the port information.
*
* @param device device info
* @param port port of the VM
*/
private void updatePortMaps(Device device, Port port) {
String portName = port.annotations().value("portName");
String channelId = device.annotations().value("channelId");
Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]);
if (portName.startsWith("vxlan")) {
tunnelPortMap.put(hostIpAddress, port);
} else {
String vni = getVniForPort(portName);
Ip4Address fixedIp = getFixedIpAddressForPort(portName);
if (vniPortMap.get(vni) == null) {
vniPortMap.put(vni, Lists.newArrayList());
}
vniPortMap.get(vni).add(new PortInfo(device.id(), portName, fixedIp, hostIpAddress));
}
}
/**
* Returns CIDR information from the subnet map for the port.
*
* @param portName port name of the port of the VM
* @return CIDR of the VNI of the VM
*/
private Ip4Prefix getCidrForPort(String portName) {
String networkId = null;
String uuid = portName.substring(3);
OpenstackPort port = openstackPortMap.values().stream()
.filter(p -> p.id().startsWith(uuid))
.findFirst().get();
if (port == null) {
log.debug("No port information for port {}", portName);
return null;
}
OpenstackSubnet subnet = openstackSubnetMap.values().stream()
.filter(s -> s.networkId().equals(port.networkId()))
.findFirst().get();
if (subnet == null) {
log.debug("No subnet information for network {}", port.networkId());
return null;
}
return Ip4Prefix.valueOf(subnet.cidr());
}
/**
* Returns the VNI of the VM of the port.
*
* @param portName VM port
* @return VNI
*/
private String getVniForPort(String portName) {
String networkId = null;
String uuid = portName.substring(3);
OpenstackPort port = openstackPortMap.values().stream()
.filter(p -> p.id().startsWith(uuid))
.findFirst().get();
if (port == null) {
log.debug("No port information for port {}", portName);
return null;
}
OpenstackNetwork network = openstackNetworkMap.values().stream()
.filter(n -> n.id().equals(port.networkId()))
.findFirst().get();
if (network == null) {
log.debug("No VNI information for network {}", network.id());
return null;
}
return network.segmentId();
}
/**
* Returns the Fixed IP address of the VM.
*
* @param portName VM port info
* @return IP address of the VM
*/
private Ip4Address getFixedIpAddressForPort(String portName) {
// FIXME - For now we use the information stored from neutron Rest API call.
// TODO - Later, the information needs to be extracted from Neutron on-demand.
String uuid = portName.substring(3);
OpenstackPort port = openstackPortMap.values().stream()
.filter(p -> p.id().startsWith(uuid))
.findFirst().get();
if (port == null) {
log.error("There is no port information for port name {}", portName);
return null;
}
if (port.fixedIps().isEmpty()) {
log.error("There is no fixed IP info in the port information");
return null;
}
return (Ip4Address) port.fixedIps().values().toArray()[0];
}
/**
* Returns the MAC address of the VM of the port.
*
* @param portName VM port
* @return MAC address of the VM
*/
private MacAddress getVmMacAddressForPort(String portName) {
String uuid = portName.substring(3);
OpenstackPort port = openstackPortMap.values().stream()
.filter(p -> p.id().startsWith(uuid))
.findFirst().get();
if (port == null) {
log.error("There is no mac information for port name {}", portName);
return null;
}
return port.macAddress();
}
private class InternalPacketProcessor implements PacketProcessor {
......@@ -529,19 +333,27 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
private class InternalConfigListener implements NetworkConfigListener {
public void configureNetwork() {
OpenstackSwitchingConfig cfg =
cfgService.getConfig(appId, OpenstackSwitchingConfig.class);
if (cfg == null) {
log.error("There is no openstack server information in config.");
return;
}
doNotPushFlows = cfg.doNotPushFlows();
restHandler = new OpenstackRestHandler(cfg);
arpHandler = new OpenstackArpHandler(restHandler, packetService);
}
@Override
public void event(NetworkConfigEvent event) {
if (((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)) &&
event.configClass().equals(OpenstackSwitchingConfig.class)) {
OpenstackSwitchingConfig cfg = cfgService.getConfig(appId,
OpenstackSwitchingConfig.class);
if (cfg != null) {
doNotPushFlows = cfg.doNotPushFlows();
log.info("Switching mode reconfigured");
}
configureNetwork();
}
}
}
private final class PortInfo {
......
......@@ -17,25 +17,35 @@
package org.onosproject.openstackswitching;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.TpPort;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.DefaultDriverData;
import org.onosproject.net.driver.DefaultDriverHandler;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
import org.onosproject.net.flow.instructions.ExtensionPropertyException;
import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
/**
* Populates switching flow rules.
*/
......@@ -43,123 +53,168 @@ public class OpenstackSwitchingRulePopulator {
private static Logger log = LoggerFactory
.getLogger(OpenstackSwitchingRulePopulator.class);
private static final int SWITCHING_RULE_PRIORITY = 50000;
private FlowObjectiveService flowObjectiveService;
private DriverService driverService;
private DeviceService deviceService;
private OpenstackRestHandler restHandler;
private ApplicationId appId;
private Collection<OpenstackNetwork> openstackNetworkList;
private Collection<OpenstackPort> openstackPortList;
/**
* Creates OpenstackSwitchingRulPopulator.
*
* @param appId application id
* @param flowObjectiveService FlowObjectiveService reference
* @param deviceService DeviceService reference
* @param driverService DriverService reference
*/
public OpenstackSwitchingRulePopulator(ApplicationId appId,
FlowObjectiveService flowObjectiveService) {
FlowObjectiveService flowObjectiveService,
DeviceService deviceService,
OpenstackRestHandler restHandler,
DriverService driverService) {
this.flowObjectiveService = flowObjectiveService;
this.deviceService = deviceService;
this.driverService = driverService;
this.restHandler = restHandler;
this.appId = appId;
openstackNetworkList = restHandler.getNetworks();
openstackPortList = restHandler.getPorts();
}
/**
* Populates flows rules for forwarding packets to and from VMs.
* Populates flow rules for the VM created.
*
* @param ip v4 IP Address
* @param id device ID
* @param port port
* @param cidr v4 IP prefix
* @return true if it succeeds to populate rules, false otherwise.
* @param device device to populate rules to
* @param port port for the VM created
*/
public boolean populateForwardingRule(Ip4Address ip, DeviceId id, Port port, Ip4Prefix cidr) {
setFlowRuleForVMsInSameCnode(ip, id, port, cidr);
return true;
public void populateSwitchingRules(Device device, Port port) {
populateFlowRulesForTrafficToSameCnode(device, port);
populateFlowRulesForTrafficToDifferentCnode(device, port);
}
/**
* Populates the common flows rules for all VMs.
* Populates the flow rules for traffic to VMs in the same Cnode as the sender.
*
* - Send ARP packets to the controller
* - Send DHCP packets to the controller
*
* @param id Device ID to populates rules to
* @param device device to put the rules
* @param port port info of the VM
*/
public void populateDefaultRules(DeviceId id) {
private void populateFlowRulesForTrafficToSameCnode(Device device, Port port) {
Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName"));
if (vmIp != null) {
setFlowRuleForVMsInSameCnode(vmIp, device.id(), port);
}
}
setFlowRuleForArp(id);
/**
* Populates the flow rules for traffic to VMs in different Cnode using
* Nicira extention.
*
* @param device device to put rules
* @param port port information of the VM
*/
private void populateFlowRulesForTrafficToDifferentCnode(Device device, Port port) {
String portName = port.annotations().value("portName");
String channelId = device.annotations().value("channelId");
Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]);
Ip4Address fixedIp = getFixedIpAddressForPort(portName);
MacAddress vmMac = getVmMacAddressForPort(portName);
String vni = getVniForPort(portName);
deviceService.getAvailableDevices().forEach(d -> {
if (!d.equals(device)) {
deviceService.getPorts(d.id()).forEach(p -> {
String pName = p.annotations().value("portName");
if (!p.equals(port) && vni.equals(getVniForPort(pName))) {
String cidx = d.annotations().value("channelId");
Ip4Address hostIpx = Ip4Address.valueOf(cidx.split(":")[0]);
MacAddress vmMacx = getVmMacAddressForPort(pName);
Ip4Address fixedIpx = getFixedIpAddressForPort(pName);
log.warn("Default rule has been set");
setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx, vmMacx);
setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp, vmMac);
}
});
}
});
}
/**
* Populates the forwarding rules for VMs with the same VNI but in other Code.
* Returns the VNI of the VM of the port.
*
* @param vni VNI for the networks
* @param id device ID to populates the flow rules
* @param hostIp host IP address of the VM
* @param vmIp fixed IP address for the VM
* @param vmMac MAC address for the VM
* @param tunnelPort tunnel port number for the VM
* @param idx device ID for OVS of the other VM
* @param hostIpx host IP address of the other VM
* @param vmIpx fixed IP address of the other VM
* @param vmMacx MAC address for the other VM
* @param tunnelPortx x tunnel port number for other VM
* @param portName VM port
* @return VNI
*/
public void populateForwardingRuleForOtherCnode(String vni, DeviceId id, Ip4Address hostIp,
Ip4Address vmIp, MacAddress vmMac, PortNumber tunnelPort,
DeviceId idx, Ip4Address hostIpx,
Ip4Address vmIpx, MacAddress vmMacx, PortNumber tunnelPortx) {
setVxLanFlowRule(vni, id, hostIp, vmIp, vmMac, tunnelPort);
setVxLanFlowRule(vni, idx, hostIpx, vmIpx, vmMacx, tunnelPortx);
private String getVniForPort(String portName) {
String uuid = portName.substring(3);
OpenstackPort port = openstackPortList.stream()
.filter(p -> p.id().startsWith(uuid))
.findAny().orElse(null);
if (port == null) {
log.warn("No port information for port {}", portName);
return null;
}
OpenstackNetwork network = openstackNetworkList.stream()
.filter(n -> n.id().equals(port.networkId()))
.findAny().orElse(null);
if (network == null) {
log.warn("No VNI information for network {}", network.id());
return null;
}
return network.segmentId();
}
/**
* Populates the flow rules for DHCP packets from VMs.
* Returns the Fixed IP address of the VM.
*
* @param id device ID to set the rules
* @param portName VM port info
* @return IP address of the VM
*/
private void setFlowRuleForDhcp(DeviceId id) {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
private Ip4Address getFixedIpAddressForPort(String portName) {
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_UDP)
.matchUdpDst(TpPort.tpPort(OpenstackSwitchingManager.DHCP_PORT));
tBuilder.setOutput(PortNumber.CONTROLLER);
String uuid = portName.substring(3);
OpenstackPort port = openstackPortList.stream()
.filter(p -> p.id().startsWith(uuid))
.findFirst().orElse(null);
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withPriority(5000)
.withFlag(ForwardingObjective.Flag.VERSATILE)
.fromApp(appId)
.add();
if (port == null) {
log.error("There is no port information for port name {}", portName);
return null;
}
flowObjectiveService.forward(id, fo);
if (port.fixedIps().isEmpty()) {
log.error("There is no fixed IP info in the port information");
return null;
}
return (Ip4Address) port.fixedIps().values().toArray()[0];
}
/**
* Populates the flow rules for ARP packets from VMs.
* Returns the MAC address of the VM of the port.
*
* @param id device ID to put rules.
* @param portName VM port
* @return MAC address of the VM
*/
private void setFlowRuleForArp(DeviceId id) {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
private MacAddress getVmMacAddressForPort(String portName) {
sBuilder.matchEthType(Ethernet.TYPE_ARP);
tBuilder.setOutput(PortNumber.CONTROLLER);
String uuid = portName.substring(3);
OpenstackPort port = openstackPortList.stream()
.filter(p -> p.id().startsWith(uuid))
.findFirst().orElse(null);
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withPriority(5000)
.withFlag(ForwardingObjective.Flag.VERSATILE)
.fromApp(appId)
.add();
if (port == null) {
log.error("There is port information for port name {}", portName);
return null;
}
flowObjectiveService.forward(id, fo);
return port.macAddress();
}
/**
......@@ -168,22 +223,20 @@ public class OpenstackSwitchingRulePopulator {
* @param ip4Address VM IP address
* @param id device ID to put rules
* @param port VM port
* @param cidr subnet info of the VMs
*/
private void setFlowRuleForVMsInSameCnode(Ip4Address ip4Address, DeviceId id,
Port port, Ip4Prefix cidr) {
Port port) {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(ip4Address.toIpPrefix())
.matchIPSrc(cidr);
.matchIPDst(ip4Address.toIpPrefix());
tBuilder.setOutput(port.number());
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withPriority(5000)
.withPriority(SWITCHING_RULE_PRIORITY)
.withFlag(ForwardingObjective.Flag.VERSATILE)
.fromApp(appId)
.add();
......@@ -199,28 +252,56 @@ public class OpenstackSwitchingRulePopulator {
* @param hostIp host IP of the VM
* @param vmIp fixed IP of the VM
* @param vmMac MAC address of the VM
* @param tunnelPort tunnel port to forward traffic to
*/
private void setVxLanFlowRule(String vni, DeviceId id, Ip4Address hostIp,
Ip4Address vmIp, MacAddress vmMac, PortNumber tunnelPort) {
Ip4Address vmIp, MacAddress vmMac) {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(vmIp.toIpPrefix());
tBuilder.setTunnelId(Long.parseLong(vni))
//.setTunnelDst() <- for Nicira ext
//.setEthDst(vmMac)
.setOutput(tunnelPort);
.extension(buildNiciraExtenstion(id, hostIp), id)
.setOutput(getTunnelPort(id));
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withPriority(5000)
.withPriority(SWITCHING_RULE_PRIORITY)
.withFlag(ForwardingObjective.Flag.VERSATILE)
.fromApp(appId)
.add();
flowObjectiveService.forward(id, fo);
}
private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
Driver driver = driverService.getDriver(id);
DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id));
ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class);
ExtensionTreatment extensionInstruction =
resolver.getExtensionInstruction(
ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type());
try {
extensionInstruction.setPropertyValue("tunnelDst", hostIp);
} catch (ExtensionPropertyException e) {
log.error("Error setting Nicira extension setting {}", e);
}
return extensionInstruction;
}
private PortNumber getTunnelPort(DeviceId id) {
Port port = deviceService.getPorts(id).stream()
.filter(p -> p.annotations().value("portName").equals("vxlan"))
.findAny().orElse(null);
if (port == null) {
log.error("No TunnelPort was created.");
return null;
}
return port.number();
}
}
......
......@@ -43,6 +43,9 @@ public class OpenstackNetworkCodec extends JsonCodec<OpenstackNetwork> {
public OpenstackNetwork decode(ObjectNode json, CodecContext context) {
JsonNode networkInfo = json.get(NETWORK);
if (networkInfo == null) {
networkInfo = json;
}
String name = networkInfo.path(NAME).asText();
String tenantId = networkInfo.path(TENANT_ID).asText();
......
......@@ -15,48 +15,52 @@
*/
package org.onosproject.openstackswitching.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.openstackswitching.OpenstackNetwork;
import org.onosproject.openstackswitching.OpenstackSwitchingService;
import org.onosproject.rest.AbstractWebResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
/**
* Handles REST API call of Neutron ML2 plugin.
*/
@Path("networks")
public class OpenstackNetworkWebResource extends AbstractWebResource {
protected static final Logger log = LoggerFactory
.getLogger(OpenstackNetworkWebResource.class);
private static final OpenstackNetworkCodec NETWORK_CODEC = new OpenstackNetworkCodec();
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createNetwork(InputStream input) {
try {
ObjectMapper mapper = new ObjectMapper();
ObjectNode networkNode = (ObjectNode) mapper.readTree(input);
OpenstackNetwork openstackNetwork = NETWORK_CODEC.decode(networkNode, this);
log.debug("REST API networks is called {}", input.toString());
return Response.status(Response.Status.OK).build();
}
OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class);
switchingService.createNetwork(openstackNetwork);
@PUT
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response updateNetwork(InputStream input) {
log.debug("REST API networks is called {}", input.toString());
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
log.error("Creates VirtualPort failed because of exception {}",
e.toString());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
.build();
}
@DELETE
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response deleteNetwork(InputStream input) {
log.debug("REST API networks is called {}", input.toString());
return Response.status(Response.Status.OK).build();
}
}
......
......@@ -58,6 +58,9 @@ public class OpenstackPortCodec extends JsonCodec<OpenstackPort> {
HashMap<String, Ip4Address> fixedIpMap = new HashMap<>();
JsonNode portInfo = json.get(PORT);
if (portInfo == null) {
portInfo = json;
}
String status = portInfo.path(STATUS).asText();
String name = portInfo.path(NAME).asText();
......
......@@ -33,6 +33,9 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
/**
* Handles Rest API call from Neutron ML2 plugin.
*/
@Path("ports")
public class OpenstackPortWebResource extends AbstractWebResource {
......@@ -50,13 +53,15 @@ public class OpenstackPortWebResource extends AbstractWebResource {
ObjectNode portNode = (ObjectNode) mapper.readTree(input);
OpenstackPort openstackPort = PORT_CODEC.decode(portNode, this);
OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class);
OpenstackSwitchingService switchingService =
getService(OpenstackSwitchingService.class);
switchingService.createPorts(openstackPort);
log.debug("REST API ports is called with {}", portNode.toString());
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
log.error("Creates VirtualPort failed because of exception {}",
log.error("Creates Port failed because of exception {}",
e.toString());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
.build();
......@@ -64,23 +69,12 @@ public class OpenstackPortWebResource extends AbstractWebResource {
}
@DELETE
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response deletesPorts(InputStream input) {
try {
ObjectMapper mapper = new ObjectMapper();
ObjectNode portNode = (ObjectNode) mapper.readTree(input);
OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class);
switchingService.deletePorts();
log.info("REST API ports is called with {}", portNode.toString());
log.debug("REST API ports is called with {}", input.toString());
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
log.error("Delete VirtualPort failed because of exception {}",
e.toString());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
.build();
}
}
@PUT
......@@ -88,19 +82,7 @@ public class OpenstackPortWebResource extends AbstractWebResource {
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response updatePorts(InputStream input) {
try {
ObjectMapper mapper = new ObjectMapper();
ObjectNode portNode = (ObjectNode) mapper.readTree(input);
OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class);
switchingService.updatePorts();
log.info("REST API ports is called with {}", portNode.toString());
log.info("REST API ports is called with {}", input.toString());
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
log.error("Update VirtualPort failed because of exception {}",
e.toString());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
.build();
}
}
}
......
......@@ -51,6 +51,9 @@ public class OpenstackSubnetCodec extends JsonCodec<OpenstackSubnet> {
@Override
public OpenstackSubnet decode(ObjectNode json, CodecContext context) {
JsonNode subnetInfo = json.get(SUBNET);
if (subnetInfo == null) {
subnetInfo = json;
}
String name = subnetInfo.path(NAME).asText();
boolean enableDhcp = subnetInfo.path(ENABLE_DHCP).asBoolean();
......
......@@ -15,18 +15,19 @@
*/
package org.onosproject.openstackswitching.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.openstackswitching.OpenstackSubnet;
import org.onosproject.openstackswitching.OpenstackSwitchingService;
/**
* Handles Rest API call from Neutron ML2 plugin.
*/
import org.onosproject.rest.AbstractWebResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
......@@ -37,28 +38,32 @@ public class OpenstackSubnetWebResource extends AbstractWebResource {
protected static final Logger log = LoggerFactory
.getLogger(OpenstackSubnetWebResource.class);
private static final OpenstackSubnetCodec SUBNET_CODEC = new OpenstackSubnetCodec();
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createSubnet(InputStream input) {
try {
ObjectMapper mapper = new ObjectMapper();
ObjectNode subnetNode = (ObjectNode) mapper.readTree(input);
return Response.status(Response.Status.OK).build();
}
OpenstackSubnet openstackSubnet = SUBNET_CODEC.decode(subnetNode, this);
OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class);
switchingService.createSubnet(openstackSubnet);
log.debug("REST API subnets is called with {}", subnetNode.toString());
@PUT
@Path("{subnetUUID}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response updateSubnet(@PathParam("id") String id,
final InputStream input) {
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
log.error("Creates VirtualSubnet failed because of exception {}",
e.toString());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
.build();
}
@DELETE
@Path("{subnetUUID}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response deleteSubnet(@PathParam("id") String id,
final InputStream input) {
return Response.status(Response.Status.OK).build();
}
}
......
{
"apps" : {
"org.onosproject.openstackswitching" : {
"openstackswitching" : {
"do_not_push_flows" : "false",
"neutron_server" : "http://127.0.0.1:9696/v2.0/",
"keystone_server" : "http://127.0.0.1:5000/v2.0/",
"user_name" : "admin",
"password" : "nova"
}
},
"org.onosproject.dhcp" : {
"dhcp" : {
"ip": "10.0.0.1",
"mac": "1a:2b:3c:4e:5e:6f",
"subnet": "255.0.0.0",
"broadcast": "10.255.255.255",
"router": "10.0.0.1",
"domain": "10.0.0.1",
"ttl": "63",
"lease": "300",
"renew": "150",
"rebind": "200",
"delay": "3",
"timeout": "150",
"startip": "10.0.0.110",
"endip": "10.0.0.130"
}
},
"org.onosproject.cordvtn" : {
"cordvtn" : {
"ovsdbNodes" : [
{
"host" : "compute-01",
"ip" : "128.199.162.106",
"port" : "6640",
"bridgeId" : "of:0000000000000001"
},
{
"host" : "compute-02",
"ip" : "103.253.145.133",
"port" : "6640",
"bridgeId" : "of:0000000000000002"
},
{
"host" : "network",
"ip" : "128.199.125.11",
"port" : "6640",
"bridgeId" : "of:0000000000000003"
}
]
}
}
}
}