Support update/delete operations for provider networks 44/41944/21
authorTali <tali.ben-meir@hpe.com>
Mon, 18 Jul 2016 04:44:09 +0000 (07:44 +0300)
committerSam Hague <shague@redhat.com>
Sat, 30 Jul 2016 19:42:19 +0000 (19:42 +0000)
Add external ports to remote BC group buckets

Depends on genius commit https://git.opendaylight.org/gerrit/#/c/41943/

Change-Id: Ibf7c73cec88f6cf629815ab57bb657bcb336a955
Signed-off-by: Tali <tali.ben-meir@hpe.com>
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elanmanager/api/IElanService.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanOvsdbNodeListener.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanServiceProvider.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronNetworkChangeListener.java

index 7325efdd610014a5cb6f807f8538b0bbfed80035..c8f258a2e7594f574ef29f108fffa1de565dc2cd 100644 (file)
@@ -39,4 +39,10 @@ public interface IElanService {
 
     void createExternalElanNetworks(Node node);
 
+    void updateExternalElanNetworks(Node origNode, Node updatedNode);
+
+    void deleteExternalElanNetwork(ElanInstance elanInstance);
+
+    void deleteExternalElanNetworks(Node node);
+
 }
index 3192c241a5d2d036347172b3b4c7eed518a9ee14..85129175a16329e2e8edca05924e2801f731e918 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.netvirt.elan.internal;
 
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -586,7 +587,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             } catch (InterruptedException e1) {
                 logger.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
             }
-            setupElanBroadcastGroups(elanInfo, dpId);
+            setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
             try {
                 Thread.sleep(waitTimeForSyncInstall);
             } catch (InterruptedException e1) {
@@ -625,57 +626,78 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
 
     private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo,
                                                      int bucketKeyStart, InterfaceInfo interfaceInfo) {
-        BigInteger dpnId = interfaceInfo.getDpId();
-        int elanTag = elanInfo.getElanTag().intValue();
-        int bucketId = bucketKeyStart;
-        List<Bucket> listBuckets = new ArrayList<Bucket>();
-        ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
-        if (elanDpns != null) {
-            List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
-            for(DpnInterfaces dpnInterface : dpnInterfaceses) {
-                if (ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
-                    try {
-                        List<Action> listAction = ElanUtils.getInternalItmEgressAction(dpnId, dpnInterface.getDpId(), elanTag);
-                        listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-                        bucketId++;
-                    } catch (Exception ex) {
-                        logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnId, dpnInterface.getDpId() );
-                    }
-                }
-            }
-            List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
-            listBuckets.addAll(elanL2GwDevicesBuckets);
-        }
-        return listBuckets;
+        return getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(), bucketKeyStart);
     }
 
-    private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, BigInteger dpnId, int bucketId) {
+    private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
         int elanTag = elanInfo.getElanTag().intValue();
         List<Bucket> listBucketInfo = new ArrayList<Bucket>();
         ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
+        listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId, elanTag));
+        listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId, bucketId));
+        listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId));
+        return listBucketInfo;
+    }
+
+    private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
+            int elanTag) {
+        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
         if (elanDpns != null) {
-            List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
-            for(DpnInterfaces dpnInterface : dpnInterfaceses) {
-                if (ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
+            for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
+                if (ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId
+                        && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
                     try {
-                        List<Action> listActionInfo = ElanUtils.getInternalItmEgressAction(dpnId, dpnInterface.getDpId(), elanTag);
+                        List<Action> listActionInfo = ElanUtils.getInternalTunnelItmEgressAction(dpnId,
+                                dpnInterface.getDpId(), elanTag);
                         if (listActionInfo.isEmpty()) {
                             continue;
                         }
-                        listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, 0, bucketId, 0xffffffffL, 0xffffffffL));
+                        listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
+                                MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
                         bucketId++;
                     } catch (Exception ex) {
-                        logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnId, dpnInterface.getDpId() );
+                        logger.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
+                                dpnId, dpnInterface.getDpId());
                     }
                 }
             }
+        }
+        return listBucketInfo;
+    }
+
+    private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns, DpnInterfaces dpnInterfaces, BigInteger dpnId,
+            int bucketId) {
+        DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
+        if (currDpnInterfaces == null || !ElanUtils.isDpnPresent(currDpnInterfaces.getDpId())
+                || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
+            return Collections.emptyList();
+        }
 
-            List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
-            listBucketInfo.addAll(elanL2GwDevicesBuckets);
+        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
+        for (String interfaceName : currDpnInterfaces.getInterfaces()) {
+            if (ElanUtils.isExternal(interfaceName)) {
+                List<Action> listActionInfo = ElanUtils.getExternalPortItmEgressAction(interfaceName);
+                if (!listActionInfo.isEmpty()) {
+                    listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
+                            MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+                    bucketId++;
+                }
+            }
         }
         return listBucketInfo;
     }
 
+    private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
+        if (elanDpns != null) {
+            for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
+                if (dpnInterface.getDpId() == dpnId) {
+                    return dpnInterface;
+                }
+            }
+        }
+        return null;
+    }
+
     private void setElanBCGrouponOtherDpns(ElanInstance elanInfo,
                                            BigInteger dpId, WriteTransaction tx) {
         int elanTag = elanInfo.getElanTag().intValue();
@@ -698,9 +720,11 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                         if (ElanUtils.isDpnPresent(otherFes.getDpId()) && otherFes.getDpId() != dpnInterface.getDpId()
                             && otherFes.getInterfaces() != null && ! otherFes.getInterfaces().isEmpty()) {
                             try {
-                                List<Action> remoteListActionInfo = ElanUtils.getInternalItmEgressAction(dpnInterface.getDpId(), otherFes.getDpId(), elanTag);
-                                remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,MDSALUtil.WATCH_GROUP));
-                                bucketId++;
+                                List<Action> remoteListActionInfo = ElanUtils.getInternalTunnelItmEgressAction(dpnInterface.getDpId(), otherFes.getDpId(), elanTag);
+                                if (!remoteListActionInfo.isEmpty()) {
+                                    remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,MDSALUtil.WATCH_GROUP));
+                                    bucketId++;
+                                }
                             } catch (Exception ex) {
                                 logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnInterface.getDpId(), otherFes.getDpId() );
                                 return;
@@ -803,6 +827,10 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
+        setupElanBroadcastGroups(elanInfo, null, dpnId);
+    }
+
+    public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
         List<Bucket> listBucket = new ArrayList<Bucket>();
         int bucketId = 0;
         int actionKey = 0;
@@ -812,7 +840,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         listAction.add((new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}, ++actionKey)).buildAction());
         listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
         bucketId++;
-        List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnId, bucketId);
+        List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId);
         listBucket.addAll(listBucketInfoRemote);
         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
         logger.trace("Installing the remote BroadCast Group:{}", group);
@@ -837,8 +865,11 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 continue;
             }
 
-            listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-            bucketId++;
+            if (!ElanUtils.isExternal(ifName)) {
+                listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
+                        MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+                bucketId++;
+            }
         }
 
         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
@@ -936,7 +967,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
 
         elanServiceProvider.getMdsalManager().addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
 
-        // only if ELAN can connect to external netowrk, perform the following
+        // only if ELAN can connect to external network, perform the following
         if (ElanUtils.isVxlan(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
             Flow flowEntity2 = MDSALUtil.buildFlowNew(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, getUnknownDmacFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag, /*SH flag*/true),
                 5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), getMatchesForElanTag(elanTag, /*SH flag*/true),
@@ -1238,7 +1269,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             if (interfaceName == null) {
                 continue;
             }
-            List<Action> listActionInfo = ElanUtils.buildItmEgressActions(interfaceName, elanInfo.getSegmentationId());
+            List<Action> listActionInfo = ElanUtils.buildTunnelItmEgressActions(interfaceName, elanInfo.getSegmentationId());
             listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
                 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
             bucketId++;
index 1d2cfc965839224566cefd9b1ba97e8de3ec7d5a..e8d9e1435d6f8d7dbaf51e402729b3c4e4e374a2 100644 (file)
@@ -66,13 +66,15 @@ public class ElanOvsdbNodeListener extends AbstractDataChangeListener<Node> {
     }
 
     @Override
-    protected void remove(InstanceIdentifier<Node> identifier, Node del) {
+    protected void remove(InstanceIdentifier<Node> identifier, Node node) {
+        elanProvider.deleteExternalElanNetworks(node);
     }
 
     @Override
     protected void update(InstanceIdentifier<Node> identifier, Node original, Node update) {
         logger.debug("ElanOvsdbNodeListener.update, updated node detected. original: {} new: {}", original, update);
         doNodeUpdate(update);
+        elanProvider.updateExternalElanNetworks(original, update);
     }
 
     @Override
@@ -85,5 +87,4 @@ public class ElanOvsdbNodeListener extends AbstractDataChangeListener<Node> {
     private void doNodeUpdate(Node node) {
         bridgeMgr.processNodePrep(node, generateIntBridgeMac);
     }
-
 }
index 2ade9083a029f3d9ee90dfa5b7a9dc19b377686c..9c7370707c0396a9d046ae50c294ae3470b88273 100644 (file)
@@ -10,8 +10,11 @@ package org.opendaylight.netvirt.elan.internal;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.Future;
+import java.util.function.BiFunction;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
@@ -36,6 +39,9 @@ import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.itm.api.IITMProvider;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+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.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.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
@@ -569,7 +575,57 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
 
     @Override
     public void createExternalElanNetworks(Node node) {
-        if (!bridgeMgr.isIntegrationBridge(node)) {
+        handleExternalElanNetworks(node, new BiFunction<ElanInstance, String, Void>() {
+
+            @Override
+            public Void apply(ElanInstance elanInstance, String interfaceName) {
+                createExternalElanNetwork(elanInstance, interfaceName);
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public void createExternalElanNetwork(ElanInstance elanInstance) {
+        handleExternalElanNetwork(elanInstance, new BiFunction<ElanInstance, String, Void>() {
+
+            @Override
+            public Void apply(ElanInstance elanInstance, String interfaceName) {
+                createExternalElanNetwork(elanInstance, interfaceName);
+                return null;
+            }
+
+        });
+    }
+
+    @Override
+    public void deleteExternalElanNetworks(Node node) {
+        handleExternalElanNetworks(node, new BiFunction<ElanInstance, String, Void>() {
+
+            @Override
+            public Void apply(ElanInstance elanInstance, String interfaceName) {
+                deleteExternalElanNetwork(elanInstance, interfaceName);
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public void deleteExternalElanNetwork(ElanInstance elanInstance) {
+        handleExternalElanNetwork(elanInstance, new BiFunction<ElanInstance, String, Void>() {
+
+            @Override
+            public Void apply(ElanInstance elanInstance, String interfaceName) {
+                deleteExternalElanNetwork(elanInstance, interfaceName);
+                return null;
+            }
+
+        });
+    }
+
+    @Override
+    public void updateExternalElanNetworks(Node origNode, Node updatedNode) {
+        if (!bridgeMgr.isIntegrationBridge(updatedNode)) {
             return;
         }
 
@@ -579,42 +635,58 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
             return;
         }
 
+        Optional<Map<String, String>> origProviderMapOpt = bridgeMgr.getOpenvswitchOtherConfigMap(origNode,
+                ElanBridgeManager.PROVIDER_MAPPINGS_KEY);
+        Optional<Map<String, String>> updatedProviderMapOpt = bridgeMgr.getOpenvswitchOtherConfigMap(updatedNode,
+                ElanBridgeManager.PROVIDER_MAPPINGS_KEY);
+        Map<String, String> origProviderMappping = origProviderMapOpt.or(Collections.emptyMap());
+        Map<String, String> updatedProviderMappping = updatedProviderMapOpt.or(Collections.emptyMap());
+
         for (ElanInstance elanInstance : elanInstances) {
-            String interfaceName = getExtInterfaceName(node, elanInstance.getPhysicalNetworkName());
-            createExternalElanNetwork(elanInstance, node, interfaceName);
+            String physicalNetworkName = elanInstance.getPhysicalNetworkName();
+            if (physicalNetworkName != null) {
+                String origPortName = origProviderMappping.get(physicalNetworkName);
+                String updatedPortName = updatedProviderMappping.get(physicalNetworkName);
+                if (origPortName != null && !origPortName.equals(updatedPortName)) {
+                    deleteExternalElanNetwork(elanInstance, getExtInterfaceName(origNode, physicalNetworkName));
+                }
+                if (updatedPortName != null && !updatedPortName.equals(origPortName)) {
+                    createExternalElanNetwork(elanInstance, getExtInterfaceName(updatedNode, updatedPortName));
+                }
+            }
         }
     }
 
-    @Override
-    public void createExternalElanNetwork(ElanInstance elanInstance) {
-        if (elanInstance.getPhysicalNetworkName() == null) {
-            logger.trace("No physical network attached to {}", elanInstance.getElanInstanceName());
+    private void createExternalElanNetwork(ElanInstance elanInstance, String interfaceName) {
+        if (interfaceName == null) {
+            logger.trace("No physial interface is attached to {}", elanInstance.getPhysicalNetworkName());
             return;
         }
 
-        List<Node> nodes = bridgeMgr.southboundUtils.getOvsdbNodes();
-        if (nodes == null || nodes.isEmpty()) {
-            logger.trace("No OVS nodes found while creating external network for ELAN {}",
-                    elanInstance.getElanInstanceName());
+        String elanInterfaceName = createIetfInterfaces(elanInstance, interfaceName);
+        addElanInterface(elanInstance.getElanInstanceName(), elanInterfaceName, null, null);
+    }
+
+    private void deleteExternalElanNetwork(ElanInstance elanInstance, String interfaceName) {
+        if (interfaceName == null) {
+            logger.trace("No physial interface is attached to {}", elanInstance.getPhysicalNetworkName());
             return;
         }
 
-        for (Node node : nodes) {
-            if (bridgeMgr.isIntegrationBridge(node)) {
-                String interfaceName = getExtInterfaceName(node, elanInstance.getPhysicalNetworkName());
-                createExternalElanNetwork(elanInstance, node, interfaceName);
-            }
+        String elanInstanceName = elanInstance.getElanInstanceName();
+        List<String> elanInterfaces = getElanInterfaces(elanInstanceName);
+        if (elanInterfaces == null || elanInterfaces.isEmpty()) {
+            logger.trace("No ELAN interfaces defined for {}", elanInstanceName);
+            return;
         }
-    }
 
-    private void createExternalElanNetwork(ElanInstance elanInstance, Node node, String interfaceName) {
-        if (interfaceName == null) {
-            logger.trace("No physial interface is attached to {} node {}", elanInstance.getPhysicalNetworkName(),
-                    node.getNodeId().getValue());
+        for (String elanInterface : elanInterfaces) {
+            if (ElanUtils.isExternal(elanInterface) && elanInterface.startsWith(interfaceName)) {
+                deleteIetfInterface(elanInterface);
+                deleteElanInterface(elanInstanceName, elanInterface);
+                return;
+            }
         }
-
-        String elanInterfaceName = createIetfInterfaces(elanInstance, interfaceName);
-        addElanInterface(elanInstance.getElanInstanceName(), elanInterfaceName, null, null);
     }
 
     /**
@@ -640,15 +712,15 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
             if (ElanUtils.isFlat(elanInstance)) {
                 interfaceName = parentRef + IfmConstants.OF_URI_PREFIX + "flat";
                 interfaceManager.createVLANInterface(interfaceName, parentRef, null, null, null,
-                        IfL2vlan.L2vlanMode.Transparent);
+                        IfL2vlan.L2vlanMode.Transparent, true);
             } else if (ElanUtils.isVlan(elanInstance)) {
                 String trunkName = parentRef + IfmConstants.OF_URI_PREFIX + "trunk";
                 interfaceManager.createVLANInterface(interfaceName, parentRef, null, null, null,
-                        IfL2vlan.L2vlanMode.Trunk);
+                        IfL2vlan.L2vlanMode.Trunk, true);
                 Long segmentationId = elanInstance.getSegmentationId();
                 interfaceName = parentRef + IfmConstants.OF_URI_PREFIX + segmentationId;
                 interfaceManager.createVLANInterface(interfaceName, trunkName, null, segmentationId.intValue(), null,
-                        IfL2vlan.L2vlanMode.TrunkMember);
+                        IfL2vlan.L2vlanMode.TrunkMember, true);
             }
         } catch (InterfaceAlreadyExistsException e) {
             logger.trace("Interface {} was already created", interfaceName);
@@ -657,6 +729,14 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         return interfaceName;
     }
 
+    private void deleteIetfInterface(String interfaceName) {
+        InterfaceKey interfaceKey = new InterfaceKey(interfaceName);
+        InstanceIdentifier<Interface> interfaceInstanceIdentifier = InstanceIdentifier
+                .builder(Interfaces.class).child(Interface.class, interfaceKey).build();
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, interfaceInstanceIdentifier);
+        logger.debug("Deleting IETF interface {}", interfaceName);
+    }
+
     private String getExtInterfaceName(Node node, String physicalNetworkName) {
         if (physicalNetworkName == null) {
             return null;
@@ -673,4 +753,45 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
                 + bridgeMgr.getIntBridgePortNameFor(node, providerMappingValue);
     }
 
+    private void handleExternalElanNetworks(Node node, BiFunction<ElanInstance, String, Void> function) {
+        if (!bridgeMgr.isIntegrationBridge(node)) {
+            return;
+        }
+
+        List<ElanInstance> elanInstances = getElanInstances();
+        if (elanInstances == null || elanInstances.isEmpty()) {
+            logger.trace("No ELAN instances found");
+            return;
+        }
+
+        for (ElanInstance elanInstance : elanInstances) {
+            String interfaceName = getExtInterfaceName(node, elanInstance.getPhysicalNetworkName());
+            if (interfaceName != null) {
+                function.apply(elanInstance, interfaceName);
+            }
+        }
+    }
+
+    private void handleExternalElanNetwork(ElanInstance elanInstance, BiFunction<ElanInstance, String, Void> function) {
+        String elanInstanceName = elanInstance.getElanInstanceName();
+        if (elanInstance.getPhysicalNetworkName() == null) {
+            logger.trace("No physical network attached to {}", elanInstanceName);
+            return;
+        }
+
+        List<Node> nodes = bridgeMgr.southboundUtils.getOvsdbNodes();
+        if (nodes == null || nodes.isEmpty()) {
+            logger.trace("No OVS nodes found while creating external network for ELAN {}",
+                    elanInstance.getElanInstanceName());
+            return;
+        }
+
+        for (Node node : nodes) {
+            if (bridgeMgr.isIntegrationBridge(node)) {
+                String interfaceName = getExtInterfaceName(node, elanInstance.getPhysicalNetworkName());
+                function.apply(elanInstance, interfaceName);
+            }
+        }
+    }
+
 }
index 58330ebc2c69f42829e5695050eb2349bf2c1d81..6ab9de86cabb8102318a21376ae027544ec7c65f 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.netvirt.elan.internal.ElanServiceProvider;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
+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.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
@@ -93,6 +94,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.IfIndexesInterfaceMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
@@ -893,7 +895,7 @@ public class ElanUtils {
 
         //List of Action for the provided Source and Destination DPIDs
         try {
-            List<Action> actions = getInternalItmEgressAction(srcDpId, destDpId, lportTag);
+            List<Action> actions = getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTag);
             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
         } catch (Exception e) {
             logger.error("Interface Not Found exception");
@@ -1074,26 +1076,42 @@ public class ElanUtils {
      *            the tunnel key
      * @return the list
      */
-    public static List<Action> buildItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
-        List<Action> result = Collections.emptyList();
+    public static List<Action> buildTunnelItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
         if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
-            GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
-                .setIntfName(tunnelIfaceName).setTunnelKey(tunnelKey).build();
-
-            Future<RpcResult<GetEgressActionsForInterfaceOutput>> egressActionsOutputFuture =
-                elanServiceProvider.getInterfaceManagerRpcService().getEgressActionsForInterface(getEgressActInput);
-            try {
-                if (egressActionsOutputFuture.get().isSuccessful()) {
-                    GetEgressActionsForInterfaceOutput egressActionsOutput = egressActionsOutputFuture.get().getResult();
-                    result = egressActionsOutput.getAction();
-                }
-            } catch (InterruptedException | ExecutionException e) {
-                logger.error("Error in RPC call getEgressActionsForInterface {}", e);
+            return buildItmEgressActions(tunnelIfaceName, tunnelKey);
+        }
+
+        return Collections.emptyList();
+    }
+
+    /**
+     * Builds the list of actions to be taken when sending the packet over external
+     * port such as tunnel, physical port etc.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @param tunnelKey
+     *            can be VNI for VxLAN tunnel interfaces, Gre Key for GRE tunnels, etc.
+     * @return the list
+     */
+    public static List<Action> buildItmEgressActions(String interfaceName, Long tunnelKey) {
+        List<Action> result = Collections.emptyList();
+        GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
+                .setIntfName(interfaceName).setTunnelKey(tunnelKey).build();
+
+        Future<RpcResult<GetEgressActionsForInterfaceOutput>> egressActionsOutputFuture = elanServiceProvider
+                .getInterfaceManagerRpcService().getEgressActionsForInterface(getEgressActInput);
+        try {
+            if (egressActionsOutputFuture.get().isSuccessful()) {
+                GetEgressActionsForInterfaceOutput egressActionsOutput = egressActionsOutputFuture.get().getResult();
+                result = egressActionsOutput.getAction();
             }
+        } catch (InterruptedException | ExecutionException e) {
+            logger.error("Error in RPC call getEgressActionsForInterface {}", e);
         }
 
         if ( result == null || result.size() == 0 ) {
-            logger.warn("Could not build Egress actions for interface {} and tunnelId {}", tunnelIfaceName, tunnelKey);
+            logger.warn("Could not build Egress actions for interface {} and tunnelId {}", interfaceName, tunnelKey);
         }
         return result;
     }
@@ -1112,7 +1130,7 @@ public class ElanUtils {
      *            Vni to be stamped on the VxLAN Header.
      * @return the external itm egress action
      */
-    public static List<Action> getExternalItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni ) {
+    public static List<Action> getExternalTunnelItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni ) {
         List<Action> result = Collections.emptyList();
 
         GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
@@ -1126,7 +1144,7 @@ public class ElanUtils {
                 if ( logger.isDebugEnabled() )
                     logger.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
 
-                result = buildItmEgressActions(tunnelIfaceName, vni);
+                result = buildTunnelItmEgressActions(tunnelIfaceName, vni);
             }
 
         } catch (InterruptedException | ExecutionException e) {
@@ -1151,7 +1169,7 @@ public class ElanUtils {
      *            serviceId to be sent on the VxLAN header.
      * @return the internal itm egress action
      */
-    public static List<Action> getInternalItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId,
+    public static List<Action> getInternalTunnelItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId,
                                                           long serviceTag) {
         List<Action> result = Collections.emptyList();
 
@@ -1167,7 +1185,7 @@ public class ElanUtils {
                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
                 logger.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
 
-                result = buildItmEgressActions(tunnelIfaceName, serviceTag);
+                result = buildTunnelItmEgressActions(tunnelIfaceName, serviceTag);
             }
         } catch (InterruptedException | ExecutionException e) {
             logger.error("Error in RPC call getTunnelInterfaceName {}", e);
@@ -1176,6 +1194,18 @@ public class ElanUtils {
         return result;
     }
 
+    /**
+     * Build the list of actions to be taken when sending the packet to
+     * external (physical) port
+     *
+     * @param interfaceName
+     *            Interface name
+     * @return the external port itm egress actions
+     */
+    public static List<Action> getExternalPortItmEgressAction(String interfaceName) {
+        return buildItmEgressActions(interfaceName, null);
+    }
+
     public static List<MatchInfo> getTunnelMatchesForServiceId(int elanTag) {
         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
         // Matching metadata
@@ -1370,7 +1400,7 @@ public class ElanUtils {
         List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /*shFlag*/ false, dstMacAddress);
         List<Instruction> mkInstructions = new ArrayList<Instruction>();
         try {
-            List<Action> actions = getExternalItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni);
+            List<Action> actions = getExternalTunnelItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni);
             mkInstructions.add( MDSALUtil.buildApplyActionsInstruction(actions) );
         } catch (Exception e) {
             logger.error("Could not get Egress Actions for DpId={}  externalNode={}", dpId, extDeviceNodeId );
@@ -1445,7 +1475,7 @@ public class ElanUtils {
 
         try {
             //List of Action for the provided Source and Destination DPIDs
-            List<Action> actions = getInternalItmEgressAction(localDpId, remoteDpId, lportTag);
+            List<Action> actions = getInternalTunnelItmEgressAction(localDpId, remoteDpId, lportTag);
             mkInstructions.add( MDSALUtil.buildApplyActionsInstruction(actions) );
         } catch (Exception e) {
             logger.error("Could not get Egress Actions for localDpId={}  remoteDpId={}   lportTag={}",
@@ -1590,6 +1620,27 @@ public class ElanUtils {
         return null;
     }
 
+    /**
+     * Gets the interface from config ds.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @param dataBroker
+     *            the data broker
+     * @return the interface from config ds
+     */
+    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface getInterfaceFromConfigDS(
+        String interfaceName, DataBroker dataBroker) {
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> ifaceId = createInterfaceInstanceIdentifier(
+            interfaceName);
+        Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> iface = MDSALUtil
+            .read(dataBroker, LogicalDatastoreType.CONFIGURATION, ifaceId);
+        if (iface.isPresent()) {
+            return iface.get();
+        }
+        return null;
+    }
+
     /**
      * Creates the interface state instance identifier.
      *
@@ -1607,6 +1658,23 @@ public class ElanUtils {
         return idBuilder.build();
     }
 
+    /**
+     * Creates the interface instance identifier.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @return the instance identifier
+     */
+    public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> createInterfaceInstanceIdentifier(
+        String interfaceName) {
+        InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> idBuilder = InstanceIdentifier
+            .builder(Interfaces.class)
+            .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface.class,
+                new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey(
+                    interfaceName));
+        return idBuilder.build();
+    }
+
     public static void waitForTransactionToComplete(WriteTransaction tx) {
         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
         try {
@@ -1632,5 +1700,19 @@ public class ElanUtils {
         return elanInstance != null && elanInstance.getSegmentType() != null
                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class);
     }
+
+    public static boolean isExternal(String interfaceName) {
+        return isExternal(getInterfaceFromConfigDS(interfaceName, elanServiceProvider.getBroker()));
+    }
+
+    public static boolean isExternal(
+            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface) {
+        if (iface == null) {
+            return false;
+        }
+
+        IfExternal ifExternal = iface.getAugmentation(IfExternal.class);
+        return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());
+    }
 }
 
index ac0d853df726e64b6139953ee55c5050c54fe621..88f240afa40f79a2d6b5aa80027c252cf9f2a7e0 100644 (file)
@@ -9,6 +9,8 @@
 package org.opendaylight.netvirt.neutronvpn;
 
 
+import java.util.Objects;
+
 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;
@@ -108,13 +110,15 @@ public class NeutronNetworkChangeListener extends AbstractDataChangeListener<Net
         }
         //Delete ELAN instance for this network
         String elanInstanceName = input.getUuid().getValue();
-        deleteElanInstance(elanInstanceName);
+        ElanInstance elanInstance = NeutronvpnServiceAccessor.getElanProvider().getElanInstance(elanInstanceName);
+        if (elanInstance != null) {
+            NeutronvpnServiceAccessor.getElanProvider().deleteExternalElanNetwork(elanInstance);
+            deleteElanInstance(elanInstanceName);
+        }
         if (input.getAugmentation(NetworkL3Extension.class).isExternal()) {
             nvpnNatManager.removeExternalNetwork(input);
             NeutronvpnUtils.removeFromNetworkCache(input);
         }
-
-        // TODO: delete elan-interfaces for physnet port
     }
 
     @Override
@@ -123,6 +127,26 @@ public class NeutronNetworkChangeListener extends AbstractDataChangeListener<Net
             LOG.trace("Updating Network : key: " + identifier + ", original value=" + original + ", update value=" +
                     update);
         }
+
+        String elanInstanceName = original.getUuid().getValue();
+        Class<? extends SegmentTypeBase> origSegmentType = NeutronvpnUtils.getSegmentTypeFromNeutronNetwork(original);
+        String origSegmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(original);
+        String origPhysicalNetwork = NeutronvpnUtils.getPhysicalNetworkName(original);
+        Class<? extends SegmentTypeBase> updateSegmentType = NeutronvpnUtils.getSegmentTypeFromNeutronNetwork(update);
+        String updateSegmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(update);
+        String updatePhysicalNetwork = NeutronvpnUtils.getPhysicalNetworkName(update);
+
+        if (!Objects.equals(origSegmentType, updateSegmentType)
+                || !Objects.equals(origSegmentationId, updateSegmentationId)
+                || !Objects.equals(origPhysicalNetwork, updatePhysicalNetwork)) {
+            ElanInstance elanInstance = NeutronvpnServiceAccessor.getElanProvider().getElanInstance(elanInstanceName);
+            if (elanInstance != null) {
+                NeutronvpnServiceAccessor.getElanProvider().deleteExternalElanNetwork(elanInstance);
+                elanInstance = updateElanInstance(elanInstanceName, updateSegmentType, updateSegmentationId,
+                        updatePhysicalNetwork);
+                NeutronvpnServiceAccessor.getElanProvider().createExternalElanNetwork(elanInstance);
+            }
+        }
     }
 
     private ElanInstance createElanInstance(Network input) {
@@ -130,6 +154,33 @@ public class NeutronNetworkChangeListener extends AbstractDataChangeListener<Net
         Class<? extends SegmentTypeBase> segmentType = NeutronvpnUtils.getSegmentTypeFromNeutronNetwork(input);
         String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(input);
         String physicalNetworkName = NeutronvpnUtils.getPhysicalNetworkName(input);
+        ElanInstance elanInstance = createElanInstance(elanInstanceName, segmentType, segmentationId, physicalNetworkName);
+        InstanceIdentifier<ElanInstance> id = createElanInstanceIdentifier(elanInstanceName);
+        MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, id, elanInstance);
+        return elanInstance;
+    }
+
+    private void deleteElanInstance(String elanInstanceName) {
+        InstanceIdentifier<ElanInstance> id = createElanInstanceIdentifier(elanInstanceName);
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, id);
+    }
+
+    private ElanInstance updateElanInstance(String elanInstanceName, Class<? extends SegmentTypeBase> segmentType,
+            String segmentationId, String physicalNetworkName) {
+        ElanInstance elanInstance = createElanInstance(elanInstanceName, segmentType, segmentationId, physicalNetworkName);
+        InstanceIdentifier<ElanInstance> id = createElanInstanceIdentifier(elanInstanceName);
+        MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, id, elanInstance);
+        return elanInstance;
+    }
+
+    private InstanceIdentifier<ElanInstance> createElanInstanceIdentifier(String elanInstanceName) {
+        InstanceIdentifier<ElanInstance> id = InstanceIdentifier.builder(ElanInstances.class)
+                .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+        return id;
+    }
+
+    private ElanInstance createElanInstance(String elanInstanceName, Class<? extends SegmentTypeBase> segmentType,
+            String segmentationId, String physicalNetworkName) {
         ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName);
         if (segmentType != null) {
             elanInstanceBuilder.setSegmentType(segmentType);
@@ -141,17 +192,7 @@ public class NeutronNetworkChangeListener extends AbstractDataChangeListener<Net
             }
         }
         elanInstanceBuilder.setKey(new ElanInstanceKey(elanInstanceName));
-        ElanInstance elanInstance = elanInstanceBuilder.build();
-        InstanceIdentifier<ElanInstance> id = InstanceIdentifier.builder(ElanInstances.class)
-                .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
-        MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, id, elanInstance);
-        return elanInstance;
-    }
-
-    private void deleteElanInstance(String elanInstanceName) {
-        InstanceIdentifier<ElanInstance> id = InstanceIdentifier.builder(ElanInstances.class)
-                .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
-        MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, id);
+        return elanInstanceBuilder.build();
     }
 
 }