Auto-creation of bridges in vpnservice 18/40918/5
authorJosh <jhershbe@redhat.com>
Tue, 28 Jun 2016 09:24:14 +0000 (11:24 +0200)
committerSam Hague <shague@redhat.com>
Thu, 7 Jul 2016 14:42:50 +0000 (14:42 +0000)
When a new OVSDB node is detected, the
event is caught and we make sure that
br-int and br-ex (if l3 is configured)
exist. Note that br-ex is not technically
required and once devstack is modified
to not check for it, we should go back
in to this code and no longer create it.

This code add dependencies to the
following ovsdb project utility bundles
and jars:
- southbound-api
- utils.mdsal-utils
- utils.southbound-utils
- utils.config

Bug for removing checks for br-int when
running devstack:
https://bugs.launchpad.net/networking-odl/+bug/1599853

Change-Id: I852c2b619c99dc2748808efe27d8d24487e0cee7
Signed-off-by: Josh <jhershbe@redhat.com>
vpnservice/elanmanager/elanmanager-impl/pom.xml
vpnservice/elanmanager/elanmanager-impl/src/main/config/default-config.xml
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanNodeListener.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanOvsdbNodeListener.java [new file with mode: 0644]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanServiceProvider.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/BridgeUtils.java [new file with mode: 0644]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanConstants.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModule.java
vpnservice/elanmanager/elanmanager-impl/src/main/yang/elanservice-impl.yang
vpnservice/features/src/main/features/features.xml

index cace98680e2f8722aca05f4645061c264e69f512..7e14e7ee7b546eb6f2e481edb256a51172afb0a1 100644 (file)
@@ -86,6 +86,26 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>dhcpservice-api</artifactId>
       <version>${vpnservices.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>southbound-api</artifactId>
+      <version>${vpns.ovsdb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${vpns.ovsdb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.southbound-utils</artifactId>
+      <version>${vpns.ovsdb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.config</artifactId>
+      <version>${vpns.ovsdb.version}</version>
+    </dependency>
 
       <!--  Only for unit-test -->
    <dependency>
@@ -124,6 +144,21 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           <scope>test</scope>
       </dependency>
   </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Embed-Dependency>utils.config;type=!pom;inline=false</Embed-Dependency>
+            <Embed-Transitive>true</Embed-Transitive>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 
     <!--
         Maven Site Configuration
index a24a733fab6852f5cbe6b6a12917d4116abafc79..5986bdd2df9772c639db3ed794a546c45d72f656 100644 (file)
@@ -52,6 +52,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
                         <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
                         <name>entity-ownership-service</name>
                     </entity-ownership-service>
+                    <int-bridge-gen-mac>true</int-bridge-gen-mac>
                 </module>
             </modules>
             <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
index 73301ce93d54c88ff866376373e84b22331a77ed..25c530be1143555500a3a4854fc134ad3d3372c8 100644 (file)
@@ -47,8 +47,8 @@ public class ElanNodeListener extends AbstractDataChangeListener<Node> {
             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
                     getWildCardPath(), ElanNodeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
         } catch (final Exception e) {
-            logger.error("IfmNodeConnectorListener: DataChange listener registration fail!", e);
-            throw new IllegalStateException("IfmNodeConnectorListener: registration Listener failed.", e);
+            logger.error("ElanNodeListener: DataChange listener registration fail!", e);
+            throw new IllegalStateException("ElanNodeListener: registration Listener failed.", e);
         }
     }
 
diff --git a/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanOvsdbNodeListener.java b/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanOvsdbNodeListener.java
new file mode 100644 (file)
index 0000000..5813dbe
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.elan.internal;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.elan.utils.BridgeUtils;
+import org.opendaylight.netvirt.elan.utils.ElanConstants;
+import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+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.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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Listen for new OVSDB nodes and then make sure they have the necessary bridges configured
+ */
+public class ElanOvsdbNodeListener extends AbstractDataChangeListener<Node> {
+
+    private static final Logger logger = LoggerFactory.getLogger(ElanOvsdbNodeListener.class);
+
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private BridgeUtils bridgeUtils;
+    private boolean generateIntBridgeMac;
+
+    /**
+     * Constructor
+     * @param db the DataBroker
+     * @param generateIntBridgeMac true if the integration bridge should be given a fixed, random MAC address
+     */
+    public ElanOvsdbNodeListener(final DataBroker db, boolean generateIntBridgeMac) {
+        super(Node.class);
+        this.bridgeUtils = new BridgeUtils(db);
+        this.generateIntBridgeMac = generateIntBridgeMac;
+        registerListener(db);
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), ElanOvsdbNodeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            logger.error("ElanOvsdbNodeListener: DataChange listener registration fail!", e);
+            throw new IllegalStateException("ElanOvsdbNodeListener: registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<Node> getWildCardPath() {
+        return InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
+                .child(Node.class);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Node> identifier, Node del) {
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Node> identifier, Node original, Node update) {
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Node> identifier, Node add) {
+        logger.debug("ElanOvsdbNodeListener.add, new bridge detected{}", add);
+        bridgeUtils.prepareNode(add, generateIntBridgeMac);
+    }
+
+}
index 36836a0afc8ebdd5d8ed25f6c25171c02120c8c3..1d168f9a48f2d28ec07683ef0204c64dead24a87 100644 (file)
@@ -85,6 +85,9 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
 
     private static final ElanStatusMonitor elanStatusMonitor = ElanStatusMonitor.getInstance();
     static DataStoreJobCoordinator dataStoreJobCoordinator;
+    private ElanOvsdbNodeListener elanOvsdbNodeListener;
+
+    private boolean generateIntBridgeMac = true;
 
     public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
         dataStoreJobCoordinator = ds;
@@ -139,6 +142,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
 
 
             elanNodeListener = new ElanNodeListener(broker, mdsalManager);
+            elanOvsdbNodeListener = new ElanOvsdbNodeListener(broker, generateIntBridgeMac);
 
             elanPacketInHandler = new ElanPacketInHandler(broker);
             elanPacketInHandler.setInterfaceManager(interfaceManager);
@@ -520,4 +524,12 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         }
         return elanInterfaces;
     }
+
+    public boolean getGenerateIntBridgeMac() {
+        return generateIntBridgeMac;
+    }
+
+    public void setGenerateIntBridgeMac(boolean generateIntBridgeMac) {
+        this.generateIntBridgeMac = generateIntBridgeMac;
+    }
 }
diff --git a/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/BridgeUtils.java b/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/BridgeUtils.java
new file mode 100644 (file)
index 0000000..5bad9d7
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.elan.utils;
+
+import com.google.common.collect.ImmutableBiMap;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.utils.config.ConfigProperties;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+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.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeNetdev;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdk;
+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.OvsdbBridgeProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeBase;
+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.OvsdbFailModeStandalone;
+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.ovsdb.bridge.attributes.BridgeOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsBuilder;
+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.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.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntry;
+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.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+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.yangtools.yang.binding.InstanceIdentifier;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class provides functions for creating bridges via OVSDB, specifically the br-int bridge.
+ * Note and TODO: br-ex is temporary. vpnservice does not require it but for the time being it is
+ * left here because devstack expects it.
+ */
+public class BridgeUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(BridgeUtils.class);
+
+    private static final ImmutableBiMap<Class<? extends OvsdbFailModeBase>,String> OVSDB_FAIL_MODE_MAP
+            = new ImmutableBiMap.Builder<Class<? extends OvsdbFailModeBase>,String>()
+            .put(OvsdbFailModeStandalone.class,"standalone")
+            .put(OvsdbFailModeSecure.class,"secure")
+            .build();
+
+    private static final String DISABLE_IN_BAND = "disable-in-band";
+    private static final String INTEGRATION_BRIDGE = "br-int";
+    private static final String EXTERNAL_BRIDGE = "br-ex";
+
+    private final MdsalUtils mdsalUtils;
+    private final SouthboundUtils southboundUtils;
+    private Random random;
+
+
+    /**
+     * Construct a new BridgeUtils
+     * @param dataBroker
+     */
+    public BridgeUtils(DataBroker dataBroker) {
+        //TODO: ClusterAware!!!??
+        this.mdsalUtils = new MdsalUtils(dataBroker);
+        this.southboundUtils = new SouthboundUtils(mdsalUtils);
+        this.random = new Random(System.currentTimeMillis());
+    }
+
+    /**
+     * Is OVS running in userspace mode?
+     * @return true if the ovsdb.userspace.enabled variable is set to true
+     */
+    public boolean isUserSpaceEnabled() {
+        final String enabledPropertyStr = ConfigProperties.getProperty(this.getClass(), "ovsdb.userspace.enabled");
+        return enabledPropertyStr != null && enabledPropertyStr.equalsIgnoreCase("yes");
+    }
+
+    /**
+     * Is vpnservice handling L3 as well? This function is deprocated because br-ex is temporary as mentioned above
+     * @return true if the ovsdb.l3.fwd.enable is set to true
+     */
+    @Deprecated
+    public boolean isL3ForwardingEnabled() {
+        final String enabledPropertyStr = ConfigProperties.getProperty(this.getClass(), "ovsdb.l3.fwd.enabled");
+        return enabledPropertyStr != null && enabledPropertyStr.equalsIgnoreCase("yes");
+    }
+
+    /**
+     * Prepare the OVSDB node for netvirt, create br-int
+     * @param ovsdbNode The OVSDB node
+     * @param generateIntBridgeMac should BrigeUtil set br-int's mac address to a random address. If this vlaue is false, the dpid may change as ports are added to the bridge
+     */
+    public void prepareNode(Node ovsdbNode, boolean generateIntBridgeMac) {
+        try {
+            createIntegrationBridge(ovsdbNode, generateIntBridgeMac);
+        } catch (Exception e) {
+            LOG.error("Error creating Integration Bridge on {}", ovsdbNode, e);
+            return;
+        }
+
+        try {
+            if (isL3ForwardingEnabled()) {
+                createExternalBridge(ovsdbNode);
+            }
+        } catch (Exception e) {
+            LOG.error("Error creating External Bridge on {}", ovsdbNode, e);
+            return;
+        }
+        // this node is an ovsdb node so it doesn't have a bridge
+        // so either look up the bridges or just wait for the bridge update to come in
+        // and add the flows there.
+        //networkingProviderManager.getProvider(node).initializeFlowRules(node);
+    }
+
+    private boolean createIntegrationBridge(Node ovsdbNode, boolean generateIntBridgeMac) {
+        LOG.debug("BridgeUtils.createIntegrationBridge, skipping if exists");
+        if (!addBridge(ovsdbNode, INTEGRATION_BRIDGE,
+                generateIntBridgeMac ? generateRandomMac() : null)) {
+            LOG.warn("Integration Bridge Creation failed");
+            return false;
+        }
+        return true;
+    }
+
+    private boolean createExternalBridge(Node ovsdbNode) {
+        LOG.debug("BridgeUtils.createExternalBridge, skipping if exists");
+        if (!addBridge(ovsdbNode, EXTERNAL_BRIDGE, null)) {
+            LOG.warn("External Bridge Creation failed");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Add a bridge to the OVSDB node but check that it does not exist in the CONFIGURATION or OPERATIONAL md-sals first
+     * @param ovsdbNode Which OVSDB node
+     * @param bridgeName Name of the bridge
+     * @param mac mac address to set on the bridge or null
+     * @return true if no errors occurred
+     */
+    public boolean addBridge(Node ovsdbNode, String bridgeName, String mac) {
+        boolean rv = true;
+        if ((!isBridgeOnOvsdbNode(ovsdbNode, bridgeName)) ||
+                (getBridgeFromConfig(ovsdbNode, bridgeName) == null)) {
+            Class<? extends DatapathTypeBase> dpType = null;
+            if (isUserSpaceEnabled()) {
+                dpType = DatapathTypeNetdev.class;
+            }
+            rv = addBridge(ovsdbNode, bridgeName, southboundUtils.getControllersFromOvsdbNode(ovsdbNode), dpType, mac);
+        }
+        return rv;
+    }
+
+    /**
+     * Add a bridge to the OVSDB node
+     * @param ovsdbNode Which OVSDB node
+     * @param bridgeName Name of the bridge
+     * @param controllersStr OVSDB's controller
+     * @param dpType datapath type
+     * @param mac mac address to set on the bridge or null
+     * @return true if the write to md-sal was successful
+     */
+    public boolean addBridge(Node ovsdbNode, String bridgeName, List<String> controllersStr,
+                             final Class<? extends DatapathTypeBase> dpType, String mac) {
+        boolean result = false;
+
+        LOG.debug("addBridge: node: {}, bridgeName: {}, controller(s): {}", ovsdbNode, bridgeName, controllersStr);
+        ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(ovsdbNode);
+        if (connectionInfo == null) {
+            throw new InvalidParameterException("Could not find ConnectionInfo");
+        }
+
+        NodeBuilder bridgeNodeBuilder = new NodeBuilder();
+        InstanceIdentifier<Node> bridgeIid = southboundUtils.createInstanceIdentifier(ovsdbNode.getKey(), bridgeName);
+        NodeId bridgeNodeId = southboundUtils.createManagedNodeId(bridgeIid);
+        bridgeNodeBuilder.setNodeId(bridgeNodeId);
+
+        OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
+        ovsdbBridgeAugmentationBuilder.setControllerEntry(createControllerEntries(controllersStr));
+        ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridgeName));
+        ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
+        ovsdbBridgeAugmentationBuilder.setFailMode( OVSDB_FAIL_MODE_MAP.inverse().get("secure"));
+
+        BridgeOtherConfigsBuilder bridgeOtherConfigsBuilder = new BridgeOtherConfigsBuilder();
+        bridgeOtherConfigsBuilder.setBridgeOtherConfigKey(DISABLE_IN_BAND);
+        bridgeOtherConfigsBuilder.setBridgeOtherConfigValue("true");
+
+        List<BridgeOtherConfigs> bridgeOtherConfigsList = new ArrayList<>();
+        bridgeOtherConfigsList.add(bridgeOtherConfigsBuilder.build());
+        if (mac != null) {
+            BridgeOtherConfigsBuilder macOtherConfigBuilder = new BridgeOtherConfigsBuilder();
+            macOtherConfigBuilder.setBridgeOtherConfigKey("hwaddr");
+            macOtherConfigBuilder.setBridgeOtherConfigValue(mac);
+            bridgeOtherConfigsList.add(macOtherConfigBuilder.build());
+        }
+
+        ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(bridgeOtherConfigsList);
+        setManagedByForBridge(ovsdbBridgeAugmentationBuilder, ovsdbNode.getKey());
+        if (dpType != null) {
+            ovsdbBridgeAugmentationBuilder.setDatapathType(dpType);
+        }
+
+        if (isOvsdbNodeDpdk(ovsdbNode)) {
+            ovsdbBridgeAugmentationBuilder.setDatapathType(DatapathTypeNetdev.class);
+        }
+
+        bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
+
+        Node node = bridgeNodeBuilder.build();
+        result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, bridgeIid, node);
+        LOG.debug("addBridge: result: {}", result);
+
+        return result;
+    }
+
+    private List<ControllerEntry> createControllerEntries(List<String> controllersStr) {
+        List<ControllerEntry> controllerEntries = new ArrayList<>();
+        if (controllersStr != null) {
+            for (String controllerStr : controllersStr) {
+                ControllerEntryBuilder controllerEntryBuilder = new ControllerEntryBuilder();
+                controllerEntryBuilder.setTarget(new Uri(controllerStr));
+                controllerEntries.add(controllerEntryBuilder.build());
+            }
+        }
+        return controllerEntries;
+    }
+
+    private List<ProtocolEntry> createMdsalProtocols() {
+        List<ProtocolEntry> protocolList = new ArrayList<>();
+        ImmutableBiMap<String, Class<? extends OvsdbBridgeProtocolBase>> mapper =
+                southboundUtils.OVSDB_PROTOCOL_MAP.inverse();
+        protocolList.add(new ProtocolEntryBuilder().
+                setProtocol(mapper.get("OpenFlow13")).build());
+        return protocolList;
+    }
+
+    private void setManagedByForBridge(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
+                                       NodeKey ovsdbNodeKey) {
+        InstanceIdentifier<Node> connectionNodePath = southboundUtils.createInstanceIdentifier(ovsdbNodeKey.getNodeId());
+        ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
+    }
+
+    private boolean isOvsdbNodeDpdk(Node ovsdbNode) {
+        boolean found = false;
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = southboundUtils.extractNodeAugmentation(ovsdbNode);
+        if (ovsdbNodeAugmentation != null) {
+            List<InterfaceTypeEntry> ifTypes = ovsdbNodeAugmentation.getInterfaceTypeEntry();
+            if (ifTypes != null) {
+                for (InterfaceTypeEntry ifType : ifTypes) {
+                    if (ifType.getInterfaceType().equals(InterfaceTypeDpdk.class)) {
+                        found = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return found;
+    }
+
+    private boolean isBridgeOnOvsdbNode(Node ovsdbNode, String bridgeName) {
+        boolean found = false;
+        //TODO: MAKE SURE extract function is right
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = southboundUtils.extractNodeAugmentation(ovsdbNode);
+        if (ovsdbNodeAugmentation != null) {
+            List<ManagedNodeEntry> managedNodes = ovsdbNodeAugmentation.getManagedNodeEntry();
+            if (managedNodes != null) {
+                for (ManagedNodeEntry managedNode : managedNodes) {
+                    InstanceIdentifier<?> bridgeIid = managedNode.getBridgeRef().getValue();
+                    if (bridgeIid.toString().contains(bridgeName)) {
+                        found = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return found;
+    }
+
+    private OvsdbBridgeAugmentation getBridgeFromConfig(Node node, String bridge) {
+        OvsdbBridgeAugmentation ovsdbBridgeAugmentation = null;
+        InstanceIdentifier<Node> bridgeIid =
+                southboundUtils.createInstanceIdentifier(node.getKey(), bridge);
+        Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, bridgeIid);
+        if (bridgeNode != null) {
+            ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
+        }
+        return ovsdbBridgeAugmentation;
+    }
+
+    private String generateRandomMac() {
+        byte[] macBytes = new byte[6];
+        random.nextBytes(macBytes);
+        macBytes[0] &= 0xfc; //the two low bits of the first byte need to be zero
+
+        StringBuilder stringBuilder = new StringBuilder();
+
+        int i = 0;
+        while(true) {
+            stringBuilder.append(String.format("%02x", macBytes[i++]));
+            if (i >= 6) {
+                break;
+            }
+            stringBuilder.append(':');
+        }
+
+        return stringBuilder.toString();
+    }
+}
index 4750e438181b09becf5d79bf0508e21efa8cca84..da6a94011973e4f79d77de3136a7cf621fba4171 100755 (executable)
@@ -9,6 +9,9 @@ package org.opendaylight.netvirt.elan.utils;
 
 import java.math.BigInteger;
 
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+
 public class ElanConstants {
 
     public static final String ELAN_ID_POOL_NAME = "elan.ids.pool";
@@ -34,4 +37,6 @@ public class ElanConstants {
     public static final String L2GATEWAY_DS_JOB_NAME = "L2GW";
     public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
     public static final int JOB_MAX_RETRIES = 3;
+    public static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1"));
+    public static final String OVSDB_BRIDGE_URI_PREFIX = "bridge";
 }
index c8f0f2224b8168d2374014446b7920514ebaa888..05236f009df9fc16a4a9cd39e8216ea46c1af86a 100644 (file)
@@ -40,6 +40,7 @@ public class ElanServiceImplModule extends org.opendaylight.yang.gen.v1.urn.open
         provider.setItmManager(getItmmanagerDependency());
         provider.setIdManager(idManager);
         provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
+        provider.setGenerateIntBridgeMac(getIntBridgeGenMac());
         getBrokerDependency().registerProvider(provider);
         return provider;
     }
index 78294221176528ae5ea0254cf9c889124acb7938..de190cc2904b5398bc9f94bb4a785087be07add1 100644 (file)
@@ -85,6 +85,9 @@ module elanservice-impl {
                     }
                 }
             }
+            leaf int-bridge-gen-mac {
+                type boolean;
+            }
         }
     }
 }
\ No newline at end of file
index eb85f2a9d32a96bfa47f70cec1db63e98fa5f202..e77ebbabaf2ad1b3f4968b11c1efca0330ab8450 100644 (file)
@@ -64,6 +64,12 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <bundle>mvn:org.opendaylight.netvirt/ipv6service-impl/{{VERSION}}</bundle>
     <bundle>mvn:org.opendaylight.netvirt/ipv6service-api/{{VERSION}}</bundle>
 
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.southbound-utils/{{VERSION}}</bundle>
+
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.southbound-utils/{{VERSION}}</bundle>
+
     <!--<bundle>mvn:org.opendaylight.vpnservice.third-party/org.apache.thriftlib/1.1.0-SNAPSHOT</bundle>-->
     <bundle>wrap:mvn:org.apache.thrift/libthrift/0.9.1$overwrite=merge&amp;Bundle-Version=0.9.1&amp;Export-Package=*;-noimport:=true;version="0.9.1"</bundle>
     <!--<bundle>wrap:mvn:javax.servlet/servlet-api/2.5</bundle>-->