Supports a creation of dpdk tunnel bridge and ports in OpenstackNode.
Change-Id: I2688837b3e677fd39f06135ff76ca856f0da1dbe
(cherry picked from commit e2658baf17d999dab362aecf703cd940659065d2)
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
index 4337355..0cf78fa 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.openstacknode.impl;
+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;
@@ -40,7 +41,6 @@
import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.net.behaviour.DefaultBridgeDescription;
import org.onosproject.net.behaviour.DefaultTunnelDescription;
-import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
import org.onosproject.net.behaviour.InterfaceConfig;
import org.onosproject.net.behaviour.TunnelDescription;
import org.onosproject.net.behaviour.TunnelEndPoints;
@@ -49,8 +49,7 @@
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.instructions.ExtensionPropertyException;
-import org.onosproject.net.flow.instructions.ExtensionTreatment;
+import org.onosproject.openstacknode.api.DpdkInterface;
import org.onosproject.openstacknode.api.NodeState;
import org.onosproject.openstacknode.api.OpenstackNode;
import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
@@ -59,14 +58,23 @@
import org.onosproject.openstacknode.api.OpenstackNodeListener;
import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.onosproject.openstacknode.api.OpenstackPhyInterface;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbInterface;
+import org.onosproject.ovsdb.controller.OvsdbPort;
+import org.onosproject.ovsdb.rfc.notation.OvsdbMap;
+import org.onosproject.ovsdb.rfc.notation.OvsdbSet;
+import org.onosproject.ovsdb.rfc.table.Interface;
import org.openstack4j.api.OSClient;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
+import java.util.Collection;
import java.util.Dictionary;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
@@ -75,20 +83,20 @@
import static org.onlab.packet.TpPort.tpPort;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
import static org.onosproject.openstacknode.api.Constants.DEFAULT_TUNNEL;
import static org.onosproject.openstacknode.api.Constants.INTEGRATION_BRIDGE;
+import static org.onosproject.openstacknode.api.Constants.TUNNEL_BRIDGE;
import static org.onosproject.openstacknode.api.DpdkConfig.DatapathType.NETDEV;
import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
import static org.onosproject.openstacknode.api.NodeState.DEVICE_CREATED;
import static org.onosproject.openstacknode.api.NodeState.INCOMPLETE;
import static org.onosproject.openstacknode.api.NodeState.INIT;
-
import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
import static org.onosproject.openstacknode.api.OpenstackNodeService.APP_ID;
import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getBooleanProperty;
import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getConnectedClient;
+import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getOvsdbClient;
import static org.onosproject.openstacknode.util.OpenstackNodeUtil.isOvsdbConnected;
import static org.slf4j.LoggerFactory.getLogger;
@@ -103,6 +111,7 @@
private static final String OVSDB_PORT = "ovsdbPortNum";
private static final String AUTO_RECOVERY = "autoRecovery";
private static final String DEFAULT_OF_PROTO = "tcp";
+ private static final String DPDK_DEVARGS = "dpdk-devargs";
private static final int DEFAULT_OVSDB_PORT = 6640;
private static final int DEFAULT_OFPORT = 6653;
private static final boolean DEFAULT_AUTO_RECOVERY = true;
@@ -196,6 +205,9 @@
if (!deviceService.isAvailable(osNode.intgBridge())) {
createBridge(osNode, INTEGRATION_BRIDGE, osNode.intgBridge());
}
+ if (hasDpdkTunnelBridge(osNode)) {
+ createDpdkTunnelBridge(osNode);
+ }
}
@Override
@@ -222,6 +234,11 @@
osNode.vlanIntf(), true);
}
+ if (osNode.dpdkConfig() != null && osNode.dpdkConfig().dpdkIntfs() != null) {
+ osNode.dpdkConfig().dpdkIntfs().forEach(dpdkInterface ->
+ addOrRemoveDpdkInterface(osNode, dpdkInterface, true));
+ }
+
osNode.phyIntfs().forEach(i -> {
if (!isIntfEnabled(osNode, i.intf())) {
addOrRemoveSystemInterface(osNode, INTEGRATION_BRIDGE,
@@ -244,6 +261,26 @@
//TODO
}
+ private boolean hasDpdkTunnelBridge(OpenstackNode osNode) {
+ if (osNode.dpdkConfig() != null && osNode.dpdkConfig().dpdkIntfs() != null) {
+ return osNode.dpdkConfig().dpdkIntfs().stream()
+ .anyMatch(intf -> intf.deviceName().equals(TUNNEL_BRIDGE));
+ }
+ return false;
+ }
+
+ private boolean dpdkTunnelBridgeCreated(OpenstackNode osNode) {
+
+ OvsdbClientService client = getOvsdbClient(osNode, ovsdbPort, ovsdbController);
+ if (client == null) {
+ log.info("Failed to get ovsdb client");
+ return false;
+ }
+
+ return client.getBridges().stream()
+ .anyMatch(bridge -> bridge.name().equals(TUNNEL_BRIDGE));
+ }
+
/**
* Creates a bridge with a given name on a given openstack node.
*
@@ -253,10 +290,6 @@
*/
private void createBridge(OpenstackNode osNode, String bridgeName, DeviceId deviceId) {
Device device = deviceService.getDevice(osNode.ovsdb());
- if (device == null || !device.is(BridgeConfig.class)) {
- log.error("Failed to create integration bridge on {}", osNode.ovsdb());
- return;
- }
List<ControllerInfo> controllers;
@@ -282,13 +315,24 @@
.controllers(controllers);
if (osNode.datapathType().equals(NETDEV)) {
- builder.datapathType(osNode.datapathType().name().toLowerCase());
+ builder.datapathType(NETDEV.name().toLowerCase());
}
BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
bridgeConfig.addBridge(builder.build());
}
+ private void createDpdkTunnelBridge(OpenstackNode osNode) {
+ Device device = deviceService.getDevice(osNode.ovsdb());
+
+ BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
+ .name(TUNNEL_BRIDGE)
+ .datapathType(NETDEV.name().toLowerCase());
+
+ BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+ bridgeConfig.addBridge(builder.build());
+ }
+
/**
* Adds or removes a network interface (aka port) into a given bridge of openstack node.
*
@@ -315,6 +359,33 @@
}
}
+ private void addOrRemoveDpdkInterface(OpenstackNode osNode,
+ DpdkInterface dpdkInterface,
+ boolean addOrRemove) {
+
+ OvsdbClientService client = getOvsdbClient(osNode, ovsdbPort, ovsdbController);
+ if (client == null) {
+ log.info("Failed to get ovsdb client");
+ return;
+ }
+
+ if (addOrRemove) {
+ Map<String, String> options = Maps.newHashMap();
+ options.put(DPDK_DEVARGS, dpdkInterface.pciAddress());
+
+ OvsdbInterface.Builder builder = OvsdbInterface.builder()
+ .name(dpdkInterface.intf())
+ .type(OvsdbInterface.Type.DPDK)
+ .mtu(dpdkInterface.mtu())
+ .options(options);
+
+
+ client.createInterface(dpdkInterface.deviceName(), builder.build());
+ } else {
+ client.dropInterface(dpdkInterface.intf());
+ }
+ }
+
/**
* Creates a tunnel interface in a given openstack node.
*
@@ -343,30 +414,6 @@
ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
}
- private ExtensionTreatment tunnelDstTreatment(DeviceId deviceId, IpAddress remoteIp) {
- Device device = deviceService.getDevice(deviceId);
- if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
- log.error("The extension treatment is not supported");
- return null;
- }
-
- if (device == null) {
- return null;
- }
-
- ExtensionTreatmentResolver resolver =
- device.as(ExtensionTreatmentResolver.class);
- ExtensionTreatment treatment =
- resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
- try {
- treatment.setPropertyValue("tunnelDst", remoteIp.getIp4Address());
- return treatment;
- } catch (ExtensionPropertyException e) {
- log.warn("Failed to get tunnelDst extension treatment for {}", deviceId);
- return null;
- }
- }
-
/**
* Checks whether a given network interface in a given openstack node is enabled or not.
*
@@ -395,7 +442,11 @@
return false;
}
- return deviceService.isAvailable(osNode.intgBridge());
+ boolean initStateDone = deviceService.isAvailable(osNode.intgBridge());
+ if (hasDpdkTunnelBridge(osNode)) {
+ initStateDone = initStateDone && dpdkTunnelBridgeCreated(osNode);
+ }
+ return initStateDone;
case DEVICE_CREATED:
if (osNode.dataIp() != null &&
!isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
@@ -409,6 +460,9 @@
!isIntfEnabled(osNode, osNode.uplinkPort())) {
return false;
}
+ if (osNode.dpdkConfig() != null && osNode.dpdkConfig().dpdkIntfs() != null) {
+ return isDpdkIntfsCreated(osNode, osNode.dpdkConfig().dpdkIntfs());
+ }
for (OpenstackPhyInterface intf : osNode.phyIntfs()) {
if (intf != null && !isIntfEnabled(osNode, intf.intf())) {
@@ -427,6 +481,47 @@
}
}
+ private boolean isDpdkIntfsCreated(OpenstackNode osNode, Collection<DpdkInterface> dpdkInterfaces) {
+ OvsdbClientService client = getOvsdbClient(osNode, ovsdbPort, ovsdbController);
+ if (client == null) {
+ log.info("Failed to get ovsdb client");
+ return false;
+ }
+
+ Set<OvsdbPort> ports = client.getPorts();
+
+ for (DpdkInterface dpdkInterface : dpdkInterfaces) {
+ Optional<OvsdbPort> port = ports.stream()
+ .filter(ovsdbPort -> ovsdbPort.portName().value().equals(dpdkInterface.intf()))
+ .findAny();
+
+ if (!port.isPresent()) {
+ return false;
+ }
+ Interface intf = client.getInterface(dpdkInterface.intf());
+ if (intf == null) {
+ return false;
+ }
+
+ OvsdbSet mtu = (OvsdbSet) intf.getMtuColumn().data();
+ if (mtu == null) {
+ return false;
+ }
+
+ OvsdbMap option = (OvsdbMap) intf.getOptionsColumn().data();
+ if (option == null) {
+ return false;
+ }
+
+ if (!mtu.set().contains(dpdkInterface.mtu().intValue()) ||
+ !option.toString().contains(dpdkInterface.pciAddress())) {
+ log.trace("The dpdk interface {} was created but mtu or pci address is different from the config.");
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Configures the openstack node with new state.
*
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java
index 368deed..0b713b4 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java
@@ -92,6 +92,7 @@
.register(DefaultOpenstackPhyInterface.class)
.register(DpdkInterface.class)
.register(DefaultDpdkInterface.class)
+ .register(DpdkInterface.Type.class)
.register(ControllerInfo.class)
.register(DefaultOpenstackAuth.class)
.register(DefaultOpenstackAuth.Perspective.class)
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java
index 4d8167b..720cfd6 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java
@@ -82,14 +82,28 @@
int ovsdbPort,
OvsdbController ovsdbController,
DeviceService deviceService) {
- OvsdbNodeId ovsdb = new OvsdbNodeId(osNode.managementIp(), ovsdbPort);
- OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
+ OvsdbClientService client = getOvsdbClient(osNode, ovsdbPort, ovsdbController);
return deviceService.isAvailable(osNode.ovsdb()) &&
client != null &&
client.isConnected();
}
/**
+ * Gets the ovsdb client with supplied openstack node.
+ *
+ * @param osNode openstack node
+ * @param ovsdbPort ovsdb port
+ * @param ovsdbController ovsdb controller
+ * @return ovsdb client
+ */
+ public static OvsdbClientService getOvsdbClient(OpenstackNode osNode,
+ int ovsdbPort,
+ OvsdbController ovsdbController) {
+ OvsdbNodeId ovsdb = new OvsdbNodeId(osNode.managementIp(), ovsdbPort);
+ return ovsdbController.getOvsdbClient(ovsdb);
+ }
+
+ /**
* Obtains a connected openstack client.
*
* @param osNode openstack node