Bug 5510 - making sure that br-int is created 86/36486/2
authorTomas Cechvala <tcechval@cisco.com>
Sat, 12 Mar 2016 12:44:24 +0000 (13:44 +0100)
committerTomas Cechvala <tcechval@cisco.com>
Mon, 21 Mar 2016 09:30:56 +0000 (09:30 +0000)
When a node with OvsdbNodeAugmentation does not have
reference to br-int node with OvsdbBridge augmentation,
the missing bridge node is created by writing it
into DS.

Change-Id: Ie0054d311916ece0030ad63647ebe3ca3f06d797
Signed-off-by: Tomas Cechvala <tcechval@cisco.com>
neutron-ovsdb/src/main/config/default-config.xml
neutron-ovsdb/src/main/java/org/opendaylight/controller/config/yang/config/neutron_ovsdb/impl/NeutronOvsdbModule.java
neutron-ovsdb/src/main/java/org/opendaylight/groupbasedpolicy/neutron/ovsdb/NeutronOvsdb.java
neutron-ovsdb/src/main/java/org/opendaylight/groupbasedpolicy/neutron/ovsdb/OvsdbNodeListener.java
neutron-ovsdb/src/main/java/org/opendaylight/groupbasedpolicy/neutron/ovsdb/util/NeutronOvsdbIidFactory.java
neutron-ovsdb/src/main/yang/neutron-ovsdb-impl.yang

index 99272eda1ce3c21d8de38187305e458234dbab9d..3953ededc7b66f6f95101fdf6bd310a68fefe9c1 100644 (file)
                       <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
                       <name>binding-data-broker</name>
                     </data-broker>
+
+                    <!-- Remove the following if integration bridge should not be automatically created on OVSDB node. -->
+                    <integration-bridge-setting>
+                        <name>br-int</name>
+                        <openflow-protocol>tcp</openflow-protocol>
+                        <openflow-port>6653</openflow-port>
+                    </integration-bridge-setting>
+
                 </module>
             </modules>
         </data>
index d29e04f7182dbebb5463282d4f057cd9c4e14477..d8137644b901cf33f8196597e295f2313a0ccd56 100644 (file)
@@ -33,7 +33,8 @@ public class NeutronOvsdbModule extends org.opendaylight.controller.config.yang.
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        final NeutronOvsdb neutronOvsdb = new NeutronOvsdb(getDataBrokerDependency(), getRpcRegistryDependency());
+        final NeutronOvsdb neutronOvsdb = new NeutronOvsdb(getDataBrokerDependency(), getRpcRegistryDependency(),
+                getIntegrationBridgeSetting());
         LOG.info("Neutron ovsdb started.");
         return neutronOvsdb;
     }
index 24d9c58e0988ce2d02ddb3d1986fb44df372fcf7..f5d389f8fd170de1c90b4368b9dc057055841189 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.groupbasedpolicy.neutron.ovsdb;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import org.opendaylight.controller.config.yang.config.neutron_ovsdb.impl.IntegrationBridgeSetting;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
@@ -21,13 +22,14 @@ public class NeutronOvsdb implements AutoCloseable {
     private final OvsdbNodeListener ovsdbNodeListener;
     private final ProviderPhysicalNetworkListener provPhysNetListener;
 
-    public NeutronOvsdb(DataBroker dataProvider, RpcProviderRegistry rpcProvider) {
+    public NeutronOvsdb(DataBroker dataProvider, RpcProviderRegistry rpcProvider,
+            IntegrationBridgeSetting integrationbridgeSettings) {
         checkNotNull(dataProvider);
         checkNotNull(rpcProvider);
 
         EndpointService epService = rpcProvider.getRpcService(EndpointService.class);
         tpListener = new TerminationPointDataChangeListener(dataProvider, epService);
-        ovsdbNodeListener = new OvsdbNodeListener(dataProvider);
+        ovsdbNodeListener = new OvsdbNodeListener(dataProvider, integrationbridgeSettings);
         portByEndpointListener = new PortByEndpointListener(dataProvider);
         provPhysNetListener = new ProviderPhysicalNetworkListener(dataProvider);
     }
index 0794b77d6cc908979beca146d1c001ef902f707a..f8fc121dac28433f5593743a7dbb24608037b19c 100644 (file)
@@ -7,40 +7,79 @@
  */
 package org.opendaylight.groupbasedpolicy.neutron.ovsdb;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import javax.annotation.Nonnull;
 
+import org.opendaylight.controller.config.yang.config.neutron_ovsdb.impl.IntegrationBridgeSetting;
 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.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper;
+import org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.NeutronOvsdbIidFactory;
+import org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper;
+import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 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.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
 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.DatapathTypeBase;
+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.OvsdbFailModeSecure;
 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.ControllerEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
+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.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.base.Strings;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
 
 public class OvsdbNodeListener extends DataTreeChangeHandler<Node> {
 
@@ -48,16 +87,19 @@ public class OvsdbNodeListener extends DataTreeChangeHandler<Node> {
     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 final String BRIDGE_SEPARATOR = "/bridge/";
+    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) {
+    public OvsdbNodeListener(DataBroker dataProvider, IntegrationBridgeSetting brSettings) {
         super(dataProvider,
                 new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
                         InstanceIdentifier.create(NetworkTopology.class)
                             .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
                             .child(Node.class)));
+        intBrSettings = brSettings;
     }
 
     @Override
@@ -66,19 +108,44 @@ 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 == false) {
+                final Node bridge = createBridge(rootIdentifier,
+                        managerToControllerEntries(ovsdbNode.getManagerEntry()), intBrSettings.getName());
+                InstanceIdentifier<Node> bridgeNodeIid = NeutronOvsdbIidFactory.nodeIid(
+                        rootIdentifier.firstKeyOf(Topology.class).getTopologyId(), bridge.getNodeId());
+                WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
+                wTx.merge(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid, bridge, true);
+                Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
 
+                    @Override
+                    public void onSuccess(Void result) {
+                        LOG.info("Bridge {} written to datastore." + bridge.getNodeId().getValue());
+                    }
+
+                    @Override
+                    public void onFailure(Throwable t) {
+                        LOG.error("Failed to write bridge {}. Message: {}" + bridge.getNodeId().getValue(),
+                                t.getMessage());
+                    }
+                });
+            }
+        }
         OvsdbBridgeAugmentation ovsdbBridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
         if (ovsdbBridge != null) {
             LOG.trace("OVSDB bridge created: {} \n {}", rootIdentifier, node);
@@ -278,6 +345,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.<ProtocolEntry>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;
index 5fad3aa639a5647ee8212f226ec52a185f52ce42..4133b61c31bed1fcd9131046811b275839870896 100644 (file)
@@ -16,22 +16,26 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gb
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.ports.EndpointByPortKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ExternalGatewaysAsL3Endpoints;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.external.gateways.as.l3.endpoints.ExternalGatewayAsL3Endpoint;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
 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.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
 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.NodeKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 public class NeutronOvsdbIidFactory {
 
-    public static InstanceIdentifier<OvsdbNodeAugmentation> ovsdbNodeAugmentationIid(TopologyId ovsdbTopologyId) {
+    public static InstanceIdentifier<Topology> topologyIid(TopologyId ovsdbTopologyId) {
         return InstanceIdentifier.create(NetworkTopology.class)
-            .child(Topology.class, new TopologyKey(ovsdbTopologyId))
+            .child(Topology.class, new TopologyKey(ovsdbTopologyId));
+    }
+
+    public static InstanceIdentifier<OvsdbNodeAugmentation> ovsdbNodeAugmentationIid(TopologyId ovsdbTopologyId) {
+        return topologyIid(ovsdbTopologyId)
             .child(Node.class)
             .augmentation(OvsdbNodeAugmentation.class);
     }
@@ -56,11 +60,15 @@ public class NeutronOvsdbIidFactory {
         return InstanceIdentifier.builder(Mappings.class).child(NeutronByGbpMappings.class).build();
     }
 
+    public static InstanceIdentifier<Node> nodeIid(TopologyId ovsdbTopologyId, NodeId nodeId) {
+        return topologyIid(ovsdbTopologyId).child(Node.class, new NodeKey(nodeId));
+    }
+
     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeIid(
-            NodeId nodeId) {
+            org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId) {
         return InstanceIdentifier.builder(Nodes.class)
             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
-                    new NodeKey(nodeId))
+                    new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(nodeId))
             .build();
     }
 }
index dda939db0c2cc016f467c8921838a54db8055b3d..5f3e3052cef31f426b15609355365bdeb40e9287 100644 (file)
@@ -47,6 +47,22 @@ module neutron-ovsdb-impl {
                 }
             }
 
+            container integration-bridge-setting {
+                leaf name {
+                    mandatory true;
+                    type string;
+                }
+                leaf openflow-port {
+                    mandatory true;
+                    type uint16;
+                }
+                leaf openflow-protocol {
+                    mandatory true;
+                    type string {
+                        pattern "^tcp$|^udp$";
+                   }
+                }
+            }
         }
     }
 }