VpnPortIpToPort Listener for ELAN 85/44585/3
authoreceghkl <manu.b@ericsson.com>
Wed, 24 Aug 2016 05:31:30 +0000 (11:01 +0530)
committereceghkl <manu.b@ericsson.com>
Thu, 25 Aug 2016 06:45:58 +0000 (12:15 +0530)
* Listens to VpnPortIpToPortListener changes
* Add SMAC and DMAC flows
* Update ELAN operational DS

Change-Id: I70280b5b4e1560e9725015d54f2345401d66f432
Signed-off-by: eceghkl <manu.b@ericsson.com>
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanVpnPortIpToPortListener.java [new file with mode: 0644]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java
vpnservice/elanmanager/elanmanager-impl/src/main/resources/org/opendaylight/blueprint/elanmanager.xml

diff --git a/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanVpnPortIpToPortListener.java b/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanVpnPortIpToPortListener.java
new file mode 100644 (file)
index 0000000..25ed609
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * 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.netvirt.elan.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+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.data.LogicalDatastoreType;
+import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.netvirt.elan.utils.ElanConstants;
+import org.opendaylight.netvirt.elan.utils.ElanUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronVpnPortipPortData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanVpnPortIpToPortListener extends
+        AsyncDataTreeChangeListenerBase<VpnPortipToPort, ElanVpnPortIpToPortListener> {
+    private static final Logger logger = LoggerFactory.getLogger(ElanVpnPortIpToPortListener.class);
+    private final DataBroker broker;
+    private final IInterfaceManager interfaceManager;
+    private final ElanUtils elanUtils;
+
+    public ElanVpnPortIpToPortListener(DataBroker broker, IInterfaceManager interfaceManager, ElanUtils elanUtils) {
+        super(VpnPortipToPort.class, ElanVpnPortIpToPortListener.class);
+        this.broker = broker;
+        this.interfaceManager = interfaceManager;
+        this.elanUtils = elanUtils;
+    }
+
+    public void init() {
+        registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+    }
+
+    public void close() throws Exception {
+        super.close();
+        logger.debug("ElanVpnPortIpToPort Listener Closed");
+    }
+
+    @Override
+    protected InstanceIdentifier<VpnPortipToPort> getWildCardPath() {
+        return InstanceIdentifier.create(NeutronVpnPortipPortData.class).child(VpnPortipToPort.class);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<VpnPortipToPort> key, VpnPortipToPort dataObjectModification) {
+        String macAddress = dataObjectModification.getMacAddress();
+        String interfaceName = dataObjectModification.getPortName();
+        boolean isLearnt = dataObjectModification.isLearnt();
+        if (!isLearnt) {
+            logger.trace("Not learnt mac {}. Not performing action", macAddress);
+            return;
+        }
+        logger.trace("Removing mac address {} from interface {} ", macAddress, interfaceName);
+        DataStoreJobCoordinator.getInstance().enqueueJob(buildJobKey(macAddress, interfaceName),
+                new StaticMacRemoveWorker(macAddress, interfaceName));
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<VpnPortipToPort> key, VpnPortipToPort dataObjectModificationBefore,
+            VpnPortipToPort dataObjectModificationAfter) {
+        String oldMac = dataObjectModificationBefore.getMacAddress();
+        String oldInterfaceName = dataObjectModificationBefore.getPortName();
+        String newMac = dataObjectModificationAfter.getMacAddress();
+        String newInterfaceName = dataObjectModificationAfter.getPortName();
+        boolean isLearntOld = dataObjectModificationBefore.isLearnt();
+        boolean isLearntNew = dataObjectModificationAfter.isLearnt();
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        if (oldMac.equals(newMac) && oldInterfaceName.equals(newInterfaceName)) {
+            logger.trace("No change in Mac Address {} and InterfaceName {}. No actions performed", newMac,
+                    newInterfaceName);
+            return;
+        }
+        if (isLearntOld) {
+            logger.trace("Removing mac address {} from interface {} due to update event", oldMac, oldInterfaceName);
+            coordinator.enqueueJob(buildJobKey(oldMac, oldInterfaceName), new StaticMacRemoveWorker(oldMac,
+                    oldInterfaceName));
+        }
+        if (isLearntNew) {
+            logger.trace("Adding mac address {} to interface {} due to update event", newMac, newInterfaceName);
+            coordinator.enqueueJob(buildJobKey(newMac, newInterfaceName), new StaticMacAddWorker(newMac,
+                    newInterfaceName));
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<VpnPortipToPort> key, VpnPortipToPort dataObjectModification) {
+        String macAddress = dataObjectModification.getMacAddress();
+        String interfaceName = dataObjectModification.getPortName();
+        boolean isLearnt = dataObjectModification.isLearnt();
+        if (isLearnt) {
+            logger.trace("Adding mac address {} to interface {} ", macAddress, interfaceName);
+            DataStoreJobCoordinator.getInstance().enqueueJob(buildJobKey(macAddress, interfaceName),
+                    new StaticMacAddWorker(macAddress, interfaceName));
+        }
+    }
+
+    @Override
+    protected ElanVpnPortIpToPortListener getDataTreeChangeListener() {
+        return this;
+    }
+
+    private class StaticMacAddWorker implements Callable<List<ListenableFuture<Void>>> {
+        String macAddress, interfaceName;
+
+        public StaticMacAddWorker(String macAddress, String interfaceName) {
+            this.macAddress = macAddress;
+            this.interfaceName = interfaceName;
+        }
+
+        @Override
+        public List<ListenableFuture<Void>> call() throws Exception {
+            List<ListenableFuture<Void>> futures = new ArrayList<>();
+            WriteTransaction flowWritetx = broker.newWriteOnlyTransaction();
+            WriteTransaction tx = broker.newWriteOnlyTransaction();
+            ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
+            if (elanInterface == null) {
+                logger.debug("ElanInterface Not present for interfaceName {} for add event", interfaceName);
+                return futures;
+            }
+            elanUtils.addMacEntryToDsAndSetupFlows(interfaceManager, interfaceName, macAddress, elanInterface.getElanInstanceName(), tx,
+                    flowWritetx, ElanConstants.STATIC_MAC_TIMEOUT);
+            futures.add(tx.submit());
+            futures.add(flowWritetx.submit());
+            return futures;
+        }
+    }
+
+    private class StaticMacRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
+        String macAddress, interfaceName;
+
+        public StaticMacRemoveWorker(String macAddress, String interfaceName) {
+            this.macAddress = macAddress;
+            this.interfaceName = interfaceName;
+        }
+
+        @Override
+        public List<ListenableFuture<Void>> call() throws Exception {
+            List<ListenableFuture<Void>> futures = new ArrayList<>();
+            WriteTransaction deleteFlowTx = broker.newWriteOnlyTransaction();
+            WriteTransaction tx = broker.newWriteOnlyTransaction();
+            ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
+            if (elanInterface == null) {
+                logger.debug("ElanInterface Not present for interfaceName {} for delete event", interfaceName);
+                return futures;
+            }
+            elanUtils.deleteMacEntryFromDsAndRemoveFlows(interfaceManager, interfaceName, macAddress,
+                    elanInterface.getElanInstanceName(), tx, deleteFlowTx);
+            futures.add(tx.submit());
+            futures.add(deleteFlowTx.submit());
+            return futures;
+        }
+    }
+
+    private String buildJobKey(String mac, String interfaceName) {
+        return "ENTERPRISEMACJOB"+ mac + interfaceName;
+    }
+
+
+}
index 80015812dfaf620a3a40d95c1e207e4fff8c919d..e68fd672620c732dbba7113b50b755dbd141cf6c 100644 (file)
@@ -7,11 +7,6 @@
  */
 package org.opendaylight.netvirt.elan.utils;
 
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -20,6 +15,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+
 import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
@@ -30,6 +26,7 @@ import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceServiceUtil;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.itm.globals.ITMConstants;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
@@ -143,6 +140,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -151,6 +149,12 @@ 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.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
 public class ElanUtils {
 
     private static final Logger LOG = LoggerFactory.getLogger(ElanUtils.class);
@@ -2094,4 +2098,40 @@ public class ElanUtils {
         }
         return false;
     }
+
+    /**
+     * Add Mac Address to ElanInterfaceForwardingEntries and ElanForwardingTables
+     * Install SMAC and DMAC flows
+     */
+    public void addMacEntryToDsAndSetupFlows(IInterfaceManager interfaceManager, String interfaceName, String macAddress, String elanName, WriteTransaction tx, WriteTransaction flowWritetx, int macTimeOut) {
+        LOG.trace("Adding mac address {} and interface name {} to ElanInterfaceForwardingEntries and ElanForwardingTables DS", macAddress, interfaceName);
+        BigInteger timeStamp = new BigInteger(String.valueOf((long)System.currentTimeMillis()));
+        PhysAddress physAddress = new PhysAddress(macAddress);
+        MacEntry macEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress).setKey(new MacEntryKey(physAddress)).setControllerLearnedForwardingEntryTimestamp(timeStamp).setIsStaticAddress(false).build();
+        InstanceIdentifier<MacEntry> macEntryId = ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
+        tx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, macEntry);
+        InstanceIdentifier<MacEntry> elanMacEntryId = ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
+        tx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry);
+        ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanName);
+        setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut, macAddress, flowWritetx);
+    }
+
+    /**
+     * Remove Mac Address from ElanInterfaceForwardingEntries and ElanForwardingTables
+     * Remove SMAC and DMAC flows
+     */
+    public void deleteMacEntryFromDsAndRemoveFlows(IInterfaceManager interfaceManager, String interfaceName, String macAddress, String elanName, WriteTransaction tx, WriteTransaction deleteFlowTx) {
+        LOG.trace("Deleting mac address {} and interface name {} from ElanInterfaceForwardingEntries and ElanForwardingTables DS", macAddress, interfaceName);
+        PhysAddress physAddress = new PhysAddress(macAddress);
+        MacEntry macEntry = getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress);
+        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+        if(macEntry != null && interfaceInfo != null) {
+            deleteMacFlows(ElanUtils.getElanInstanceByName(broker, elanName), interfaceInfo, macEntry, deleteFlowTx);
+        }
+        InstanceIdentifier<MacEntry> macEntryIdForElanInterface =  ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
+        InstanceIdentifier<MacEntry> macEntryIdForElanInstance  =  ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
+        tx.delete(LogicalDatastoreType.OPERATIONAL, macEntryIdForElanInterface);
+        tx.delete(LogicalDatastoreType.OPERATIONAL, macEntryIdForElanInstance);
+    }
+
 }
index ecac275fbd4942e2e980d898c357488f9029279b..bd4f8f79de51baa0513bd8e7378736df69fc2656 100644 (file)
     <argument ref="elanUtils" />
   </bean>
 
+  <bean id="elanVpnPortIpToPortListener"
+    class="org.opendaylight.netvirt.elan.internal.ElanVpnPortIpToPortListener"
+    init-method="init" destroy-method="close">
+    <argument ref="dataBroker" />
+    <argument ref="interfaceManager" />
+    <argument ref="elanUtils" />
+  </bean>
+
   <bean id="elanService" class="org.opendaylight.netvirt.elan.internal.ElanServiceProvider"
     init-method="init">
     <argument ref="idManagerService" />