DHCP Handling for TOR VM 09/38009/4
authorKency Kurian <kency.kurian@ericsson.com>
Fri, 22 Apr 2016 10:04:52 +0000 (15:34 +0530)
committerKency Kurian <kency.kurian@ericsson.com>
Fri, 29 Apr 2016 03:13:23 +0000 (03:13 +0000)
- As the TOR floods the packets to the CSS mesh, some logic should be
  added such that only one CSS punts the DHCP packet to the controller and
  the other CSS drops the DHCP packet.
- The designated CSS is chosen for each TOR-ELAN pair and it is stored in
  the datastore.

Change-Id: I695f1a7600938c1e4f6411f9752de20bf44349cd
Signed-off-by: Kency Kurian <kency.kurian@ericsson.com>
24 files changed:
dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPUtils.java
dhcpservice/dhcpservice-api/src/main/yang/dhcp.yang [new file with mode: 0644]
dhcpservice/dhcpservice-impl/pom.xml
dhcpservice/dhcpservice-impl/src/main/config/default-config.xml
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceConfigListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceEventListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpManager.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpNeutronPortListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpPktHandler.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpProvider.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpServiceUtils.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpUCastMacListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/NodeListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModule.java
dhcpservice/dhcpservice-impl/src/main/yang/dhcpservice-impl.yang
neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/l2gw/utils/L2GatewayCacheUtils.java
neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/utils/NeutronUtils.java [new file with mode: 0644]
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronNetworkChangeListener.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronPortChangeListener.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnUtils.java

index 167e8077bf783fa9e4e1e28a0548f99931242ec0..99f7a7f6ecb56fdf479e5fc3f7033377c5ed735a 100644 (file)
@@ -86,4 +86,14 @@ public abstract class DHCPUtils {
         return result;
     }
 
+    public static String byteArrayToString(byte[] bytes) {
+        StringBuilder str = new StringBuilder();
+        for (byte b : bytes) {
+            str.append(Integer.toHexString((b >>> 4) & 0x0F));
+            str.append(Integer.toHexString(b & 0x0F));
+            str.append(":");
+        }
+        str.deleteCharAt(str.lastIndexOf(":"));
+        return str.toString();
+    }
 }
diff --git a/dhcpservice/dhcpservice-api/src/main/yang/dhcp.yang b/dhcpservice/dhcpservice-api/src/main/yang/dhcp.yang
new file mode 100644 (file)
index 0000000..14b721c
--- /dev/null
@@ -0,0 +1,34 @@
+module vpnservice-dhcp {
+    namespace "urn:opendaylight:vpnservice:dhcp";
+    prefix "dhcp";
+
+    import ietf-inet-types {
+        prefix inet;
+        revision-date "2010-09-24";
+    }
+
+    revision "2016-04-28" {
+        description "It provides required datastore containers to handle DHCP requests
+                     coming from access or external tunnel ports";
+    }
+
+    container designated-switches-for-external-tunnels {
+        config true;
+        description "contains designated dataplane-node-identifier which handles DHCP requests for each external tunnel";
+        list designated-switch-for-tunnel {
+            key "tunnel-remote-ip-address elan-instance-name";
+            leaf tunnel-remote-ip-address {
+                description "remote end point ip address of external tunnel";
+                type inet:ip-address;
+            }
+            leaf elan-instance-name {
+                description "elan name indicates l2 network domain";
+                type string;
+            }
+            leaf dpId {
+                description "contains dataplane-node-identifier";
+                type int64;
+            }
+        }
+    }
+}
\ No newline at end of file
index cff44a5f53057800f367a9ff744883e538d758f4..a5a5ce67f0bdeaa16299a8f06389298a997957f9 100644 (file)
@@ -64,6 +64,21 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>interfacemgr-api</artifactId>
       <version>${vpnservices.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>elanmanager-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>itm-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>hwvtepsouthbound-api</artifactId>
+      <version>${vpns.ovsdb.version}</version>
+    </dependency>
    </dependencies>
 
 </project>
index fe6008a4a2eb2258ca657388182d2e075625a286..988288d6fcc9d0823ef3acd1e143eb9f55c15545 100644 (file)
@@ -12,6 +12,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <capability>urn:opendaylight:params:xml:ns:yang:dhcpservice:impl?module=dhcpservice-impl&amp;revision=2015-07-10</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:mdsalutil:api?module=odl-mdsalutil&amp;revision=2015-04-10</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:config:distributed-entity-ownership-service?module=distributed-entity-ownership-service&amp;revision=2015-08-10</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:neutronvpn:api?module=neutronvpn-api&amp;revision=2015-08-12</capability>
   </required-capabilities>
   <configuration>
@@ -41,6 +42,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <type xmlns:neutronvpn="urn:opendaylight:params:xml:ns:yang:neutronvpn:api">neutronvpn:neutronvpn-api</type>
             <name>neutronvpn</name>
           </neutronvpn>
+          <entity-ownership-service>
+            <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>
         </module>
       </modules>
     </data>
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java
new file mode 100644 (file)
index 0000000..838cc46
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpDesignatedDpnListener extends AsyncClusteredDataChangeListenerBase<DesignatedSwitchForTunnel, DhcpDesignatedDpnListener> implements AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DhcpDesignatedDpnListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private DataBroker broker;
+
+    public DhcpDesignatedDpnListener(final DhcpExternalTunnelManager dhcpExternalTunnelManager, final DataBroker broker) {
+        super(DesignatedSwitchForTunnel.class, DhcpDesignatedDpnListener.class);
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+        this.broker = broker;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DhcpDesignatedDpnListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.debug("DhcpDesignatedDpnListener Listener Closed");
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel del) {
+        dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(del.getDpId()), del.getTunnelRemoteIpAddress(), del.getElanInstanceName());
+        dhcpExternalTunnelManager.unInstallDhcpFlowsForVms(del.getElanInstanceName(), del.getTunnelRemoteIpAddress(), DhcpServiceUtils.getListOfDpns(broker));
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel original,
+            DesignatedSwitchForTunnel update) {
+        BigInteger designatedDpnId = BigInteger.valueOf(update.getDpId());
+        IpAddress tunnelRemoteIpAddress = update.getTunnelRemoteIpAddress();
+        String elanInstanceName = update.getElanInstanceName();
+        dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()), original.getTunnelRemoteIpAddress(), original.getElanInstanceName());
+        dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+/*        List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+        if (elanDpns == null || elanDpns.isEmpty()) {
+            dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+        }*/
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel add) {
+        BigInteger designatedDpnId = BigInteger.valueOf(add.getDpId());
+        IpAddress tunnelRemoteIpAddress = add.getTunnelRemoteIpAddress();
+        String elanInstanceName = add.getElanInstanceName();
+        dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+/*        List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+        if (elanDpns == null || elanDpns.isEmpty()) {
+            dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+        }*/
+    }
+
+    @Override
+    protected InstanceIdentifier<DesignatedSwitchForTunnel> getWildCardPath() {
+        return InstanceIdentifier.create(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return DhcpDesignatedDpnListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.SUBTREE;
+    }
+}
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java
new file mode 100644 (file)
index 0000000..b51c834
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+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.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class DhcpExternalTunnelManager {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpExternalTunnelManager.class);
+    public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
+    private static final FutureCallback<Void> DEFAULT_CALLBACK =
+            new FutureCallback<Void>() {
+                @Override
+                public void onSuccess(Void result) {
+                    logger.debug("Success in Datastore write operation");
+                }
+                @Override
+                public void onFailure(Throwable error) {
+                    logger.error("Error in Datastore write operation", error);
+                };
+            };
+    private final DataBroker broker;
+    private IMdsalApiManager mdsalUtil;
+
+    private ConcurrentMap<BigInteger, List<Pair<IpAddress, String>>> designatedDpnsToTunnelIpElanNameCache = new ConcurrentHashMap<BigInteger, List<Pair<IpAddress, String>>>();
+    private ConcurrentMap<Pair<IpAddress, String>, Set<String>> tunnelIpElanNameToVmMacCache = new ConcurrentHashMap<Pair<IpAddress, String>, Set<String>>();
+    private ConcurrentMap<Pair<BigInteger, String>, Port> vniMacAddressToPortCache = new ConcurrentHashMap<Pair<BigInteger, String>, Port>();
+    private ItmRpcService itmRpcService;
+    private EntityOwnershipService entityOwnershipService;
+
+    public DhcpExternalTunnelManager(DataBroker broker, IMdsalApiManager mdsalUtil, ItmRpcService itmRpcService, EntityOwnershipService entityOwnershipService) {
+        this.broker = broker;
+        this.mdsalUtil = mdsalUtil;
+        this.itmRpcService = itmRpcService;
+        this.entityOwnershipService = entityOwnershipService;
+        initilizeCaches();
+    }
+
+    private void initilizeCaches() {
+        logger.trace("Loading designatedDpnsToTunnelIpElanNameCache");
+        InstanceIdentifier<DesignatedSwitchesForExternalTunnels> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).build();
+        Optional<DesignatedSwitchesForExternalTunnels> designatedSwitchForTunnelOptional = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
+        if (designatedSwitchForTunnelOptional.isPresent()) {
+            List<DesignatedSwitchForTunnel> list = designatedSwitchForTunnelOptional.get().getDesignatedSwitchForTunnel();
+            for (DesignatedSwitchForTunnel designatedSwitchForTunnel : list) {
+                List<Pair<IpAddress, String>> listOfTunnelIpElanNamePair = designatedDpnsToTunnelIpElanNameCache.get(designatedSwitchForTunnel.getDpId());
+                if (listOfTunnelIpElanNamePair == null) {
+                    listOfTunnelIpElanNamePair = new LinkedList<Pair<IpAddress, String>>();
+                }
+                Pair<IpAddress, String> tunnelIpElanNamePair = new ImmutablePair<IpAddress, String>(designatedSwitchForTunnel.getTunnelRemoteIpAddress(), designatedSwitchForTunnel.getElanInstanceName());
+                listOfTunnelIpElanNamePair.add(tunnelIpElanNamePair);
+                designatedDpnsToTunnelIpElanNameCache.put(BigInteger.valueOf(designatedSwitchForTunnel.getDpId()), listOfTunnelIpElanNamePair);
+            }
+        }
+        logger.trace("Loading vniMacAddressToPortCache");
+        InstanceIdentifier<Ports> inst = InstanceIdentifier.builder(Neutron.class).child(Ports.class).build();
+        Optional<Ports> optionalPorts = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+        if (optionalPorts.isPresent()) {
+            List<Port> list = optionalPorts.get().getPort();
+            for (Port port : list) {
+                if(NeutronUtils.isPortVnicTypeNormal(port)) {
+                    continue;
+                }
+                String macAddress = port.getMacAddress();
+                Uuid networkId = port.getNetworkId();
+                String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
+                if (segmentationId == null) {
+                    return;
+                }
+                updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, port);
+            }
+        }
+
+    }
+
+
+    public BigInteger designateDpnId(IpAddress tunnelIp,
+            String elanInstanceName, List<BigInteger> dpns) {
+        BigInteger designatedDpnId = readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
+        if (designatedDpnId != null && !designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+            logger.trace("Dpn {} already designated for tunnelIp - elan : {} - {}", designatedDpnId, tunnelIp, elanInstanceName);
+            return designatedDpnId;
+        }
+        return chooseDpn(tunnelIp, elanInstanceName, dpns);
+    }
+
+    public void installDhcpFlowsForVms(IpAddress tunnelIp, String elanInstanceName, List<BigInteger> dpns,
+            BigInteger designatedDpnId, String vmMacAddress) {
+        installDhcpEntries(designatedDpnId, vmMacAddress, entityOwnershipService);
+        dpns.remove(designatedDpnId);
+        for (BigInteger dpn : dpns) {
+            installDhcpDropAction(dpn, vmMacAddress, entityOwnershipService);
+        }
+        updateLocalCache(tunnelIp, elanInstanceName, vmMacAddress);
+    }
+
+    public void installDhcpFlowsForVms(IpAddress tunnelIp,
+            String elanInstanceName, BigInteger designatedDpnId, Set<String> listVmMacAddress) {
+        for (String vmMacAddress : listVmMacAddress) {
+            installDhcpEntries(designatedDpnId, vmMacAddress);
+        }
+    }
+
+    public void unInstallDhcpFlowsForVms(String elanInstanceName, List<BigInteger> dpns, String vmMacAddress) {
+        for (BigInteger dpn : dpns) {
+            unInstallDhcpEntries(dpn, vmMacAddress, entityOwnershipService);
+        }
+        removeFromLocalCache(elanInstanceName, vmMacAddress);
+    }
+
+    public BigInteger readDesignatedSwitchesForExternalTunnel(IpAddress tunnelIp, String elanInstanceName) {
+        InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp)).build();
+        Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
+        if (designatedSwitchForTunnelOptional.isPresent()) {
+            return BigInteger.valueOf(designatedSwitchForTunnelOptional.get().getDpId());
+        }
+        return null;
+    }
+
+    public void writeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp, String elanInstanceName) {
+        DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey = new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
+        InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
+        DesignatedSwitchForTunnel designatedSwitchForTunnel = new DesignatedSwitchForTunnelBuilder().setDpId(dpnId.longValue()).setElanInstanceName(elanInstanceName).setTunnelRemoteIpAddress(tunnelIp).setKey(designatedSwitchForTunnelKey).build();
+        logger.trace("Writing into CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp, elanInstanceName, dpnId);
+        MDSALDataStoreUtils.asyncUpdate(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier, designatedSwitchForTunnel, DEFAULT_CALLBACK);
+    }
+
+    public void removeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp, String elanInstanceName) {
+        DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey = new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
+        InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
+        logger.trace("Writing into CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp, elanInstanceName, dpnId);
+        MDSALDataStoreUtils.asyncRemove(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier, DEFAULT_CALLBACK);
+    }
+
+    public void installDhcpDropActionOnDpn(BigInteger dpId) {
+        List<String> vmMacs = getAllVmMacs();
+        logger.trace("Installing drop actions to this new DPN {} VMs {}", dpId, vmMacs);
+        for (String vmMacAddress : vmMacs) {
+            installDhcpDropAction(dpId, vmMacAddress);
+        }
+    }
+
+    private List<String> getAllVmMacs() {
+        List<String> vmMacs = new LinkedList<String>();
+        Collection<Set<String>> listOfVmMacs = tunnelIpElanNameToVmMacCache.values();
+        for (Set<String> list : listOfVmMacs) {
+            vmMacs.addAll(list);
+        }
+        return vmMacs;
+    }
+
+    public void updateLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
+        Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+        List<Pair<IpAddress, String>> tunnelIpElanNameList;
+        tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
+        if (tunnelIpElanNameList == null) {
+            tunnelIpElanNameList = new LinkedList<Pair<IpAddress, String>>();
+        }
+        tunnelIpElanNameList.add(tunnelIpElanName);
+        designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameList);
+    }
+
+    private void updateLocalCache(IpAddress tunnelIp, String elanInstanceName, String vmMacAddress) {
+        Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+        Set<String> listExistingVmMacAddress;
+        listExistingVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanName);
+        if (listExistingVmMacAddress == null) {
+            listExistingVmMacAddress = new HashSet<String>();
+        }
+        listExistingVmMacAddress.add(vmMacAddress);
+        tunnelIpElanNameToVmMacCache.put(tunnelIpElanName, listExistingVmMacAddress);
+    }
+
+    public void handleDesignatedDpnDown(BigInteger dpnId, List<BigInteger> listOfDpns) {
+        logger.trace("In handleDesignatedDpnDown dpnId {}, listOfDpns {}", dpnId, listOfDpns);
+        try {
+            List<Pair<IpAddress, String>> listOfTunnelIpElanNamePairs = designatedDpnsToTunnelIpElanNameCache.get(dpnId);
+            if (!dpnId.equals(DHCPMConstants.INVALID_DPID)) {
+                List<String> listOfVms = getAllVmMacs();
+                for (String vmMacAddress : listOfVms) {
+                    unInstallDhcpEntries(dpnId, vmMacAddress);
+                }
+            }
+            if (listOfTunnelIpElanNamePairs == null || listOfTunnelIpElanNamePairs.isEmpty()) {
+                logger.trace("No tunnelIpElanName to handle for dpn {}. Returning", dpnId);
+                return;
+            }
+            for (Pair<IpAddress, String> pair : listOfTunnelIpElanNamePairs) {
+                updateCacheAndInstallNewFlows(dpnId, listOfDpns, pair);
+            }
+        } catch (Exception e) {
+            logger.error("Error in handleDesignatedDpnDown {}", e);
+        }
+    }
+
+    public void updateCacheAndInstallNewFlows(BigInteger dpnId,
+            List<BigInteger> listOfDpns, Pair<IpAddress, String> pair)
+            throws ExecutionException {
+        BigInteger newDesignatedDpn = chooseDpn(pair.getLeft(), pair.getRight(), listOfDpns);
+        if (newDesignatedDpn.equals(DHCPMConstants.INVALID_DPID)) {
+            return;
+        }
+        Set<String> listVmMacs = tunnelIpElanNameToVmMacCache.get(pair);
+        if (listVmMacs != null && !listVmMacs.isEmpty()) {
+            installDhcpFlowsForVms(pair.getLeft(), pair.getRight(), newDesignatedDpn, listVmMacs);
+        }
+    }
+
+    private void changeExistingFlowToDrop(Pair<IpAddress, String> tunnelIpElanNamePair, BigInteger dpnId) {
+        try {
+            Set<String> listVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
+            if (listVmMacAddress == null || listVmMacAddress.isEmpty()) {
+                return;
+            }
+            for (String vmMacAddress : listVmMacAddress) {
+                installDhcpDropAction(dpnId, vmMacAddress);
+            }
+        } catch (Exception e) {
+            logger.error("Error in uninstallExistingFlows {}", e);
+        }
+    }
+
+    /**
+     * Choose a dpn among the list of elanDpns such that it has lowest count of being the designated dpn.
+     * @param tunnelIp
+     * @param elanInstanceName
+     * @param dpns
+     * @return
+     */
+    private BigInteger chooseDpn(IpAddress tunnelIp, String elanInstanceName,
+            List<BigInteger> dpns) {
+        BigInteger designatedDpnId = DHCPMConstants.INVALID_DPID;
+        if (dpns != null && dpns.size() != 0) {
+            List<BigInteger> candidateDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+            candidateDpns.retainAll(dpns);
+            logger.trace("Choosing new dpn for tunnelIp {}, elanInstanceName {}, among elanDpns {}", tunnelIp, elanInstanceName, candidateDpns);
+            boolean elanDpnAvailableFlag = true;
+            if (candidateDpns == null || candidateDpns.isEmpty()) {
+                candidateDpns = dpns;
+                elanDpnAvailableFlag = false;
+            }
+            int size = 0;
+            L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
+            if (device == null) {
+                logger.trace("Could not find any device for elanInstanceName {} and tunnelIp {}", elanInstanceName, tunnelIp);
+                handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
+                return designatedDpnId;
+            }
+            for (BigInteger dpn : candidateDpns) {
+                String hwvtepNodeId = device.getHwvtepNodeId();
+                if (!elanDpnAvailableFlag) {
+                    if (!isTunnelConfigured(dpn, hwvtepNodeId)) {
+                        logger.trace("Tunnel is not configured on dpn {} to TOR {}", dpn, hwvtepNodeId);
+                        continue;
+                    }
+                } else if (!isTunnelUp(hwvtepNodeId, dpn)) {
+                    logger.trace("Tunnel is not up between dpn {} and TOR {}", dpn, hwvtepNodeId);
+                    continue;
+                }
+                List<Pair<IpAddress, String>> tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(dpn);
+                if (tunnelIpElanNameList == null) {
+                    designatedDpnId = dpn;
+                    break;
+                }
+                if (size == 0 || tunnelIpElanNameList.size() < size) {
+                    size = tunnelIpElanNameList.size();
+                    designatedDpnId = dpn;
+                }
+            }
+            if (!elanDpnAvailableFlag) {
+                installRemoteMcastMac(designatedDpnId, device, elanInstanceName);
+            }
+            writeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
+            return designatedDpnId;
+        }
+        handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
+        return designatedDpnId;
+    }
+
+    private void handleUnableToDesignateDpn(IpAddress tunnelIp, String elanInstanceName) {
+        writeDesignatedSwitchForExternalTunnel(DHCPMConstants.INVALID_DPID, tunnelIp, elanInstanceName);
+    }
+
+    public void installDhcpEntries(BigInteger dpnId, String vmMacAddress) {
+        DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
+    }
+
+    public void installDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
+        final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, MDSALUtil.NODE_PREFIX, nodeId);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    installDhcpEntries(dpnId, vmMacAddress);
+                } else {
+                    logger.trace("Exiting installDhcpEntries since this cluster node is not the owner for dpn {}", nodeId);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Error while fetching checkNodeEntityOwner", error);
+            }
+        });
+    }
+
+    public void unInstallDhcpEntries(BigInteger dpnId, String vmMacAddress) {
+        DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil);
+    }
+
+    public void unInstallDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
+        final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, MDSALUtil.NODE_PREFIX, nodeId);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    unInstallDhcpEntries(dpnId, vmMacAddress);
+                } else {
+                    logger.trace("Exiting unInstallDhcpEntries since this cluster node is not the owner for dpn {}", nodeId);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Error while fetching checkNodeEntityOwner", error);
+            }
+        });
+    }
+
+    public void installDhcpDropAction(BigInteger dpn, String vmMacAddress) {
+        DhcpServiceUtils.setupDhcpDropAction(dpn, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
+    }
+
+    public void installDhcpDropAction(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
+        final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, MDSALUtil.NODE_PREFIX, nodeId);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    installDhcpDropAction(dpnId, vmMacAddress);
+                } else {
+                    logger.trace("Exiting installDhcpDropAction since this cluster node is not the owner for dpn {}", nodeId);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Error while fetching checkNodeEntityOwner", error);
+            }
+        });
+    }
+
+    public void handleTunnelStateDown(IpAddress tunnelIp, BigInteger interfaceDpn) {
+        logger.trace("In handleTunnelStateDown tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
+        if (interfaceDpn == null) {
+            return;
+        }
+        try {
+            List<Pair<IpAddress, String>> tunnelElanPairList = designatedDpnsToTunnelIpElanNameCache.get(interfaceDpn);
+            if (tunnelElanPairList == null || tunnelElanPairList.isEmpty()) {
+                return;
+            }
+            for (Pair<IpAddress, String> tunnelElanPair : tunnelElanPairList) {
+                IpAddress tunnelIpInDpn = tunnelElanPair.getLeft();
+                if (tunnelIpInDpn.equals(tunnelIp)) {
+                    List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
+                    dpns.remove(interfaceDpn);
+                    changeExistingFlowToDrop(tunnelElanPair, interfaceDpn);
+                    updateCacheAndInstallNewFlows(interfaceDpn, dpns, tunnelElanPair);
+                }
+            }
+        } catch (Exception e) {
+            logger.error("Error in handleTunnelStateDown {}", e.getMessage());
+            logger.trace("Exception details {}", e);
+        }
+    }
+
+    private void removeFromLocalCache(String elanInstanceName, String vmMacAddress) {
+        Set<Pair<IpAddress, String>> tunnelIpElanNameKeySet = tunnelIpElanNameToVmMacCache.keySet();
+        for (Pair<IpAddress, String> pair : tunnelIpElanNameKeySet) {
+            if (pair.getRight().trim().equalsIgnoreCase(elanInstanceName.trim())) {
+                Set<String> listExistingVmMacAddress;
+                listExistingVmMacAddress = tunnelIpElanNameToVmMacCache.get(pair);
+                if (listExistingVmMacAddress == null || listExistingVmMacAddress.isEmpty()) {
+                    continue;
+                }
+                listExistingVmMacAddress.remove(vmMacAddress);
+                if (listExistingVmMacAddress.size() > 0) {
+                    tunnelIpElanNameToVmMacCache.put(pair, listExistingVmMacAddress);
+                    return;
+                }
+                tunnelIpElanNameToVmMacCache.remove(pair);
+            }
+        }
+    }
+
+    public void removeFromLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
+        Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+        List<Pair<IpAddress, String>> tunnelIpElanNameList;
+        tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
+        if (tunnelIpElanNameList != null) {
+            tunnelIpElanNameList.remove(tunnelIpElanName);
+            if (tunnelIpElanNameList.size() != 0) {
+                designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameList);
+            } else {
+                designatedDpnsToTunnelIpElanNameCache.remove(designatedDpnId);
+            }
+        }
+    }
+
+    public void updateVniMacToPortCache(BigInteger vni, String macAddress, Port port) {
+        if (macAddress == null) {
+            return;
+        }
+        Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
+        logger.trace("Updating vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}", vni, macAddress.toUpperCase(), vniMacAddressPair, port);
+        vniMacAddressToPortCache.put(vniMacAddressPair, port);
+    }
+
+    public void removeVniMacToPortCache(BigInteger vni, String macAddress) {
+        if (macAddress == null) {
+            return;
+        }
+        Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
+        vniMacAddressToPortCache.remove(vniMacAddressPair);
+    }
+
+    public Port readVniMacToPortCache(BigInteger vni, String macAddress) {
+        if (macAddress == null) {
+            return null;
+        }
+        Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
+        logger.trace("Reading vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}", vni, macAddress.toUpperCase(), vniMacAddressPair, vniMacAddressToPortCache.get(vniMacAddressPair));
+        return vniMacAddressToPortCache.get(vniMacAddressPair);
+    }
+
+    public String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
+        String tunnelInterfaceName = null;
+        try {
+            Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
+                    .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
+                            .setSourceNode(sourceNode).setDestinationNode(dstNode).build());
+
+            RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
+            if (rpcResult.isSuccessful()) {
+                tunnelInterfaceName = rpcResult.getResult().getInterfaceName();
+                logger.debug("Tunnel interface name: {}", tunnelInterfaceName);
+            } else {
+                logger.warn("RPC call to ITM.GetExternalTunnelInterfaceName failed with error: {}",
+                        rpcResult.getErrors());
+            }
+        } catch (NullPointerException | InterruptedException | ExecutionException e) {
+            logger.error("Failed to get external tunnel interface name for sourceNode: {} and dstNode: {}: {} ",
+                    sourceNode, dstNode, e);
+        }
+        return tunnelInterfaceName;
+    }
+
+    public static Optional<Node> getNode(DataBroker dataBroker, String physicalSwitchNodeId) {
+        InstanceIdentifier<Node> psNodeId = HwvtepSouthboundUtils
+                .createInstanceIdentifier(new NodeId(physicalSwitchNodeId));
+        Optional<Node> physicalSwitchOptional = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, psNodeId, dataBroker);
+        return physicalSwitchOptional;
+    }
+
+    public RemoteMcastMacs createRemoteMcastMac(Node dstDevice, String logicalSwitchName, IpAddress internalTunnelIp) {
+        List<LocatorSet> locators = new ArrayList<>();
+        for (TerminationPoint tp : dstDevice.getTerminationPoint()) {
+            HwvtepPhysicalLocatorAugmentation aug = tp.getAugmentation(HwvtepPhysicalLocatorAugmentation.class);
+            if (internalTunnelIp.getIpv4Address().equals(aug.getDstIp().getIpv4Address())) {
+                HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
+                        HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(dstDevice.getNodeId(), aug));
+                locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
+            }
+        }
+        HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
+                .createLogicalSwitchesInstanceIdentifier(dstDevice.getNodeId(), new HwvtepNodeName(logicalSwitchName)));
+
+        RemoteMcastMacs remoteUcastMacs = new RemoteMcastMacsBuilder()
+                .setMacEntryKey(new MacAddress(UNKNOWN_DMAC))
+                .setLogicalSwitchRef(lsRef).setLocatorSet(locators).build();
+        return remoteUcastMacs;
+    }
+
+    private WriteTransaction putRemoteMcastMac(WriteTransaction transaction, String elanName, L2GatewayDevice device, IpAddress internalTunnelIp) {
+        Optional<Node> optionalNode = getNode(broker, device.getHwvtepNodeId());
+        Node dstNode = optionalNode.get();
+        if (dstNode == null) {
+            logger.debug("could not get device node {} ", device.getHwvtepNodeId());
+            return null;
+        }
+        RemoteMcastMacs macs = createRemoteMcastMac(dstNode, elanName, internalTunnelIp);
+        HwvtepUtils.putRemoteMcastMac(transaction, dstNode.getNodeId(), macs);
+        return transaction;
+    }
+
+    private void installRemoteMcastMac(BigInteger designatedDpnId, L2GatewayDevice device, String elanInstanceName) {
+        String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(designatedDpnId), device.getHwvtepNodeId());
+        IpAddress internalTunnelIp = null;
+        if (tunnelInterfaceName != null) {
+            Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
+            if (tunnelInterface == null) {
+                logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
+                return;
+            }
+            internalTunnelIp = tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource();
+            WriteTransaction transaction = broker.newWriteOnlyTransaction();
+            putRemoteMcastMac(transaction, elanInstanceName, device, internalTunnelIp);
+            if (transaction != null) {
+                transaction.submit();
+            }
+        }
+    }
+
+    private L2GatewayDevice getDeviceFromTunnelIp(String elanInstanceName, IpAddress tunnelIp) {
+        ConcurrentMap<String, L2GatewayDevice> devices = L2GatewayCacheUtils.getCache();
+        for (L2GatewayDevice device : devices.values()) {
+            if (device.getTunnelIp().equals(tunnelIp)) {
+                return device;
+            }
+        }
+        return null;
+    }
+
+    private boolean isTunnelUp(String nodeName, BigInteger dpn) {
+        boolean isTunnelUp = false;
+        String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), nodeName);
+        if (tunnelInterfaceName == null) {
+            logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
+            return isTunnelUp;
+        }
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromOperationalDS(tunnelInterfaceName, broker);
+        if (tunnelInterface == null) {
+            logger.debug("Interface {} is not present in interface state", tunnelInterfaceName);
+            return isTunnelUp;
+        }
+        isTunnelUp = (tunnelInterface.getOperStatus() == OperStatus.Up) ? true :false;
+        return isTunnelUp;
+    }
+
+    public void handleTunnelStateUp(IpAddress tunnelIp, BigInteger interfaceDpn) {
+        logger.trace("In handleTunnelStateUp tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
+        try {
+            List<Pair<IpAddress, String>> tunnelIpElanPair = designatedDpnsToTunnelIpElanNameCache.get(DHCPMConstants.INVALID_DPID);
+            List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
+            if (tunnelIpElanPair == null || tunnelIpElanPair.isEmpty()) {
+                return;
+            }
+            for (Pair<IpAddress, String> pair : tunnelIpElanPair) {
+                if (tunnelIp.equals(pair.getLeft())) {
+                    designateDpnId(tunnelIp, pair.getRight(), dpns);
+                }
+            }
+        } catch (Exception e) {
+            logger.error("Error in handleTunnelStateUp {}", e.getMessage());
+            logger.trace("Exception details {}", e);
+        }
+    }
+
+    private boolean isTunnelConfigured(BigInteger dpn, String hwVtepNodeId) {
+        String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), hwVtepNodeId);
+        if (tunnelInterfaceName == null) {
+            return false;
+        }
+        Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
+        if (tunnelInterface == null) {
+            logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
+            return false;
+        }
+        return true;
+    }
+
+    public void unInstallDhcpFlowsForVms(String elanInstanceName, IpAddress tunnelIp, List<BigInteger> dpns) {
+        Pair<IpAddress, String> tunnelIpElanNamePair = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+        Set<String> vmMacs = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
+        logger.trace("In unInstallFlowsForVms elanInstanceName {}, tunnelIp {}, dpns {}, vmMacs {}", elanInstanceName, tunnelIp, dpns, vmMacs);
+        if (vmMacs == null) {
+            return;
+        }
+        for (String vmMacAddress : vmMacs) {
+            for (BigInteger dpn : dpns) {
+                unInstallDhcpEntries(dpn, vmMacAddress, entityOwnershipService);
+            }
+        }
+        tunnelIpElanNameToVmMacCache.remove(tunnelIpElanNamePair);
+    }
+}
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceConfigListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceConfigListener.java
new file mode 100644 (file)
index 0000000..1bb1dd7
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.dhcpservice;
+
+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.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpInterfaceConfigListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpInterfaceConfigListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DataBroker dataBroker;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+
+    public DhcpInterfaceConfigListener(DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+        super(Interface.class);
+        this.dataBroker = dataBroker;
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+        registerListener();
+    }
+
+    private void registerListener() {
+        try {
+            listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                    getWildCardPath(), DhcpInterfaceConfigListener.this, DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            logger.error("DhcpInterfaceEventListener DataChange listener registration fail!", e);
+            throw new IllegalStateException("DhcpInterfaceEventListener registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<Interface> getWildCardPath() {
+        return InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        logger.info("DhcpInterfaceConfigListener Closed");
+    }
+    @Override
+    protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
+        IfTunnel tunnelInterface = del.getAugmentation(IfTunnel.class);
+        if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+            IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+            ParentRefs interfce = del.getAugmentation(ParentRefs.class);
+            if (interfce != null) {
+                dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, interfce.getDatapathNodeIdentifier());
+            }
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
+        // Handled in update () DhcpInterfaceEventListener
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
+        // Handled in add() DhcpInterfaceEventListener
+    }
+}
\ No newline at end of file
index 5cc245653a097bdf6d4f4ac3b5f59344a06fd34c..199db9136be5478683dc9210f6ad55845c1992a6 100644 (file)
@@ -10,21 +10,28 @@ package org.opendaylight.vpnservice.dhcpservice;
 import java.math.BigInteger;
 import java.util.List;
 
+import org.apache.commons.lang3.tuple.ImmutablePair;
 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.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.InterfaceNameMacAddresses;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -40,26 +47,30 @@ public class DhcpInterfaceEventListener extends AbstractDataChangeListener<Inter
     private ListenerRegistration<DataChangeListener> listenerRegistration;
     private DataBroker dataBroker;
     private static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
+        @Override
         public void onSuccess(Void result) {
             logger.debug("Success in Datastore write operation");
         }
 
+        @Override
         public void onFailure(Throwable error) {
             logger.error("Error in Datastore write operation", error);
         }
     };
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
 
-    public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker) {
+    public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) {
         super(Interface.class);
         this.dhcpManager = dhcpManager;
         this.dataBroker = dataBroker;
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         registerListener();
     }
 
     private void registerListener() {
         try {
             listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
-                    getWildCardPath(), DhcpInterfaceEventListener.this, DataChangeScope.SUBTREE);
+                getWildCardPath(), DhcpInterfaceEventListener.this, DataChangeScope.SUBTREE);
         } catch (final Exception e) {
             logger.error("DhcpInterfaceEventListener DataChange listener registration fail!", e);
             throw new IllegalStateException("DhcpInterfaceEventListener registration Listener failed.", e);
@@ -85,29 +96,109 @@ public class DhcpInterfaceEventListener extends AbstractDataChangeListener<Inter
 
 
     @Override
-    protected void remove(InstanceIdentifier<Interface> identifier,
-            Interface del) {
-        String interfaceName = del.getName();
+    protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
         List<String> ofportIds = del.getLowerLayerIf();
+        if (ofportIds == null || ofportIds.isEmpty()) {
+            return;
+        }
         NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
         BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+                DhcpServiceUtils.getInterfaceFromConfigDS(del.getName(), dataBroker);
+        if (iface != null) {
+            IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class);
+            if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+                IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+                List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+                if (dpns.contains(dpId)) {
+                    dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, dpId);
+                }
+                return;
+            }
+        }
+        String interfaceName = del.getName();
         logger.trace("Received remove DCN for interface {} dpId {}", interfaceName, dpId);
         unInstallDhcpEntries(interfaceName, dpId);
+        dhcpManager.removeInterfaceCache(interfaceName);
     }
 
     @Override
     protected void update(InstanceIdentifier<Interface> identifier,
             Interface original, Interface update) {
+        List<String> ofportIds = update.getLowerLayerIf();
+        if (ofportIds == null || ofportIds.isEmpty()) {
+            return;
+        }
+        NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
+        BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
+        String interfaceName = update.getName();
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+                DhcpServiceUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
+        if (iface == null) {
+            logger.trace("Interface {} is not present in the config DS", interfaceName);
+            return;
+        }
+        if (update.getType() == null) {
+            logger.trace("Interface type for interface {} is null", interfaceName);
+            return;
+        }
+        if ((original.getOperStatus().getIntValue() ^ update.getOperStatus().getIntValue()) == 0) {
+            logger.trace("Interface operstatus {} is same", update.getOperStatus());
+            return;
+        }
+        if (Tunnel.class.equals(update.getType())) {
+            IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class);
+            if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+                IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+                List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+                if (dpns.contains(dpId)) {
+                    if (update.getOperStatus() == OperStatus.Down) {
+                        dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, dpId);
+                    } else if (update.getOperStatus() == OperStatus.Up) {
+                        dhcpExternalTunnelManager.handleTunnelStateUp(tunnelIp, dpId);
+                    }
+                }
+            }
+            return;
+        }
+        if (update.getOperStatus() == OperStatus.Down) {
+            unInstallDhcpEntries(interfaceName, dpId);
+            dhcpManager.removeInterfaceCache(interfaceName);
+        } else if (update.getOperStatus() == OperStatus.Up) {
+            if (!dpId.equals(DHCPMConstants.INVALID_DPID)) {
+                installDhcpEntries(interfaceName, dpId);
+                dhcpManager.updateInterfaceCache(interfaceName, new ImmutablePair<BigInteger, String>(dpId, update.getPhysAddress().getValue()));
+            }
+        }
     }
 
     @Override
     protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
         String interfaceName = add.getName();
         List<String> ofportIds = add.getLowerLayerIf();
+        if (ofportIds == null || ofportIds.isEmpty()) {
+            return;
+        }
         NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
         BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
         logger.trace("Received add DCN for interface {}, dpid {}", interfaceName, dpId);
-        installDhcpEntries(interfaceName, dpId);
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+                DhcpServiceUtils.getInterfaceFromConfigDS(add.getName(), dataBroker);
+        if (iface != null) {
+            IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class);
+            if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+                IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+                List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+                if (dpns.contains(dpId)) {
+                    dhcpExternalTunnelManager.handleTunnelStateUp(tunnelIp, dpId);
+                }
+                return;
+            }
+        }
+        if (!dpId.equals(DHCPMConstants.INVALID_DPID)) {
+            installDhcpEntries(interfaceName, dpId);
+            dhcpManager.updateInterfaceCache(interfaceName, new ImmutablePair<BigInteger, String>(dpId, add.getPhysAddress().getValue()));
+        }
     }
 
     private String getNeutronMacAddress(String interfaceName) {
@@ -116,7 +207,6 @@ public class DhcpInterfaceEventListener extends AbstractDataChangeListener<Inter
             logger.trace("Port found in neutron. Interface Name {}, port {}", interfaceName, port);
             return port.getMacAddress();
         }
-        logger.trace("Port not found in neutron. Interface Name {}", interfaceName);
         return null;
     }
 
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java
new file mode 100644 (file)
index 0000000..6ba1776
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.L2gatewayConnections;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.L2gateways;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gateway;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gatewayKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DhcpL2GatewayConnectionListener extends AsyncClusteredDataChangeListenerBase<L2gatewayConnection,DhcpL2GatewayConnectionListener> implements AutoCloseable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpInterfaceEventListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private final DataBroker dataBroker;
+
+    public DhcpL2GatewayConnectionListener(DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+        super(L2gatewayConnection.class, DhcpL2GatewayConnectionListener.class);
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+        this.dataBroker = dataBroker;
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<L2gatewayConnection> identifier,
+            L2gatewayConnection del) {
+        Uuid gatewayId = del.getL2gatewayId();
+        InstanceIdentifier<L2gateway> inst = InstanceIdentifier.create(Neutron.class).child(L2gateways.class)
+                .child(L2gateway.class, new L2gatewayKey(gatewayId));
+        Optional<L2gateway> l2Gateway = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, inst);
+        if (!l2Gateway.isPresent()) {
+            return;
+        }
+        Uuid networkUuid = del.getNetworkId();
+        boolean isLastConnection = true;
+        InstanceIdentifier<L2gatewayConnections> l2gatewayConnectionIdentifier = InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class);
+        Optional<L2gatewayConnections> l2GwConnection = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, l2gatewayConnectionIdentifier);
+        List<L2gatewayConnection> l2GatewayConnectionList = l2GwConnection.get().getL2gatewayConnection();
+        for (L2gatewayConnection l2gatewayConnection : l2GatewayConnectionList) {
+            if (networkUuid.equals(l2gatewayConnection.getNetworkId())) {
+                isLastConnection = false;
+                break;
+            }
+        }
+        if (!isLastConnection) {
+            return;
+        }
+        List<Devices> l2Devices = l2Gateway.get().getDevices();
+        for (Devices l2Device : l2Devices) {
+            String l2DeviceName = l2Device.getDeviceName();
+            L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+            IpAddress tunnelIp = l2GatewayDevice.getTunnelIp();
+            BigInteger designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, del.getNetworkId().getValue());
+            if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+                logger.error("Could not find desiganted DPN ID");
+                return;
+            }
+            dhcpExternalTunnelManager.removeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, del.getNetworkId().getValue());
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<L2gatewayConnection> identifier,
+            L2gatewayConnection original, L2gatewayConnection update) {
+
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<L2gatewayConnection> identifier,
+            L2gatewayConnection add) {
+
+    }
+
+    @Override
+    protected InstanceIdentifier<L2gatewayConnection> getWildCardPath() {
+        return InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class)
+                .child(L2gatewayConnection.class);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return DhcpL2GatewayConnectionListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.SUBTREE;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        logger.info("DhcpL2GatewayConnection listener Closed");
+    }
+}
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java
new file mode 100644 (file)
index 0000000..5f46611
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+
+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.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpLogicalSwitchListener extends AbstractDataChangeListener<LogicalSwitches> implements AutoCloseable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpLogicalSwitchListener.class);
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DataBroker dataBroker;
+
+    public DhcpLogicalSwitchListener(DhcpExternalTunnelManager dhcpManager, DataBroker dataBroker) {
+        super(LogicalSwitches.class);
+        this.dhcpExternalTunnelManager = dhcpManager;
+        this.dataBroker = dataBroker;
+        registerListener();
+    }
+
+    private void registerListener() {
+        try {
+            listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), DhcpLogicalSwitchListener.this, DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            logger.error("DhcpLogicalSwitchListener DataChange listener registration fail!", e);
+            throw new IllegalStateException("DhcpLogicalSwitchListener registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<LogicalSwitches> getWildCardPath() {
+        return InstanceIdentifier.create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+                .child(Node.class).augmentation(HwvtepGlobalAugmentation.class)
+                .child(LogicalSwitches.class);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        logger.info("DhcpLogicalSwitchListener Closed");
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<LogicalSwitches> identifier,
+            LogicalSwitches del) {
+        logger.trace("Received LogicalSwitch remove DCN");
+        String elanInstanceName = del.getLogicalSwitchUuid().toString();
+        ConcurrentMap<String, L2GatewayDevice> devices  = L2GatewayCacheUtils.getCache();
+        String nodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+        L2GatewayDevice targetDevice = null;
+        for (L2GatewayDevice device : devices.values()) {
+            if (nodeId.equals(device.getHwvtepNodeId())) {
+                targetDevice = device;
+                break;
+            }
+        }
+        if (targetDevice == null) {
+            logger.error("Logical Switch Device with name {} is not present in L2GW cache", elanInstanceName);
+            return;
+        }
+        IpAddress tunnelIp = targetDevice.getTunnelIp();
+        handleLogicalSwitchRemove(elanInstanceName, tunnelIp);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<LogicalSwitches> identifier,
+            LogicalSwitches original, LogicalSwitches update) {
+        logger.trace("Received LogicalSwitch update DCN");
+
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<LogicalSwitches> identifier,
+            LogicalSwitches add) {
+        logger.trace("Received LogicalSwitch add DCN");
+        String elanInstanceName = add.getHwvtepNodeName().getValue();
+        ConcurrentMap<String, L2GatewayDevice> devices  = L2GatewayCacheUtils.getCache();
+        String nodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+        L2GatewayDevice targetDevice = null;
+        for (L2GatewayDevice device : devices.values()) {
+            if (nodeId.equals(device.getHwvtepNodeId())) {
+                targetDevice = device;
+                break;
+            }
+        }
+        if (targetDevice == null) {
+            logger.error("Logical Switch Device with name {} is not present in L2GW cache", elanInstanceName);
+            return;
+        }
+        IpAddress tunnelIp = targetDevice.getTunnelIp();
+        handleLogicalSwitchAdd(elanInstanceName, tunnelIp);
+
+    }
+
+    private void handleLogicalSwitchRemove(String elanInstanceName, IpAddress tunnelIp) {
+        BigInteger designatedDpnId;
+        designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
+        if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+            logger.error("Could not find designated DPN ID");
+            return;
+        }
+        dhcpExternalTunnelManager.removeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
+    }
+
+    private void handleLogicalSwitchAdd(String elanInstanceName, IpAddress tunnelIp) {
+        List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+        BigInteger designatedDpnId;
+        designatedDpnId = dhcpExternalTunnelManager.designateDpnId(tunnelIp, elanInstanceName, dpns);
+        if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+            logger.error("Unable to designate a DPN");
+            return;
+        }
+    }
+}
\ No newline at end of file
index 2309defb00a5ad69c9b46bcd792508228718d20a..af36ca955d24949290f1b1a0b990fe13987fe5d2 100644 (file)
@@ -7,36 +7,22 @@
  */
 package org.opendaylight.vpnservice.dhcpservice;
 
-import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
-
-import com.google.common.base.Optional;
-
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
-import com.google.common.util.concurrent.FutureCallback;
-
+import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
-import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
-import org.opendaylight.vpnservice.mdsalutil.ActionType;
 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
-import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
 import org.slf4j.Logger;
@@ -53,16 +39,8 @@ public class DhcpManager implements AutoCloseable {
     private int dhcpOptRebindingTime = 0;
     private String dhcpOptDefDomainName;
     private INeutronVpnManager neutronVpnService;
-
-    private static final FutureCallback<Void> DEFAULT_CALLBACK =
-        new FutureCallback<Void>() {
-            public void onSuccess(Void result) {
-                logger.debug("Success in Datastore write operation");
-            }
-            public void onFailure(Throwable error) {
-                logger.error("Error in Datastore write operation", error);
-            };
-        };
+    // cache used to maintain DpnId and physical address for each interface.
+    private static HashMap<String, ImmutablePair<BigInteger, String>> interfaceToDpnIdMacAddress = new HashMap<String, ImmutablePair<BigInteger, String>>();
 
     /**
     * @param db - dataBroker reference
@@ -86,43 +64,6 @@ public class DhcpManager implements AutoCloseable {
         logger.info("DHCP Manager Closed");
     }
 
-    public void installDhcpEntries(BigInteger dpnId) {
-        logger.debug("Installing Default DHCP Flow tp DPN: {}", dpnId);
-        setupDefaultDhcpFlow(dpnId, NwConstants.DHCP_TABLE, NwConstants.ADD_FLOW);
-    }
-
-    private void setupDefaultDhcpFlow(BigInteger dpId,  short tableId, int addOrRemove) {
-
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-
-        matches.add(new MatchInfo(MatchFieldType.eth_type,
-                new long[] { NwConstants.ETHTYPE_IPV4 }));
-        matches.add(new MatchInfo(MatchFieldType.ip_proto,
-                new long[] { IPProtocols.UDP.intValue() }));
-        matches.add(new MatchInfo(MatchFieldType.udp_src,
-                new long[] { DHCPMConstants.dhcpClientPort }));
-        matches.add(new MatchInfo(MatchFieldType.udp_dst,
-                new long[] { DHCPMConstants.dhcpServerPort }));
-
-        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
-
-        // Punt to controller
-        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
-                new String[] {}));
-        instructions.add(new InstructionInfo(InstructionType.write_actions,
-                actionsInfos));
-        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                getDefaultDhcpFlowRef(dpId, tableId),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
-                DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
-        mdsalUtil.installFlow(flowEntity);
-    }
-
-    private String getDefaultDhcpFlowRef(BigInteger dpId, long tableId) {
-        return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX).append(dpId)
-                        .append(NwConstants.FLOWID_SEPARATOR).append(tableId).toString();
-    }
-
     public int setLeaseDuration(int leaseDuration) {
         configureLeaseDuration(leaseDuration);
         return getDhcpLeaseTime();
@@ -174,6 +115,8 @@ public class DhcpManager implements AutoCloseable {
     public Port getNeutronPort(String name) {
         try {
             return neutronVpnService.getNeutronPort(name);
+        } catch (IllegalArgumentException e) {
+            return null;
         } catch (Exception ex) {
             logger.trace("In getNeutronPort interface name passed {} exception message {}.", name, ex.getMessage());
             return null;
@@ -181,59 +124,11 @@ public class DhcpManager implements AutoCloseable {
     }
 
     public void installDhcpEntries(BigInteger dpnId, String vmMacAddress) {
-        setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.ADD_FLOW);
-    }
-
-    private void setupDhcpFlowEntry(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove) {
-        if (dpId == null || dpId == DHCPMConstants.INVALID_DPID || vmMacAddress == null) {
-            return;
-        }
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-
-        matches.add(new MatchInfo(MatchFieldType.eth_type,
-                new long[] { NwConstants.ETHTYPE_IPV4 }));
-        matches.add(new MatchInfo(MatchFieldType.ip_proto,
-                new long[] { IPProtocols.UDP.intValue() }));
-        matches.add(new MatchInfo(MatchFieldType.udp_src,
-                new long[] { DHCPMConstants.dhcpClientPort }));
-        matches.add(new MatchInfo(MatchFieldType.udp_dst,
-                new long[] { DHCPMConstants.dhcpServerPort }));
-        matches.add(new MatchInfo(MatchFieldType.eth_src,
-                new String[] { vmMacAddress }));
-
-        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
-
-        // Punt to controller
-        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
-                new String[] {}));
-        instructions.add(new InstructionInfo(InstructionType.write_actions,
-                actionsInfos));
-        if (addOrRemove == NwConstants.DEL_FLOW) {
-            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                    getDhcpFlowRef(dpId, tableId, vmMacAddress),
-                    DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
-                    DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
-            logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
-            mdsalUtil.removeFlow(flowEntity);
-        } else {
-            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                    getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
-                    DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
-            logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
-            mdsalUtil.installFlow(flowEntity);
-        }
-    }
-
-    private String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
-        return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX)
-                .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
-                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
-                .append(vmMacAddress).toString();
+        DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
     }
 
     public void unInstallDhcpEntries(BigInteger dpId, String vmMacAddress) {
-        setupDhcpFlowEntry(dpId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.DEL_FLOW);
+        DhcpServiceUtils.setupDhcpFlowEntry(dpId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil);
     }
 
     public void setupTableMissForDhcpTable(BigInteger dpId) {
@@ -245,5 +140,29 @@ public class DhcpManager implements AutoCloseable {
                 0, "DHCP Table Miss Flow", 0, 0,
                 DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
         mdsalUtil.installFlow(flowEntity);
+        setupTableMissForHandlingExternalTunnel(dpId);
+    }
+
+    private void setupTableMissForHandlingExternalTunnel(BigInteger dpId) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.EXTERNAL_TUNNEL_TABLE }));
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, "DHCPTableMissFlowForExternalTunnel",
+                0, "DHCP Table Miss Flow For External Tunnel", 0, 0,
+                DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
+        mdsalUtil.installFlow(flowEntity);
+    }
+
+    public void updateInterfaceCache(String interfaceName, ImmutablePair<BigInteger, String> pair) {
+        interfaceToDpnIdMacAddress.put(interfaceName, pair);
+    }
+
+    public ImmutablePair<BigInteger, String> getInterfaceCache(String interfaceName) {
+        return interfaceToDpnIdMacAddress.get(interfaceName);
+    }
+
+    public void removeInterfaceCache(String interfaceName) {
+        interfaceToDpnIdMacAddress.remove(interfaceName);
     }
 }
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpNeutronPortListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpNeutronPortListener.java
new file mode 100644 (file)
index 0000000..385d919
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpNeutronPortListener extends AsyncClusteredDataChangeListenerBase<Port, DhcpNeutronPortListener> implements AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DhcpNeutronPortListener.class);
+
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private DataBroker broker;
+
+    public DhcpNeutronPortListener(final DataBroker db, final DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+        super(Port.class, DhcpNeutronPortListener.class);
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+        this.broker = db;
+    }
+
+    @Override
+    protected InstanceIdentifier<Port> getWildCardPath() {
+        return InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DhcpNeutronPortListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.debug("DhcpNeutronPortListener Listener Closed");
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Port> identifier, Port del) {
+        LOG.trace("Port removed: {}", del);
+        if(NeutronUtils.isPortVnicTypeNormal(del)) {
+            return;
+        }
+        String macAddress = del.getMacAddress();
+        Uuid networkId = del.getNetworkId();
+        String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
+        if (segmentationId == null) {
+            return;
+        }
+        List<BigInteger> listOfDpns = DhcpServiceUtils.getListOfDpns(broker);
+        dhcpExternalTunnelManager.unInstallDhcpFlowsForVms(networkId.getValue(), listOfDpns, macAddress);
+        dhcpExternalTunnelManager.removeVniMacToPortCache(new BigInteger(segmentationId), macAddress);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
+        LOG.trace("Port changed to {}", update);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Port> identifier, Port add) {
+        LOG.trace("Port added {}", add);
+        if(NeutronUtils.isPortVnicTypeNormal(add)) {
+            LOG.trace("Port is normal {}", add);
+            return;
+        }
+        String macAddress = add.getMacAddress();
+        Uuid networkId = add.getNetworkId();
+        String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
+        if (segmentationId == null) {
+            LOG.trace("segmentation id is null");
+            return;
+        }
+        dhcpExternalTunnelManager.updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, add);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return DhcpNeutronPortListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.SUBTREE;
+    }
+}
index 60d8bd729ec465a125968e3826dff8c2c37a0131..c74171a30ffe28c33b91a2e2fbd7dc9d3d6b6289 100644 (file)
@@ -13,7 +13,6 @@ import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -72,11 +71,12 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
     private final DataBroker dataBroker;
     private final DhcpManager dhcpMgr;
     private OdlInterfaceRpcService interfaceManagerRpc;
-    private static HashMap<String, ImmutablePair<BigInteger, String>> localCache = new HashMap<String, ImmutablePair<BigInteger, String>>();
     private boolean computeUdpChecksum = true;
     private PacketProcessingService pktService;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
 
-    public DhcpPktHandler(final DataBroker broker, final DhcpManager dhcpManager) {
+    public DhcpPktHandler(final DataBroker broker, final DhcpManager dhcpManager, final DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         this.dataBroker = broker;
         dhcpMgr = dhcpManager;
     }
@@ -84,16 +84,15 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
     //TODO: Handle this in a separate thread
     @Override
     public void onPacketReceived(PacketReceived packet) {
-        LOG.trace("Pkt received: {}", packet);
         Class<? extends PacketInReason> pktInReason = packet.getPacketInReason();
-        short tableId = packet.getTableId().getValue();
         if (isPktInReasonSendtoCtrl(pktInReason)) {
             byte[] inPayload = packet.getPayload();
             Ethernet ethPkt = new Ethernet();
             try {
                 ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
             } catch (Exception e) {
-                LOG.warn("Failed to decode DHCP Packet", e);
+                LOG.warn("Failed to decode DHCP Packet {}", e);
+                LOG.trace("Received packet {}", packet);
                 return;
             }
             try {
@@ -101,29 +100,33 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
                 pktIn = getDhcpPktIn(ethPkt);
                 if (pktIn != null) {
                     LOG.trace("DHCPPkt received: {}", pktIn);
+                    LOG.trace("Received Packet: {}", packet);
                     BigInteger metadata = packet.getMatch().getMetadata().getMetadata();
                     long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+                    String macAddress = DHCPUtils.byteArrayToString(ethPkt.getSourceMACAddress());
+                    BigInteger tunnelId = packet.getMatch().getTunnel() == null ? null : packet.getMatch().getTunnel().getTunnelId();
                     String interfaceName = getInterfaceNameFromTag(portTag);
                     ImmutablePair<BigInteger, String> pair = getDpnIdPhysicalAddressFromInterfaceName(interfaceName);
-                    DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName);
+                    DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName, macAddress, tunnelId);
                     byte[] pktOut = getDhcpPacketOut(replyPkt, ethPkt, pair.getRight());
-                    sendPacketOut(pktOut, pair.getLeft(), interfaceName);
+                    sendPacketOut(pktOut, pair.getLeft(), interfaceName, tunnelId);
                 }
             } catch (Exception e) {
-                LOG.warn("Failed to get DHCP Reply {}", e);
+                LOG.warn("Failed to get DHCP Reply");
+                LOG.trace("Reason for failure {}", e);
             }
         }
     }
 
-    private void sendPacketOut(byte[] pktOut, BigInteger dpnId, String interfaceName) {
+    private void sendPacketOut(byte[] pktOut, BigInteger dpnId, String interfaceName, BigInteger tunnelId) {
         LOG.trace("Sending packet out DpId {}, portId {}, vlanId {}, interfaceName {}", dpnId, interfaceName);
-        List<Action> action = getEgressAction(interfaceName);
+        List<Action> action = getEgressAction(interfaceName, tunnelId);
         TransmitPacketInput output = MDSALUtil.getPacketOut(action, pktOut, dpnId);
         LOG.trace("Transmitting packet: {}",output);
         this.pktService.transmitPacket(output);
     }
 
-    private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName) {
+    private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName, String macAddress, BigInteger tunnelId) {
         LOG.debug("DHCP pkt rcvd {}", dhcpPkt);
         byte msgType = dhcpPkt.getMsgType();
         if (msgType == DHCPConstants.MSG_DECLINE) {
@@ -133,8 +136,12 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
             LOG.debug("DHCPRELEASE received");
             return null;
         }
-
-        Port nPort = getNeutronPort(interfaceName);
+        Port nPort;
+        if (tunnelId != null) {
+            nPort = dhcpExternalTunnelManager.readVniMacToPortCache(tunnelId, macAddress);
+        } else {
+            nPort = getNeutronPort(interfaceName);
+        }
         Subnet nSubnet = getNeutronSubnet(nPort);
         DhcpInfo dhcpInfo = getDhcpInfo(nPort, nSubnet);
         LOG.trace("NeutronPort: {} \n NeutronSubnet: {}, dhcpInfo{}",nPort, nSubnet, dhcpInfo);
@@ -160,13 +167,6 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
             dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
                 .setCidr(nSubnet.getCidr()).setHostRoutes(nSubnet.getHostRoutes())
                 .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp);
-        } else {
-            //FIXME: Delete this test code
-            LOG.error("TestOnly Code");
-            dhcpInfo = new DhcpInfo();
-            dhcpInfo.setClientIp("1.1.1.3").setServerIp("1.1.1.1")
-                .setCidr("1.1.1.0/24").addDnsServer("1.1.1.1");
-            LOG.warn("Failed to get Subnet info for DHCP reply");
         }
         return dhcpInfo;
     }
@@ -181,7 +181,6 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
 
     private DHCP getDhcpPktIn(Ethernet actualEthernetPacket) {
         Ethernet ethPkt = actualEthernetPacket;
-        LOG.trace("Inside getDhcpPktIn ethPkt {} \n getPayload {}", ethPkt, ethPkt.getPayload());
         if (ethPkt.getEtherType() == (short)NwConstants.ETHTYPE_802_1Q) {
             ethPkt = (Ethernet)ethPkt.getPayload();
         }
@@ -197,7 +196,8 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
                     try {
                         reply.deserialize(rawDhcpPayload, 0, rawDhcpPayload.length);
                     } catch (PacketException e) {
-                        LOG.warn("Failed to deserialize DHCP pkt {}", e);
+                        LOG.warn("Failed to deserialize DHCP pkt");
+                        LOG.trace("Reason for failure {}", e);
                         return null;
                     }
                     return reply;
@@ -329,7 +329,6 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
             ether.setEtherType(EtherTypes.IPv4.shortValue());
             ether.setPayload(ip4Reply);
         }
-        //TODO: 
         ether.setSourceMACAddress(getServerMacAddress(phyAddrees));
         ether.setDestinationMACAddress(etherPkt.getSourceMACAddress());
 
@@ -577,12 +576,15 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
         return id;
     }
 
-    private List<Action> getEgressAction(String interfaceName) {
+    private List<Action> getEgressAction(String interfaceName, BigInteger tunnelId) {
         List<Action> actions = null;
         try {
+            GetEgressActionsForInterfaceInputBuilder egressAction = new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName);
+            if (tunnelId != null) {
+                egressAction.setTunnelKey(tunnelId.longValue());
+            }
             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
-                    interfaceManagerRpc.getEgressActionsForInterface(
-                            new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName).build());
+                    interfaceManagerRpc.getEgressActionsForInterface(egressAction.build());
             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
             if(!rpcResult.isSuccessful()) {
                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", interfaceName, rpcResult.getErrors());
@@ -596,7 +598,7 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
     }
 
     private ImmutablePair<BigInteger, String> getDpnIdPhysicalAddressFromInterfaceName(String interfaceName) {
-        ImmutablePair<BigInteger, String> pair = localCache.get(interfaceName);
+        ImmutablePair<BigInteger, String> pair = dhcpMgr.getInterfaceCache(interfaceName);
         if (pair!=null && pair.getLeft() != null && pair.getRight() != null) {
             return pair;
         }
@@ -609,7 +611,7 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
         BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
         String phyAddress = interfaceState==null ? "":interfaceState.getPhysAddress().getValue();
         pair = new ImmutablePair<BigInteger, String>(dpId, phyAddress);
-        localCache.put(interfaceName, pair);
-        return null;
+        dhcpMgr.updateInterfaceCache(interfaceName, pair);
+        return pair;
     }
 }
index 439d7352ada125065e56709c544c8a17d38d72f4..f86b46424ec7de44a7f67eb263f2a0ecf9dcb214 100644 (file)
@@ -7,15 +7,18 @@
  */
 package org.opendaylight.vpnservice.dhcpservice;
 
-import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
-import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yangtools.concepts.Registration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,6 +35,15 @@ public class DhcpProvider implements BindingAwareProvider, AutoCloseable {
     private DhcpConfigListener dhcpConfigListener;
     private OdlInterfaceRpcService interfaceManagerRpc;
     private DhcpInterfaceEventListener dhcpInterfaceEventListener;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private DhcpNeutronPortListener dhcpNeutronPortListener;
+    private DhcpLogicalSwitchListener dhcpLogicalSwitchListener;
+    private DhcpUCastMacListener dhcpUCastMacListener;
+    private ItmRpcService itmRpcService;
+    private DhcpInterfaceConfigListener dhcpInterfaceConfigListener;
+    private EntityOwnershipService entityOwnershipService;
+    private DhcpDesignatedDpnListener dhcpDesignatedDpnListener;
+    private DhcpL2GatewayConnectionListener dhcpL2GatewayConnectionListener;
 
     @Override
     public void onSessionInitiated(ProviderContext session) {
@@ -42,19 +54,29 @@ public class DhcpProvider implements BindingAwareProvider, AutoCloseable {
             dhcpManager = new DhcpManager(dataBroker);
             dhcpManager.setMdsalManager(mdsalManager);
             dhcpManager.setNeutronVpnService(neutronVpnManager);
-            dhcpPktHandler = new DhcpPktHandler(dataBroker, dhcpManager);
+            dhcpExternalTunnelManager = new DhcpExternalTunnelManager(dataBroker, mdsalManager, itmRpcService, entityOwnershipService);
+            dhcpPktHandler = new DhcpPktHandler(dataBroker, dhcpManager, dhcpExternalTunnelManager);
             dhcpPktHandler.setPacketProcessingService(pktProcessingService);
             dhcpPktHandler.setInterfaceManagerRpc(interfaceManagerRpc);
             packetListener = notificationService.registerNotificationListener(dhcpPktHandler);
-            dhcpNodeListener = new NodeListener(dataBroker, dhcpManager);
+            dhcpNodeListener = new NodeListener(dataBroker, dhcpManager, dhcpExternalTunnelManager);
             dhcpConfigListener = new DhcpConfigListener(dataBroker, dhcpManager);
-            dhcpInterfaceEventListener = new DhcpInterfaceEventListener(dhcpManager, dataBroker);
+            dhcpInterfaceEventListener = new DhcpInterfaceEventListener(dhcpManager, dataBroker, dhcpExternalTunnelManager);
+            dhcpInterfaceConfigListener = new DhcpInterfaceConfigListener(dataBroker, dhcpExternalTunnelManager);
+            dhcpLogicalSwitchListener = new DhcpLogicalSwitchListener(dhcpExternalTunnelManager, dataBroker);
+            dhcpUCastMacListener = new DhcpUCastMacListener(dhcpExternalTunnelManager, dataBroker);
+            dhcpUCastMacListener.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
+            dhcpNeutronPortListener = new DhcpNeutronPortListener(dataBroker, dhcpExternalTunnelManager);
+            dhcpNeutronPortListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+            dhcpDesignatedDpnListener = new DhcpDesignatedDpnListener(dhcpExternalTunnelManager, dataBroker);
+            dhcpDesignatedDpnListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+            dhcpL2GatewayConnectionListener = new DhcpL2GatewayConnectionListener(dataBroker, dhcpExternalTunnelManager);
+            dhcpL2GatewayConnectionListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
         } catch (Exception e) {
             LOG.error("Error initializing services {}", e);
         }
     }
 
-
     public void setMdsalManager(IMdsalApiManager mdsalManager) {
         this.mdsalManager = mdsalManager;
     }
@@ -84,4 +106,12 @@ public class DhcpProvider implements BindingAwareProvider, AutoCloseable {
     public void setInterfaceManagerRpc(OdlInterfaceRpcService interfaceManagerRpc) {
         this.interfaceManagerRpc = interfaceManagerRpc;
     }
+
+    public void setItmRpcService(ItmRpcService itmRpcService) {
+        this.itmRpcService = itmRpcService;
+    }
+
+    public void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+        this.entityOwnershipService = entityOwnershipService;
+    }
 }
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpServiceUtils.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpServiceUtils.java
new file mode 100644 (file)
index 0000000..c6fd549
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+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.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DhcpServiceUtils {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpServiceUtils.class);
+
+    public static Interface getInterfaceFromConfigDS(String interfaceName, DataBroker dataBroker) {
+        InterfaceKey interfaceKey = new InterfaceKey(interfaceName);
+        InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
+        Optional<Interface> interfaceOptional = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, interfaceId, dataBroker);
+        if (!interfaceOptional.isPresent()) {
+            return null;
+        }
+        return interfaceOptional.get();
+    }
+
+    private static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
+        InstanceIdentifier.InstanceIdentifierBuilder<Interface> interfaceInstanceIdentifierBuilder =
+                InstanceIdentifier.builder(Interfaces.class).child(Interface.class, interfaceKey);
+        return interfaceInstanceIdentifierBuilder.build();
+    }
+
+    public static void setupDhcpFlowEntry(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove, IMdsalApiManager mdsalUtil) {
+        if (dpId == null || dpId.equals(DHCPMConstants.INVALID_DPID) || vmMacAddress == null) {
+            return;
+        }
+        List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+
+        // Punt to controller
+        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
+                new String[] {}));
+        instructions.add(new InstructionInfo(InstructionType.write_actions,
+                actionsInfos));
+        if (addOrRemove == NwConstants.DEL_FLOW) {
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+                    getDhcpFlowRef(dpId, tableId, vmMacAddress),
+                    DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+                    DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
+            logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            mdsalUtil.removeFlow(flowEntity);
+        } else {
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+                    getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+                    DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
+            logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            mdsalUtil.installFlow(flowEntity);
+        }
+    }
+
+    private static String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
+        return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX)
+                .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(vmMacAddress).toString();
+    }
+
+    public static void setupDhcpDropAction(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove, IMdsalApiManager mdsalUtil) {
+        if (dpId == null || dpId.equals(DHCPMConstants.INVALID_DPID) || vmMacAddress == null) {
+            return;
+        }
+        List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
+
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+        // Drop Action
+        actionsInfos.add(new ActionInfo(ActionType.drop_action,
+                new String[] {}));
+        if (addOrRemove == NwConstants.DEL_FLOW) {
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+                    getDhcpFlowRef(dpId, tableId, vmMacAddress),
+                    DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+                    DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
+            logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            mdsalUtil.removeFlow(flowEntity);
+        } else {
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+                    getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+                    DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
+            logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            mdsalUtil.installFlow(flowEntity);
+        }
+    }
+
+    private static List<MatchInfo> getDhcpMatch(String vmMacAddress) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { NwConstants.ETHTYPE_IPV4 }));
+        matches.add(new MatchInfo(MatchFieldType.ip_proto,
+                new long[] { IPProtocols.UDP.intValue() }));
+        matches.add(new MatchInfo(MatchFieldType.udp_src,
+                new long[] { DHCPMConstants.dhcpClientPort }));
+        matches.add(new MatchInfo(MatchFieldType.udp_dst,
+                new long[] { DHCPMConstants.dhcpServerPort }));
+        matches.add(new MatchInfo(MatchFieldType.eth_src,
+                new String[] { vmMacAddress }));
+        return matches;
+    }
+
+    public static List<BigInteger> getListOfDpns(DataBroker broker) {
+        List<BigInteger> dpnsList = new LinkedList<BigInteger>();
+        InstanceIdentifier<Nodes> nodesInstanceIdentifier = InstanceIdentifier.builder(Nodes.class).build();
+        Optional<Nodes> nodesOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, nodesInstanceIdentifier);
+        if (!nodesOptional.isPresent()) {
+            return dpnsList;
+        }
+        Nodes nodes = nodesOptional.get();
+        List<Node> nodeList = nodes.getNode();
+        for (Node node : nodeList) {
+            NodeId nodeId = node.getId();
+            if (nodeId == null) {
+                continue;
+            }
+            BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeId);
+            dpnsList.add(dpnId);
+        }
+        return dpnsList;
+    }
+
+    public static List<BigInteger> getDpnsForElan(String elanInstanceName, DataBroker broker) {
+        List<BigInteger> elanDpns = new LinkedList<BigInteger>();
+        InstanceIdentifier<ElanDpnInterfacesList> elanDpnInstanceIdentifier = InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
+        Optional<ElanDpnInterfacesList> elanDpnOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInstanceIdentifier);
+        if (elanDpnOptional.isPresent()) {
+            List<DpnInterfaces> dpns = elanDpnOptional.get().getDpnInterfaces();
+            for (DpnInterfaces dpnInterfaces : dpns) {
+                elanDpns.add(dpnInterfaces.getDpId());
+            }
+        }
+        return elanDpns;
+    }
+
+    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceFromOperationalDS(String interfaceName, DataBroker dataBroker) {
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey interfaceKey = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName);
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceId = InstanceIdentifier.builder(InterfacesState.class).child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class, interfaceKey).build();
+        Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceOptional = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, interfaceId, dataBroker);
+        if (!interfaceOptional.isPresent()) {
+            return null;
+        }
+        return interfaceOptional.get();
+    }
+
+
+    public static String getSegmentationId(Uuid networkId, DataBroker broker) {
+        InstanceIdentifier<Network> inst = InstanceIdentifier.create(Neutron.class).child(Networks.class).child
+                (Network.class, new NetworkKey(networkId));
+        Optional<Network> optionalNetwork = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+        if (!optionalNetwork.isPresent()) {
+            return null;
+        }
+        Network network = optionalNetwork.get();
+        String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(network);
+        return segmentationId;
+    }
+
+    public static String getNodeIdFromDpnId(BigInteger dpnId) {
+        return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
+    }
+
+    public static String getTrunkPortMacAddress(String parentRefName,
+            DataBroker broker) {
+        InstanceIdentifier<Port> portInstanceIdentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
+        Optional<Port> trunkPort = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, portInstanceIdentifier);
+        if (!trunkPort.isPresent()) {
+            logger.warn("Trunk port {} not available for sub-port", parentRefName);
+            return null;
+        }
+        return trunkPort.get().getMacAddress();
+    }
+}
\ No newline at end of file
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpUCastMacListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpUCastMacListener.java
new file mode 100644 (file)
index 0000000..472414e
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+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.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DhcpUCastMacListener extends AsyncClusteredDataChangeListenerBase<LocalUcastMacs, DhcpUCastMacListener> implements AutoCloseable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpUCastMacListener.class);
+    private DataBroker broker;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+
+    public DhcpUCastMacListener(DhcpExternalTunnelManager dhcpManager, DataBroker dataBroker) {
+        super(LocalUcastMacs.class, DhcpUCastMacListener.class);
+        this.broker = dataBroker;
+        this.dhcpExternalTunnelManager = dhcpManager;
+    }
+
+    @Override
+    protected InstanceIdentifier<LocalUcastMacs> getWildCardPath() {
+        return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
+                .augmentation(HwvtepGlobalAugmentation.class).child(LocalUcastMacs.class);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        logger.info("DhcpUCastMacListener Closed");
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<LocalUcastMacs> identifier,
+            LocalUcastMacs del) {
+        // Flow removal for table 18 is handled in Neutron Port delete.
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<LocalUcastMacs> identifier,
+            LocalUcastMacs original, LocalUcastMacs update) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<LocalUcastMacs> identifier,
+            LocalUcastMacs add) {
+        NodeId torNodeId = identifier.firstKeyOf(Node.class).getNodeId();
+        InstanceIdentifier<LogicalSwitches> logicalSwitchRef = (InstanceIdentifier<LogicalSwitches>) add.getLogicalSwitchRef().getValue();
+        Optional<LogicalSwitches> logicalSwitchOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, logicalSwitchRef);
+        if ( !logicalSwitchOptional.isPresent() ) {
+            logger.error("Logical Switch ref doesn't have data {}", logicalSwitchRef);
+            return;
+        }
+        LogicalSwitches logicalSwitch = logicalSwitchOptional.get();
+        String elanInstanceName = logicalSwitch.getHwvtepNodeName().getValue();
+        L2GatewayDevice device = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanInstanceName, torNodeId.getValue());
+        if (device == null) {
+            logger.error("Logical Switch Device with name {} is not present in L2GWCONN cache", elanInstanceName);
+            return;
+        }
+        IpAddress tunnelIp = device.getTunnelIp();
+        BigInteger designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
+        dhcpExternalTunnelManager.installDhcpFlowsForVms(tunnelIp, elanInstanceName, DhcpServiceUtils.getListOfDpns(broker), designatedDpnId, add.getMacEntryKey().getValue());
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return DhcpUCastMacListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return DataChangeScope.SUBTREE;
+    }
+}
\ No newline at end of file
index b7d0f2be5aa45994182b49eec67072a317b41892..11bbb71a04a3efdea40160626defb24404df0bf2 100644 (file)
@@ -7,14 +7,16 @@
  */
 package org.opendaylight.vpnservice.dhcpservice;
 
+import java.math.BigInteger;
+import java.util.List;
+
 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.vpnservice.dhcpservice.api.DHCPMConstants;
-import org.opendaylight.vpnservice.mdsalutil.*;
-import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 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.Node;
@@ -23,30 +25,27 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.List;
-
 public class NodeListener extends AbstractDataChangeListener<Node> implements AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(NodeListener.class);
 
-    private IMdsalApiManager mdsalManager;
     private ListenerRegistration<DataChangeListener> listenerRegistration;
     private final DataBroker broker;
     private DhcpManager dhcpManager;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
 
-    public NodeListener(final DataBroker db, final DhcpManager dhcpMgr) {
+    public NodeListener(final DataBroker db, final DhcpManager dhcpMgr, final DhcpExternalTunnelManager dhcpExternalTunnelManager) {
         super(Node.class);
         broker = db;
         dhcpManager = dhcpMgr;
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         registerListener(db);
     }
 
     private void registerListener(final DataBroker db) {
         try {
             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
-                    getWildCardPath(), NodeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+            getWildCardPath(), NodeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
         } catch (final Exception e) {
             LOG.error("NodeListener: DataChange listener registration fail!", e);
             throw new IllegalStateException("NodeListener: registration Listener failed.", e);
@@ -57,10 +56,12 @@ public class NodeListener extends AbstractDataChangeListener<Node> implements Au
         return InstanceIdentifier.create(Nodes.class).child(Node.class);
     }
 
-
     @Override
     protected void remove(InstanceIdentifier<Node> identifier, Node del) {
-
+        NodeId nodeId = del.getId();
+        BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeId);
+        List<BigInteger> listOfDpns = DhcpServiceUtils.getListOfDpns(broker);
+        dhcpExternalTunnelManager.handleDesignatedDpnDown(dpnId, listOfDpns);
     }
 
     @Override
@@ -72,8 +73,15 @@ public class NodeListener extends AbstractDataChangeListener<Node> implements Au
     protected void add(InstanceIdentifier<Node> identifier, Node add) {
         NodeId nodeId = add.getId();
         String[] node =  nodeId.getValue().split(":");
+        if(node.length < 2) {
+            LOG.warn("Unexpected nodeId {}", nodeId.getValue());
+            return;
+        }
         BigInteger dpId = new BigInteger(node[1]);
         dhcpManager.setupTableMissForDhcpTable(dpId);
+        dhcpExternalTunnelManager.installDhcpDropActionOnDpn(dpId);
+        List<BigInteger> listOfDpns = DhcpServiceUtils.getListOfDpns(broker);
+        dhcpExternalTunnelManager.handleDesignatedDpnDown(DHCPMConstants.INVALID_DPID, listOfDpns);
     }
 
     @Override
index 2fa746dce7abb10fa7790114cc113195af39aa74..01c99cf9bc62974653f70fc9cf32162448fc5484 100644 (file)
@@ -3,6 +3,7 @@ package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpser
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.vpnservice.dhcpservice.DhcpProvider;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
 
 public class DhcpServiceImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.impl.rev150710.AbstractDhcpServiceImplModule {
     public DhcpServiceImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
@@ -26,6 +27,8 @@ public class DhcpServiceImplModule extends org.opendaylight.yang.gen.v1.urn.open
         dhcpProvider.setMdsalManager(getMdsalutilDependency());
         dhcpProvider.setNeutronVpnManager(getNeutronvpnDependency());
         dhcpProvider.setInterfaceManagerRpc(rpcregistryDependency.getRpcService(OdlInterfaceRpcService.class));
+        dhcpProvider.setItmRpcService(rpcregistryDependency.getRpcService(ItmRpcService.class));
+        dhcpProvider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
         getBrokerDependency().registerProvider(dhcpProvider);
         return dhcpProvider;
     }
index 856b7716dc26a1244c8aa30f0618474184208ebc..9a05103f179bf69dcadd9f117ed6a3f5f43a858e 100644 (file)
@@ -7,6 +7,7 @@ module dhcpservice-impl {
     import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
     import odl-mdsalutil { prefix odl-mdsal; revision-date 2015-04-10;}
     import neutronvpn-api { prefix nvpn; revision-date 2015-08-12;}
+    import opendaylight-entity-ownership-service { prefix eos; revision-date 2015-08-10;}
 
     description
         "Service definition for dhcpservice project";
@@ -66,6 +67,15 @@ module dhcpservice-impl {
                     }
                 }
             }
+
+            container entity-ownership-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity eos:entity-ownership-service;
+                    }
+                }
+            }
         }
     }
 }
index d941dec97f63e27ac3c7c799a87635dca82d6fe0..dd16a42f41cc2eb774c2077faf66b35249f25457 100644 (file)
@@ -38,4 +38,9 @@ public class L2GatewayCacheUtils {
                 .getCache(L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME);
         return cachedMap.get(devicename);
     }
+
+    public static ConcurrentMap<String, L2GatewayDevice> getCache() {
+        return (ConcurrentMap<String, L2GatewayDevice>) CacheUtil
+                .getCache(L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME);
+    }
 }
diff --git a/neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/utils/NeutronUtils.java b/neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/utils/NeutronUtils.java
new file mode 100644 (file)
index 0000000..5b70621
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.neutronvpn.api.utils;
+
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.Segments;
+
+public class NeutronUtils {
+    public static final String VNIC_TYPE_NORMAL = "normal";
+
+    public static boolean isPortVnicTypeNormal(Port port) {
+        PortBindingExtension portBinding = port.getAugmentation(PortBindingExtension.class);
+        if(portBinding == null || portBinding.getVnicType() == null) {
+            // By default, VNIC_TYPE is NORMAL
+            return true;
+        }
+        String vnicType = portBinding.getVnicType().trim().toLowerCase();
+        return vnicType.equals(VNIC_TYPE_NORMAL);
+    }
+
+    public static String getSegmentationIdFromNeutronNetwork(Network network) {
+        String segmentationId = null;
+        NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+        if (providerExtension != null) {
+            segmentationId = providerExtension.getSegmentationId();
+            if (segmentationId == null) {
+                List<Segments> providerSegments = providerExtension.getSegments();
+                if (providerSegments != null && providerSegments.size() > 0) {
+                    for (Segments providerSegment: providerSegments) {
+                        if (isNetworkSegmentTypeVxlan(providerSegment)) {
+                            segmentationId = providerSegment.getSegmentationId();
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return segmentationId;
+    }
+
+    static boolean isNetworkSegmentTypeVxlan(Segments providerSegment) {
+        Class<? extends NetworkTypeBase> networkType = providerSegment.getNetworkType();
+        return (networkType != null && networkType.isAssignableFrom(NetworkTypeVxlan.class));
+    }
+}
index d432f45cfbc7a9eee99d1bf6e5335cd02d3bc910..7488a361d9e37da003a4e5c2e852004c3062d7d5 100644 (file)
@@ -15,13 +15,14 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataCh
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -98,7 +99,7 @@ public class NeutronNetworkChangeListener extends AbstractDataChangeListener<Net
 
     private void createElanInstance(Network input) {
         String elanInstanceName = input.getUuid().getValue();
-        String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(input);
+        String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(input);
         ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName);
         if (segmentationId != null) {
             elanInstanceBuilder.setVni(Long.valueOf(segmentationId));
index 826955dff5a553b5a27daeadb7030ea2c64aa9c7..0c81884525df302336b00518c658fbada65e7aba 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataCh
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
@@ -140,7 +141,7 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
     }
 
     private void handleNeutronPortCreated(Port port) {
-        if (!NeutronvpnUtils.isPortVnicTypeNormal(port)) {
+        if (!NeutronUtils.isPortVnicTypeNormal(port)) {
             LOG.info("Port {} is not a NORMAL VNIC Type port; OF Port interfaces are not created",
                     port.getUuid().getValue());
             return;
index 3acc5ce43b90c8ca480945b7110a2f34266a497d..d161f97dfdde3441ca4dd97e18128a7c795ee77c 100644 (file)
@@ -188,26 +188,6 @@ public class NeutronvpnUtils {
         return null;
     }
 
-    protected static String getSegmentationIdFromNeutronNetwork(Network network) {
-        String segmentationId = null;
-        NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
-        if (providerExtension != null) {
-            segmentationId = providerExtension.getSegmentationId();
-            if (segmentationId == null) {
-                List<Segments> providerSegments = providerExtension.getSegments();
-                if (providerSegments != null && providerSegments.size() > 0) {
-                    for (Segments providerSegment: providerSegments) {
-                        if (isNetworkSegmentTypeVxlan(providerSegment)) {
-                            segmentationId = providerSegment.getSegmentationId();
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-        return segmentationId;
-    }
-
     protected static List<Uuid> getNeutronRouterSubnetIds(DataBroker broker, Uuid routerId) {
         logger.info("getNeutronRouterSubnetIds for {}", routerId.getValue());
 
@@ -243,16 +223,6 @@ public class NeutronvpnUtils {
         return new StringBuilder().append("tap").append(tapId).toString();
     }
 
-    protected static boolean isPortVnicTypeNormal(Port port) {
-        PortBindingExtension portBinding = port.getAugmentation(PortBindingExtension.class);
-        if(portBinding == null || portBinding.getVnicType() == null) {
-            // By default, VNIC_TYPE is NORMAL
-            return true;
-        }
-        String vnicType = portBinding.getVnicType().trim().toLowerCase();
-        return vnicType.equals(VNIC_TYPE_NORMAL);
-    }
-
     protected static boolean lock(LockManagerService lockManager, String lockName) {
         TryLockInput input = new TryLockInputBuilder().setLockName(lockName).setTime(5L).setTimeUnit
                 (TimeUnits.Milliseconds).build();
@@ -365,9 +335,4 @@ public class NeutronvpnUtils {
 
         return result;
     }
-
-    static boolean isNetworkSegmentTypeVxlan(Segments providerSegment) {
-        Class<? extends NetworkTypeBase> networkType = providerSegment.getNetworkType();
-        return (networkType != null && networkType.isAssignableFrom(NetworkTypeVxlan.class));
-    }
 }