apply checkstyle check during build for neutron-ovsdb
[groupbasedpolicy.git] / neutron-ovsdb / src / main / java / org / opendaylight / groupbasedpolicy / neutron / ovsdb / OvsdbNodeListener.java
index acf3603d7a378edcdc16ba9478a54ae315e5930f..09f8c2a23dc2a048170589747fddaaa6a9e33bd7 100644 (file)
@@ -7,9 +7,19 @@
  */
 package org.opendaylight.groupbasedpolicy.neutron.ovsdb;
 
+import com.google.common.base.Function;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.MoreExecutors;
+
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 import javax.annotation.Nonnull;
@@ -17,47 +27,63 @@ import javax.annotation.Nonnull;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper;
+import org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.NeutronOvsdbIidFactory;
 import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.ovsdb.params.rev160812.IntegrationBridgeSetting;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeSystem;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow13;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigsKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Strings;
-
 public class OvsdbNodeListener extends DataTreeChangeHandler<Node> {
 
+    static final String BRIDGE_SEPARATOR = "/bridge/";
+    static final String NEUTRON_PROVIDER_MAPPINGS_KEY = "provider_mappings";
     private static final Logger LOG = LoggerFactory.getLogger(OvsdbNodeListener.class);
-    public static final String NEUTRON_PROVIDER_MAPPINGS_KEY = "provider_mappings";
     private static final String OF_SEPARATOR = ":";
     private static final String OF_INVENTORY_PREFIX = "openflow";
+    private static IntegrationBridgeSetting intBrSettings;
 
     private final Map<OvsdbBridgeRef, String> providerPortNameByBridgeRef = new HashMap<>();
     private final Map<InstanceIdentifier<Node>, NeutronBridgeWithExtPort> bridgeByNodeIid = new HashMap<>();
 
-    public OvsdbNodeListener(DataBroker dataProvider) {
-        super(dataProvider,
-                new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
-                        InstanceIdentifier.create(NetworkTopology.class)
-                            .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
-                            .child(Node.class)));
+    public OvsdbNodeListener(DataBroker dataProvider, IntegrationBridgeSetting brSettings) {
+        super(dataProvider);
+        intBrSettings = brSettings;
+        this.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifier.create(NetworkTopology.class)
+                    .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
+                    .child(Node.class)));
     }
 
     @Override
@@ -66,19 +92,46 @@ public class OvsdbNodeListener extends DataTreeChangeHandler<Node> {
         OvsdbNodeAugmentation ovsdbNode = node.getAugmentation(OvsdbNodeAugmentation.class);
         if (ovsdbNode != null) {
             LOG.trace("OVSDB node created: {} \n {}", rootIdentifier, node);
-            DataObjectModification<OpenvswitchOtherConfigs> ovsOtherConfigModification =
-                    getProviderMappingsModification(rootNode);
+            DataObjectModification<OpenvswitchOtherConfigs>
+                ovsOtherConfigModification = getProviderMappingsModification(rootNode);
+            boolean integrationBridgePresent = false;
             if (isProviderPortNameChanged(ovsOtherConfigModification) && ovsdbNode.getManagedNodeEntry() != null) {
                 String newProviderPortName = getProviderPortName(ovsOtherConfigModification.getDataAfter());
                 LOG.debug("provider_mappings created {} on node {}", newProviderPortName, node.getNodeId().getValue());
                 for (ManagedNodeEntry mngdNodeEntry : ovsdbNode.getManagedNodeEntry()) {
-                    providerPortNameByBridgeRef.put(mngdNodeEntry.getBridgeRef(), newProviderPortName);
+                    OvsdbBridgeRef bridgeRef = mngdNodeEntry.getBridgeRef();
+                    providerPortNameByBridgeRef.put(bridgeRef, newProviderPortName);
                     LOG.trace("Added Provider port name {} by OVSDB bridge ref {}", newProviderPortName,
                             mngdNodeEntry.getBridgeRef());
+                    NodeKey managedNodeKey = bridgeRef.getValue().firstKeyOf(Node.class);
+                    if (intBrSettings != null && managedNodeKey.getNodeId().getValue()
+                        .equals(intBrSettings.getName())) {
+                        integrationBridgePresent = true;
+                    }
                 }
             }
-        }
+            if (intBrSettings != null && !integrationBridgePresent) {
+                final Node bridge = createBridge(rootIdentifier,
+                        managerToControllerEntries(ovsdbNode.getManagerEntry()), intBrSettings.getName());
+                InstanceIdentifier<Node> bridgeNodeIid = NeutronOvsdbIidFactory.nodeIid(
+                        rootIdentifier.firstKeyOf(Topology.class).getTopologyId(), bridge.getNodeId());
+                WriteTransaction writeTx = dataProvider.newWriteOnlyTransaction();
+                writeTx.merge(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid, bridge, true);
+                Futures.addCallback(writeTx.submit(), new FutureCallback<Void>() {
 
+                    @Override
+                    public void onSuccess(Void result) {
+                        LOG.info("Bridge {} written to datastore." + bridge.getNodeId().getValue());
+                    }
+
+                    @Override
+                    public void onFailure(Throwable throwable) {
+                        LOG.error("Failed to write bridge {}. Message: {}" + bridge.getNodeId().getValue(),
+                                throwable.getMessage());
+                    }
+                }, MoreExecutors.directExecutor());
+            }
+        }
         OvsdbBridgeAugmentation ovsdbBridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
         if (ovsdbBridge != null) {
             LOG.trace("OVSDB bridge created: {} \n {}", rootIdentifier, node);
@@ -143,6 +196,12 @@ public class OvsdbNodeListener extends DataTreeChangeHandler<Node> {
             }
             for (DataObjectModification<OvsdbTerminationPointAugmentation> ovsdbTpModification : ovsdbTpModifications) {
                 OvsdbTerminationPointAugmentation newOvsdbTp = ovsdbTpModification.getDataAfter();
+
+                if (newOvsdbTp == null) {
+                    LOG.trace("Termination Point is null. Not processing");
+                    continue;
+                }
+
                 if (ovsdbBridge.getBridgeName().getValue().equals(newOvsdbTp.getName())) {
                     LOG.trace("Termination Point {} same as Bridge {}. Not processing", newOvsdbTp.getName(),
                             ovsdbBridge.getBridgeName().getValue());
@@ -203,7 +262,8 @@ public class OvsdbNodeListener extends DataTreeChangeHandler<Node> {
         OvsdbTerminationPointAugmentation oldTp = ovsdbTpModification.getDataBefore();
         OvsdbTerminationPointAugmentation newTp = ovsdbTpModification.getDataAfter();
         if (oldTp != null && newTp != null) {
-            if (oldTp.getOfport() != null && newTp.getOfport() != null && oldTp.getOfport() != newTp.getOfport()) {
+            if (oldTp.getOfport() != null && newTp.getOfport() != null && !Objects.equals(oldTp.getOfport(),
+                newTp.getOfport())) {
                 return true;
             }
             if (!(Strings.nullToEmpty(oldTp.getName())).equals(Strings.nullToEmpty(newTp.getName()))) {
@@ -272,6 +332,59 @@ public class OvsdbNodeListener extends DataTreeChangeHandler<Node> {
         return "";
     }
 
+    /**
+     * Extracts IP address from URI.
+     *
+     * @param uri in format protocol:ip:port
+     * @return IPv4 or IPv6 address as {@link String}.
+     */
+    private static @Nonnull String getIpAddrFromUri(Uri uri) {
+        String otherConfig = uri.getValue();
+        String[] elements = otherConfig.split(":");
+        // IPv6 expression also contains colons
+        if (elements.length < 3) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder();
+        // first (protocol) and last (port) elements are filtered
+        for (int i = 1; i < elements.length - 1; i++) {
+            sb.append(elements[i]);
+        }
+        return sb.toString();
+    }
+
+    private List<ControllerEntry> managerToControllerEntries(List<ManagerEntry> managerEntries) {
+        return Lists.transform(managerEntries, new Function<ManagerEntry, ControllerEntry>() {
+
+            @Override
+            public ControllerEntry apply(ManagerEntry managerEntry) {
+                String ipAddr = getIpAddrFromUri(managerEntry.getTarget());
+                Uri uri = new Uri(intBrSettings.getOpenflowProtocol() + OF_SEPARATOR + ipAddr + OF_SEPARATOR
+                        + intBrSettings.getOpenflowPort());
+                return new ControllerEntryBuilder().setTarget(new Uri(uri)).build();
+            }
+        });
+    }
+
+    private Node createBridge(InstanceIdentifier<Node> managedByIid, List<ControllerEntry> controllerEntries,
+            String bridgeName) {
+        OvsdbBridgeAugmentation br = new OvsdbBridgeAugmentationBuilder()
+            .setBridgeName(new OvsdbBridgeName(bridgeName))
+            .setManagedBy(new OvsdbNodeRef(managedByIid))
+            .setControllerEntry(controllerEntries)
+            .setDatapathType(DatapathTypeSystem.class)
+            .setProtocolEntry(
+                    ImmutableList.of(new ProtocolEntryBuilder().setProtocol(
+                            OvsdbBridgeProtocolOpenflow13.class).build()))
+            .build();
+        NodeKey managerNodeKey = managedByIid.firstKeyOf(Node.class);
+        return new NodeBuilder().setNodeId(
+                new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId(
+                        managerNodeKey.getNodeId().getValue() + BRIDGE_SEPARATOR + bridgeName))
+            .addAugmentation(OvsdbBridgeAugmentation.class, br)
+            .build();
+    }
+
     private static NodeId buildOfNodeId(OvsdbBridgeAugmentation ovsdbBridge) {
         if (ovsdbBridge.getDatapathId() == null) {
             return null;