Hyunsun Moon
Committed by Gerrit Code Review

CORD-471 Added physical port and data plane IP as node attribtes

Change-Id: I4c28053151e61feb4b9b0ca60e98f7e0e4af0207
......@@ -105,9 +105,13 @@ public class CordVtn implements CordVtnService {
.register(KryoNamespaces.API)
.register(CordVtnNode.class)
.register(NodeState.class);
private static final String DEFAULT_BRIDGE = "br-int";
private static final String VPORT_PREFIX = "tap";
private static final String DEFAULT_TUNNEL = "vxlan";
private static final String OK = "OK";
private static final String NO = "NO";
private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
{
put("key", "flow");
......@@ -213,6 +217,8 @@ public class CordVtn implements CordVtnService {
}
};
// TODO Add physical port add state
public abstract void process(CordVtn cordVtn, CordVtnNode node);
}
......@@ -307,6 +313,27 @@ public class CordVtn implements CordVtnService {
}
@Override
public String checkNodeInitState(CordVtnNode node) {
checkNotNull(node);
NodeState state = getNodeState(node);
if (state == null) {
log.warn("Failed to get init state of {}", node.hostname());
return null;
}
String result = String.format(
"Integration bridge created/connected : %s (%s)%n" +
"VXLAN interface created : %s%n" +
"Physical interface added : %s (%s)",
checkIntegrationBridge(node) ? OK : NO, DEFAULT_BRIDGE,
checkTunnelInterface(node) ? OK : NO,
checkPhyInterface(node) ? OK : NO, node.phyPortName());
return result;
}
@Override
public void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
CordService tService = getCordService(tServiceId);
CordService pService = getCordService(pServiceId);
......@@ -374,7 +401,12 @@ public class CordVtn implements CordVtnService {
checkNotNull(node);
if (checkIntegrationBridge(node) && checkTunnelInterface(node)) {
// TODO add physical port add state
if (checkPhyInterface(node)) {
return NodeState.COMPLETE;
} else {
return NodeState.INCOMPLETE;
}
} else if (checkIntegrationBridge(node)) {
return NodeState.BRIDGE_CREATED;
} else if (getOvsdbConnectionState(node)) {
......@@ -488,6 +520,16 @@ public class CordVtn implements CordVtnService {
}
/**
* Returns port name.
*
* @param port port
* @return port name
*/
private String getPortName(Port port) {
return port.annotations().value("portName");
}
/**
* Returns OVSDB client for a given node.
*
* @param node cordvtn node
......@@ -520,6 +562,7 @@ public class CordVtn implements CordVtnService {
ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
controllers.add(ctrlInfo);
});
String dpid = node.intBrId().toString().substring(DPID_BEGIN);
try {
......@@ -545,9 +588,11 @@ public class CordVtn implements CordVtnService {
for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) {
optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
}
TunnelDescription description =
new DefaultTunnelDescription(null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL),
TunnelDescription description = new DefaultTunnelDescription(
null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL),
optionBuilder.build());
try {
DriverHandler handler = driverService.createHandler(node.ovsdbId());
TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class);
......@@ -578,7 +623,26 @@ public class CordVtn implements CordVtnService {
try {
deviceService.getPorts(node.intBrId())
.stream()
.filter(p -> p.annotations().value("portName").contains(DEFAULT_TUNNEL)
.filter(p -> getPortName(p).contains(DEFAULT_TUNNEL)
&& p.isEnabled())
.findAny().get();
return true;
} catch (NoSuchElementException e) {
return false;
}
}
/**
* Checks if physical interface exists.
*
* @param node cordvtn node
* @return true if the interface exists, false otherwise
*/
private boolean checkPhyInterface(CordVtnNode node) {
try {
deviceService.getPorts(node.intBrId())
.stream()
.filter(p -> getPortName(p).contains(node.phyPortName())
&& p.isEnabled())
.findAny().get();
return true;
......@@ -596,7 +660,7 @@ public class CordVtn implements CordVtnService {
private PortNumber getTunnelPort(DeviceId bridgeId) {
try {
return deviceService.getPorts(bridgeId).stream()
.filter(p -> p.annotations().value("portName").contains(DEFAULT_TUNNEL)
.filter(p -> getPortName(p).contains(DEFAULT_TUNNEL)
&& p.isEnabled())
.findFirst().get().number();
} catch (NoSuchElementException e) {
......@@ -613,8 +677,7 @@ public class CordVtn implements CordVtnService {
private Ip4Address getRemoteIp(DeviceId bridgeId) {
CordVtnNode node = getNodeByBridgeId(bridgeId);
if (node != null) {
// TODO get data plane IP for tunneling
return node.ovsdbIp().getIp4Address();
return node.localIp().getIp4Address();
} else {
return null;
}
......@@ -712,7 +775,7 @@ public class CordVtn implements CordVtnService {
private boolean isVm(Host host) {
Port port = deviceService.getPort(host.location().deviceId(),
host.location().port());
return port.annotations().value("portName").contains(VPORT_PREFIX);
return getPortName(port).contains(VPORT_PREFIX);
}
/**
......@@ -866,43 +929,50 @@ public class CordVtn implements CordVtnService {
/**
* Handles port added situation.
* If the added port is tunnel port, proceed remaining node initialization.
* Otherwise, do nothing.
* If the added port is tunnel or physical port, proceed remaining node
* initialization. Otherwise, do nothing.
*
* @param port port
*/
public void portAdded(Port port) {
CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
if (node == null) {
return;
}
// TODO add host by updating network config
if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) {
String portName = getPortName(port);
if (!portName.contains(DEFAULT_TUNNEL) && !portName.equals(node.phyPortName())) {
return;
}
CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
if (node != null) {
log.info("Port {} is added to {}", portName, node.hostname());
setNodeState(node, checkNodeState(node));
}
}
/**
* Handles port removed situation.
* If the removed port is tunnel port, proceed remaining node initialization.
* Others, do nothing.
* If the removed port is tunnel or physical port, proceed remaining node
* initialization.Others, do nothing.
*
* @param port port
*/
public void portRemoved(Port port) {
CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
if (node == null) {
return;
}
// TODO remove host by updating network config
if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) {
String portName = getPortName(port);
if (!portName.contains(DEFAULT_TUNNEL) && !portName.equals(node.phyPortName())) {
return;
}
CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
if (node != null) {
log.info("Tunnel interface is removed from {}", node.hostname());
log.info("Port {} is removed from {}", portName, node.hostname());
setNodeState(node, NodeState.INCOMPLETE);
}
}
}
private class VmHandler implements ConnectionHandler<Host> {
......
......@@ -37,6 +37,8 @@ public class CordVtnConfig extends Config<ApplicationId> {
public static final String OVSDB_IP = "ovsdbIp";
public static final String OVSDB_PORT = "ovsdbPort";
public static final String BRIDGE_ID = "bridgeId";
public static final String PHYSICAL_PORT_NAME = "phyPortName";
public static final String LOCAL_IP = "localIp";
/**
* Returns the set of nodes read from network config.
......@@ -54,7 +56,9 @@ public class CordVtnConfig extends Config<ApplicationId> {
jsonNode.path(HOSTNAME).asText(),
IpAddress.valueOf(jsonNode.path(OVSDB_IP).asText()),
TpPort.tpPort(jsonNode.path(OVSDB_PORT).asInt()),
DeviceId.deviceId(jsonNode.path(BRIDGE_ID).asText()))));
DeviceId.deviceId(jsonNode.path(BRIDGE_ID).asText()),
jsonNode.path(PHYSICAL_PORT_NAME).asText(),
IpAddress.valueOf(jsonNode.path(LOCAL_IP).asText()))));
return nodes;
}
......@@ -68,12 +72,17 @@ public class CordVtnConfig extends Config<ApplicationId> {
private final IpAddress ovsdbIp;
private final TpPort ovsdbPort;
private final DeviceId bridgeId;
private final String phyPortName;
private final IpAddress localIp;
public CordVtnNodeConfig(String hostname, IpAddress ovsdbIp, TpPort ovsdbPort, DeviceId bridgeId) {
public CordVtnNodeConfig(String hostname, IpAddress ovsdbIp, TpPort ovsdbPort,
DeviceId bridgeId, String phyPortName, IpAddress localIp) {
this.hostname = checkNotNull(hostname);
this.ovsdbIp = checkNotNull(ovsdbIp);
this.ovsdbPort = checkNotNull(ovsdbPort);
this.bridgeId = checkNotNull(bridgeId);
this.phyPortName = checkNotNull(phyPortName);
this.localIp = checkNotNull(localIp);
}
/**
......@@ -111,5 +120,23 @@ public class CordVtnConfig extends Config<ApplicationId> {
public DeviceId bridgeId() {
return this.bridgeId;
}
/**
* Returns physical port name.
*
* @return physical port name
*/
public String phyPortName() {
return this.phyPortName;
}
/**
* Returns local IP address.
*
* @return ip address
*/
public IpAddress localIp() {
return this.localIp;
}
}
}
......
......@@ -97,7 +97,13 @@ public class CordVtnConfigManager {
config.cordVtnNodes().forEach(node -> {
CordVtnNode cordVtnNode = new CordVtnNode(
node.hostname(), node.ovsdbIp(), node.ovsdbPort(), node.bridgeId());
node.hostname(),
node.ovsdbIp(),
node.ovsdbPort(),
node.bridgeId(),
node.phyPortName(),
node.localIp());
cordVtnService.addNode(cordVtnNode);
});
}
......
......@@ -34,6 +34,8 @@ public final class CordVtnNode {
private final IpAddress ovsdbIp;
private final TpPort ovsdbPort;
private final DeviceId bridgeId;
private final String phyPortName;
private final IpAddress localIp;
public static final Comparator<CordVtnNode> CORDVTN_NODE_COMPARATOR =
(node1, node2) -> node1.hostname().compareTo(node2.hostname());
......@@ -45,12 +47,17 @@ public final class CordVtnNode {
* @param ovsdbIp OVSDB server IP address
* @param ovsdbPort OVSDB server port number
* @param bridgeId integration bridge identifier
* @param phyPortName physical port name
* @param localIp local ip address of data plane
*/
public CordVtnNode(String hostname, IpAddress ovsdbIp, TpPort ovsdbPort, DeviceId bridgeId) {
public CordVtnNode(String hostname, IpAddress ovsdbIp, TpPort ovsdbPort,
DeviceId bridgeId, String phyPortName, IpAddress localIp) {
this.hostname = checkNotNull(hostname);
this.ovsdbIp = checkNotNull(ovsdbIp);
this.ovsdbPort = checkNotNull(ovsdbPort);
this.bridgeId = checkNotNull(bridgeId);
this.phyPortName = checkNotNull(phyPortName);
this.localIp = checkNotNull(localIp);
}
/**
......@@ -98,6 +105,24 @@ public final class CordVtnNode {
return DeviceId.deviceId("ovsdb:" + this.ovsdbIp.toString());
}
/**
* Returns physical port name.
*
* @return physical port name
*/
public String phyPortName() {
return this.phyPortName;
}
/**
* Returns local IP address.
*
* @return ip address
*/
public IpAddress localIp() {
return this.localIp;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
......@@ -106,10 +131,7 @@ public final class CordVtnNode {
if (obj instanceof CordVtnNode) {
CordVtnNode that = (CordVtnNode) obj;
if (Objects.equals(hostname, that.hostname) &&
Objects.equals(ovsdbIp, that.ovsdbIp) &&
Objects.equals(ovsdbPort, that.ovsdbPort) &&
Objects.equals(bridgeId, that.bridgeId)) {
if (Objects.equals(hostname, that.hostname)) {
return true;
}
}
......@@ -128,6 +150,8 @@ public final class CordVtnNode {
.add("ip", ovsdbIp)
.add("port", ovsdbPort)
.add("bridgeId", bridgeId)
.add("phyPortName", phyPortName)
.add("localIp", localIp)
.toString();
}
}
......
......@@ -60,6 +60,19 @@ public interface CordVtnService {
boolean getNodeInitState(CordVtnNode node);
/**
* Returns detailed node initialization state.
* Return string includes the following information.
*
* Integration bridge created/connected: OK or NO
* VXLAN interface created: OK or NO
* Physical interface added: OK or NO
*
* @param node cordvtn node
* @return string including detailed node init state
*/
String checkNodeInitState(CordVtnNode node);
/**
* Returns all nodes known to the service.
*
* @return list of nodes
......
......@@ -48,6 +48,16 @@ public class CordVtnNodeAddCommand extends AbstractShellCommand {
required = true, multiValued = false)
private String bridgeId = null;
@Argument(index = 3, name = "phyPortName",
description = "Physical port name",
required = true, multiValued = false)
private String phyPortName = null;
@Argument(index = 4, name = "localIp",
description = "Local data plane IP address",
required = true, multiValued = false)
private String localIp = null;
@Override
protected void execute() {
checkArgument(ovsdb.contains(":"), "OVSDB address should be ip:port format");
......@@ -58,7 +68,9 @@ public class CordVtnNodeAddCommand extends AbstractShellCommand {
CordVtnNode node = new CordVtnNode(hostname,
IpAddress.valueOf(ipPort[0]),
TpPort.tpPort(Integer.parseInt(ipPort[1])),
DeviceId.deviceId(bridgeId));
DeviceId.deviceId(bridgeId),
phyPortName,
IpAddress.valueOf(localIp));
service.addNode(node);
}
}
......
/*
* 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.cordvtn.cli;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.cordvtn.CordVtnNode;
import org.onosproject.cordvtn.CordVtnService;
/**
* Checks detailed node init state.
*/
@Command(scope = "onos", name = "cordvtn-node-check",
description = "Shows detailed node init state")
public class CordVtnNodeCheckCommand extends AbstractShellCommand {
@Argument(index = 0, name = "hostname", description = "Hostname",
required = true, multiValued = false)
private String hostname = null;
@Override
protected void execute() {
CordVtnService service = AbstractShellCommand.get(CordVtnService.class);
CordVtnNode node = service.getNodes()
.stream()
.filter(n -> n.hostname().equals(hostname))
.findFirst()
.orElse(null);
if (node == null) {
print("Cannot find %s from registered nodes", hostname);
return;
}
print(service.checkNodeInitState(node));
}
}
......@@ -44,10 +44,12 @@ public class CordVtnNodeListCommand extends AbstractShellCommand {
print("%s", json(service, nodes));
} else {
for (CordVtnNode node : nodes) {
print("hostname=%s, ovsdb=%s, br-int=%s, init=%s",
print("hostname=%s, ovsdb=%s, br-int=%s, phyPort=%s, localIp=%s, init=%s",
node.hostname(),
node.ovsdbIp().toString() + ":" + node.ovsdbPort().toString(),
node.intBrId().toString(),
node.phyPortName(),
node.localIp().toString(),
getState(service, node));
}
print("Total %s nodes", service.getNodeCount());
......@@ -63,6 +65,8 @@ public class CordVtnNodeListCommand extends AbstractShellCommand {
.put("hostname", node.hostname())
.put("ovsdb", ipPort)
.put("brInt", node.intBrId().toString())
.put("phyPort", node.phyPortName())
.put("localIp", node.localIp().toString())
.put("init", getState(service, node)));
}
return result;
......
......@@ -28,5 +28,8 @@
<command>
<action class="org.onosproject.cordvtn.cli.CordVtnNodeInitCommand"/>
</command>
<command>
<action class="org.onosproject.cordvtn.cli.CordVtnNodeCheckCommand"/>
</command>
</command-bundle>
</blueprint>
......