Bug 8998 - stale l2gw connection cleanup 62/66562/16
authoreaksahu <a.k.sahu@ericsson.com>
Mon, 18 Dec 2017 12:55:53 +0000 (18:25 +0530)
committerK.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
Sat, 17 Feb 2018 14:48:13 +0000 (20:18 +0530)
Upon cluster reboot fill the l2gw connection cache
by reading from config datastore.

Process l2gw connection even after dependent elan deletion.

Change-Id: Iee993e8f4e2bc6322b394543cb43408361d46e5c
Signed-off-by: eaksahu <a.k.sahu@ericsson.com>
17 files changed:
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanBridgeManager.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanOvsdbNodeListener.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/ha/HwvtepHAUtil.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/ha/commands/BaseCommand.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/jobs/DeleteLogicalSwitchJob.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/HwvtepLocalUcastMacListener.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/HwvtepLogicalSwitchListener.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/HwvtepPhysicalSwitchListener.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/HwvtepRemoteMcastMacListener.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/L2GatewayConnectionListener.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/LocalUcastMacListener.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayUtils.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/L2GatewayConnectionUtils.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java
neutronvpn/impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronNetworkChangeListener.java

index edf744eee6b73c2607ce0127da802e98b174e448..05035f4c7365d744638aa99e3a48cb7ffbaaed6f 100644 (file)
@@ -87,6 +87,8 @@ public class ElanBridgeManager implements IElanBridgeManager {
      * @param dataBroker DataBroker
      * @param elanConfig the elan configuration
      * @param interfaceManager InterfaceManager
+     * @param southboundUtils southboutUtils
+     * @param mdsalUtils mdsalUtils
      */
     @Inject
     public ElanBridgeManager(DataBroker dataBroker, ElanConfig elanConfig, IInterfaceManager interfaceManager,
index 4fb4ace555fc851f91ddb2dcb8b75ca20ee870a3..327ae36c68ee52c96f754e22cc886c1dcf45d5a1 100644 (file)
@@ -44,6 +44,7 @@ public class ElanOvsdbNodeListener extends AsyncDataTreeChangeListenerBase<Node,
      * @param elanConfig the elan configuration
      * @param bridgeMgr bridge manager
      * @param elanProvider elan provider
+     * @param tzUtil TransportzoneNotificationUtils
      */
     @Inject
     public ElanOvsdbNodeListener(final DataBroker dataBroker, ElanConfig elanConfig,
index 05ced1f403aaec8b5b6cb1868394b75becd17c4e..a2fe70bbf0ddf0360594b71d196b5e0e8e6b5fc4 100644 (file)
@@ -611,4 +611,12 @@ public final class HwvtepHAUtil {
         }
         return true;
     }
+
+    public static String getPsName(InstanceIdentifier<Node> psNodeIid) {
+        String psNodeId = psNodeIid.firstKeyOf(Node.class).getNodeId().getValue();
+        if (psNodeId.contains(PHYSICALSWITCH)) {
+            return psNodeId.substring(psNodeId.indexOf(PHYSICALSWITCH) +  PHYSICALSWITCH.length());
+        }
+        return null;
+    }
 }
index 78d410c91f7b3decd3bb4785dec4542034091502..f3f430a8ea7d08f457de4a3f3dd5b9c3cb215b87 100644 (file)
@@ -19,6 +19,7 @@ public abstract class BaseCommand<T> {
      * @param updated Updated List
      * @param original Origina list to be compared with
      * @param comparator based on which diff will be returned
+     * @param <T> T extends DataObject
      * @return List of diff based on comparator
      */
     public <T> List<T> diffOf(List<T> updated, final List<T> original, final Comparator comparator) {
index 8ea4388b9d4b7f53d4dd122014b5d2f606cace5f..c3ed90c422d59c425c3996464abbe6e70dff5a3b 100644 (file)
@@ -86,8 +86,7 @@ public class DeleteLogicalSwitchJob implements Callable<List<ListenableFuture<Vo
         futures.add(HwvtepUtils.deleteLogicalSwitch(broker, hwvtepNodeId, logicalSwitchName));
         if (clearUcast) {
             LOG.trace("Clearing the local ucast macs of device {} macs ", hwvtepNodeId.getValue());
-            futures.addAll(
-                    elanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, logicalSwitchName));
+            elanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, logicalSwitchName);
         }
         return futures;
     }
index 0dc50a6cc36a720c7493a7f01b83df3db8112867..41607824e741120cdfa860e33b4e09616eb5bd2d 100644 (file)
@@ -88,7 +88,7 @@ public class DisAssociateHwvtepFromElanJob implements Callable<List<ListenableFu
                     elanInstanceSupplier.get(), l2GatewayDevice));
 
             LOG.info("delete local ucast macs {} {}", elanName, strHwvtepNodeId);
-            futures.addAll(elanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
+            elanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName);
 
             LOG.info("scheduled delete logical switch {} {}", elanName, strHwvtepNodeId);
             elanL2GatewayUtils.scheduleDeleteLogicalSwitch(hwvtepNodeId,
index 669036786be96eaed527240a095be9adf39a4048..d9585087c1ee496e41c49063811a9be8c06c736e 100644 (file)
@@ -64,7 +64,6 @@ public class HwvtepLocalUcastMacListener extends
         LOG.trace("LocalUcastMacs {} removed from {}", macAddress, hwvtepNodeId);
 
         String elanName = getElanName(macRemoved);
-        ElanInstance elan = ElanUtils.getElanInstanceByName(broker, elanName);
 
         L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
         if (elanL2GwDevice == null) {
@@ -74,9 +73,10 @@ public class HwvtepLocalUcastMacListener extends
 
         // Remove MAC from cache
         elanL2GwDevice.removeUcastLocalMac(macRemoved);
-
-        elanL2GatewayUtils.unInstallL2GwUcastMacFromElan(elan, elanL2GwDevice,
+        elanL2GatewayUtils.unInstallL2GwUcastMacFromL2gwDevices(elanName, elanL2GwDevice,
                 Collections.singletonList(new MacAddress(macAddress.toLowerCase(Locale.getDefault()))));
+        elanL2GatewayUtils.unInstallL2GwUcastMacFromElanDpns(ElanUtils.getElanInstanceByName(broker, elanName),
+                elanL2GwDevice, Collections.singletonList(new MacAddress(macAddress.toLowerCase(Locale.getDefault()))));
     }
 
     protected String getElanName(LocalUcastMacs mac) {
index 75b2c8e6e7d6cbb4be8ba184309655958a70f029..e232ee7efbeae479d99859856868301c2e2a3182 100644 (file)
@@ -63,6 +63,16 @@ public class HwvtepLogicalSwitchListener extends
 
     /**
      * Instantiates a new hardware vtep logical switch listener.
+     * @param elanInstanceManager ElanInstanceManager
+     * @param elanL2GatewayUtils ElanL2GatewayUtils
+     * @param elanClusterUtils ElanClusterUtils
+     * @param elanL2GatewayMulticastUtils ElanL2GatewayMulticastUtils
+     * @param l2GatewayConnectionUtils L2GatewayConnectionUtils
+     * @param l2GatewayDevice L2GatewayDevice for which the listener is initiated
+     * @param logicalSwitchName LS name of the network
+     * @param physicalDevice Devices from cache
+     * @param defaultVlanId default vlanId of the LS
+     * @param l2GwConnId L2gateway connection UUID
      */
     public HwvtepLogicalSwitchListener(ElanInstanceManager elanInstanceManager, ElanL2GatewayUtils elanL2GatewayUtils,
             ElanClusterUtils elanClusterUtils, ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
index 476dbccea89033befa8449470d76a13cfe8120c5..bfb17b03129c0de62c9f93999b9fe8edfcded1aa 100644 (file)
@@ -19,6 +19,7 @@ import java.util.function.Predicate;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
+
 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
@@ -28,6 +29,7 @@ import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.utils.hwvtep.HwvtepHACache;
 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
 import org.opendaylight.netvirt.elan.l2gw.ha.listeners.HAOpClusteredListener;
 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
@@ -42,6 +44,7 @@ import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentationBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
 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;
@@ -132,6 +135,13 @@ public class HwvtepPhysicalSwitchListener
 
     /**
      * Instantiates a new hwvtep physical switch listener.
+     * @param dataBroker DataBroker
+     * @param itmRpcService ItmRpcService
+     * @param elanClusterUtils ElanClusterUtils
+     * @param l2gwServiceProvider L2gwServiceProvider
+     * @param haListener HAOpClusteredListener
+     * @param l2GatewayCache L2GatewayCache
+     * @param staleVlanBindingsCleaner StaleVlanBindingsCleaner
      */
     @Inject
     public HwvtepPhysicalSwitchListener(final DataBroker dataBroker, ItmRpcService itmRpcService,
@@ -306,6 +316,9 @@ public class HwvtepPhysicalSwitchListener
             }
 
             handleAdd(l2GwDevice);
+            elanClusterUtils.runOnlyInOwnerNode("Update config tunnels IP ", () -> {
+                updateConfigTunnelIp(identifier, phySwitchAdded);
+            });
             return;
         });
     }
@@ -383,4 +396,17 @@ public class HwvtepPhysicalSwitchListener
         }
         return null;
     }
+
+    private void updateConfigTunnelIp(InstanceIdentifier<PhysicalSwitchAugmentation> identifier,
+                                      PhysicalSwitchAugmentation phySwitchAdded) {
+        if (phySwitchAdded.getTunnelIps() != null) {
+            ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
+            PhysicalSwitchAugmentationBuilder psBuilder = new PhysicalSwitchAugmentationBuilder();
+            psBuilder.setTunnelIps(phySwitchAdded.getTunnelIps());
+            tx.merge(LogicalDatastoreType.CONFIGURATION, identifier, psBuilder.build());
+            LOG.trace("Updating config tunnel ips {}", identifier);
+            ListenableFutures.addErrorLogging(tx.submit(), LOG,
+                    "Failed to update config tunnel ip for iid {}", identifier);
+        }
+    }
 }
index 575ea2a943e7157ab85a22845d2b844506750695..126004f2e0c818ee6f9d1d4999074c64fa335eba 100644 (file)
@@ -59,6 +59,14 @@ public class HwvtepRemoteMcastMacListener
 
     /**
      * Instantiates a new remote mcast mac listener.
+     * @param broker DataBroker
+     * @param elanUtils ElanUtils
+     * @param logicalSwitchName LS name of the network
+     * @param l2GatewayDevice L2GatewayDevice
+     * @param expectedPhyLocatorIps List of IP addresses
+     * @param task List of tasks to be executed on callbacks
+     * @param jobCoordinator JobCoordinator
+     * @throws Exception throws Exception
      */
     public HwvtepRemoteMcastMacListener(DataBroker broker, ElanUtils elanUtils, String logicalSwitchName,
                                         L2GatewayDevice l2GatewayDevice,
index 5de55b3d170446502b136491b2bb5857ae613f1a..a0d2e0d989e76ac1208b11ff662218fe514022cd 100644 (file)
@@ -7,16 +7,44 @@
  */
 package org.opendaylight.netvirt.elan.l2gw.listeners;
 
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+
+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.MoreExecutors;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+import java.util.function.Predicate;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
+
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
 import org.opendaylight.netvirt.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.netvirt.elan.utils.Scheduler;
+import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
+import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 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.rev150712.Neutron;
+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.PhysicalSwitchAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
+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.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -25,20 +53,55 @@ import org.slf4j.LoggerFactory;
 public class L2GatewayConnectionListener extends AsyncClusteredDataTreeChangeListenerBase<L2gatewayConnection,
         L2GatewayConnectionListener> {
     private static final Logger LOG = LoggerFactory.getLogger(L2GatewayConnectionListener.class);
+    private static final int MAX_READ_TRIALS = 120;
+
+    private static final Function<Node, InstanceIdentifier<Node>> TO_GLOBAL_PATH = (psNode) -> {
+        return HwvtepHAUtil.getGlobalNodePathFromPSNode(psNode);
+    };
+
+    private static final Function<Node, InstanceIdentifier<Node>> TO_NODE_PATH = (node) -> {
+        return HwvtepSouthboundUtils.createInstanceIdentifier(node.getNodeId());
+    };
+
+    private static final Function<InstanceIdentifier<Node>, String> GET_DEVICE_NAME = (psIid) -> {
+        return HwvtepHAUtil.getPsName(psIid);
+    };
+
+    private static final Predicate<InstanceIdentifier<Node>> IS_PS_NODE = (psIid) -> {
+        return HwvtepHAUtil.getPsName(psIid) != null;
+    };
+
+    private static final Predicate<Node> IS_HA_PARENT_NODE = (node) -> {
+        HwvtepGlobalAugmentation augmentation = node.getAugmentation(HwvtepGlobalAugmentation.class);
+        if (augmentation != null && augmentation.getManagers() != null) {
+            return augmentation.getManagers().stream().anyMatch(
+                manager -> manager.getKey().getTarget().getValue().equals(HwvtepHAUtil.MANAGER_KEY));
+        }
+        return false;
+    };
+
+    private static final BiPredicate<InstanceIdentifier<Node>, Node> PS_NODE_OF_PARENT_NODE = (psIid, node) -> {
+        return psIid.firstKeyOf(Node.class).getNodeId().getValue().contains(node.getNodeId().getValue());
+    };
 
     private final DataBroker broker;
     private final L2GatewayConnectionUtils l2GatewayConnectionUtils;
+    private final Scheduler scheduler;
+    private final L2GatewayCache l2GatewayCache;
 
     @Inject
-    public L2GatewayConnectionListener(final DataBroker db, L2GatewayConnectionUtils l2GatewayConnectionUtils) {
+    public L2GatewayConnectionListener(final DataBroker db, L2GatewayConnectionUtils l2GatewayConnectionUtils,
+                                       Scheduler scheduler, L2GatewayCache l2GatewayCache) {
         super(L2gatewayConnection.class, L2GatewayConnectionListener.class);
         this.broker = db;
         this.l2GatewayConnectionUtils = l2GatewayConnectionUtils;
+        this.scheduler = scheduler;
+        this.l2GatewayCache = l2GatewayCache;
     }
 
     @PostConstruct
     public void init() {
-        registerListener(LogicalDatastoreType.CONFIGURATION, broker);
+        loadL2GwDeviceCache(1);
     }
 
     @Override
@@ -75,4 +138,90 @@ public class L2GatewayConnectionListener extends AsyncClusteredDataTreeChangeLis
     protected L2GatewayConnectionListener getDataTreeChangeListener() {
         return this;
     }
+
+    private void loadL2GwDeviceCache(final int trialNo) {
+        scheduler.getScheduledExecutorService().schedule(() -> {
+            if (trialNo == MAX_READ_TRIALS) {
+                LOG.error("Failed to read config topology");
+                return;
+            }
+            ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+            InstanceIdentifier<Topology> topoIid = HwvtepSouthboundUtils.createHwvtepTopologyInstanceIdentifier();
+            Futures.addCallback(tx.read(CONFIGURATION, topoIid), new FutureCallback<Optional<Topology>>() {
+                @Override
+                public void onSuccess(Optional<Topology> topologyOptional) {
+                    if (topologyOptional != null && topologyOptional.isPresent()) {
+                        loadL2GwDeviceCache(topologyOptional.get().getNode());
+                    }
+                    registerListener(CONFIGURATION, broker);
+                }
+
+                @Override
+                public void onFailure(Throwable throwable) {
+                    loadL2GwDeviceCache(trialNo + 1);
+                }
+            }, MoreExecutors.directExecutor());
+            tx.close();
+        }, 1, TimeUnit.SECONDS);
+    }
+
+    private void loadL2GwDeviceCache(List<Node> nodes) {
+        if (nodes == null) {
+            LOG.debug("No config topology nodes are present");
+            return;
+        }
+        Map<InstanceIdentifier<Node>, Node> allNodes = nodes
+                .stream()
+                .collect(toMap(TO_NODE_PATH, Function.identity()));
+
+        LOG.trace("Loading all config nodes");
+
+        Set<InstanceIdentifier<Node>> allIids = allNodes.keySet();
+
+        Map<String, List<InstanceIdentifier<Node>>> psNodesByDeviceName = allIids
+                .stream()
+                .filter(IS_PS_NODE)
+                .collect(groupingBy(GET_DEVICE_NAME, toList()));
+
+        //Process HA nodes
+        allNodes.values().stream()
+                .filter(IS_HA_PARENT_NODE)
+                .forEach(parentNode -> {
+                    allIids.stream()
+                            .filter(IS_PS_NODE)
+                            .filter(psIid -> PS_NODE_OF_PARENT_NODE.test(psIid, parentNode))
+                            .forEach(psIid -> {
+                                addL2DeviceToCache(psIid, parentNode, allNodes.get(psIid));
+                            });
+                });
+
+        //Process non HA nodes there will be only one ps node iid for each device for non ha nodes
+        psNodesByDeviceName.values().stream()
+                .filter(psIids -> psIids.size() == 1)
+                .map(psIids -> psIids.get(0))
+                .forEach(psIid -> {
+                    Node psNode = allNodes.get(psIid);
+                    Node globalNode = allNodes.get(TO_GLOBAL_PATH.apply(psNode));
+                    if (globalNode != null) {
+                        addL2DeviceToCache(psIid, globalNode, psNode);
+                    }
+                });
+    }
+
+    void addL2DeviceToCache(InstanceIdentifier<Node> psIid, Node globalNode, Node psNode) {
+        LOG.trace("Adding device to cache {}", psNode.getNodeId().getValue());
+        String deviceName = HwvtepHAUtil.getPsName(psIid);
+        L2GatewayDevice l2GwDevice = l2GatewayCache.addOrGet(deviceName);
+        l2GwDevice.setConnected(true);
+        l2GwDevice.setHwvtepNodeId(globalNode.getNodeId().getValue());
+
+        List<TunnelIps> tunnelIps = psNode.getAugmentation(PhysicalSwitchAugmentation.class) != null
+                ? psNode.getAugmentation(PhysicalSwitchAugmentation.class).getTunnelIps() : null;
+        if (tunnelIps != null) {
+            for (TunnelIps tunnelIp : tunnelIps) {
+                IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
+                l2GwDevice.addTunnelIp(tunnelIpAddr);
+            }
+        }
+    }
 }
index 0c870846f27056379a39e95215045aa1535bf72d..f0503e57123545d02e00cbaa3d7e37021a3deb3f 100644 (file)
@@ -34,7 +34,6 @@ import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
 import org.opendaylight.netvirt.elan.l2gw.ha.listeners.HAOpClusteredListener;
 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
-import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
 import org.opendaylight.netvirt.elan.utils.ElanUtils;
 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
@@ -69,18 +68,15 @@ public class LocalUcastMacListener extends ChildListener<Node, LocalUcastMacs, S
     private final ElanL2GatewayUtils elanL2GatewayUtils;
     private final HAOpClusteredListener haOpClusteredListener;
     private final JobCoordinator jobCoordinator;
-    private final ElanClusterUtils elanClusterUtils;
 
     @Inject
     public LocalUcastMacListener(final DataBroker dataBroker,
                                  final HAOpClusteredListener haOpClusteredListener,
                                  final ElanL2GatewayUtils elanL2GatewayUtils,
-                                 final ElanClusterUtils elanClusterUtils,
                                  final JobCoordinator jobCoordinator) {
         super(dataBroker, false);
         this.elanL2GatewayUtils = elanL2GatewayUtils;
         this.haOpClusteredListener = haOpClusteredListener;
-        this.elanClusterUtils = elanClusterUtils;
         this.jobCoordinator = jobCoordinator;
     }
 
@@ -145,11 +141,10 @@ public class LocalUcastMacListener extends ChildListener<Node, LocalUcastMacs, S
 
                 elanL2GwDevice.removeUcastLocalMac(macRemoved);
                 ElanInstance elanInstance = ElanUtils.getElanInstanceByName(dataBroker, elanName);
-
-                elanClusterUtils.runOnlyInOwnerNode(elanName + ":" + macAddress,
-                        "Delete l2gw local ucast mac", () -> {
-                        return elanL2GatewayUtils.unInstallL2GwUcastMacFromElan(elanInstance, elanL2GwDevice,
-                                Collections.singletonList(new MacAddress(macAddress.toLowerCase()))); });
+                elanL2GatewayUtils.unInstallL2GwUcastMacFromL2gwDevices(elanName, elanL2GwDevice,
+                        Collections.singletonList(new MacAddress(macAddress.toLowerCase(Locale.getDefault()))));
+                elanL2GatewayUtils.unInstallL2GwUcastMacFromElanDpns(elanInstance, elanL2GwDevice,
+                        Collections.singletonList(new MacAddress(macAddress.toLowerCase(Locale.getDefault()))));
                 return null;
             });
     }
index 567496e368f46238f1f04c28a6478feb8e09eaa5..488ee4846893d73323b1b23a0a6658312d1d1019 100644 (file)
@@ -101,11 +101,9 @@ public class ElanL2GatewayMulticastUtils {
 
     /**
      * Handle mcast for elan l2 gw device add.
-     *
-     * @param elanName
-     *            the elan name
-     * @param device
-     *            the device
+     * @param elanName the elan name
+     * @param elanInstance elanInstace
+     * @param device the device
      * @return the listenable future
      */
     public ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, ElanInstance elanInstance,
index 9d5fc08b7acf0bbd041358742e3b9e429b104c9c..ae3874d949c5b2559f6f3ec0dc580afbb3ad7e94 100644 (file)
@@ -13,7 +13,6 @@ import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.SettableFuture;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -413,41 +412,61 @@ public class ElanL2GatewayUtils {
     }
 
     /**
-     * Un install l2 gw ucast mac from elan.
-     *
-     * @param elan
-     *            the elan
-     * @param l2GwDevice
-     *            the l2 gw device
-     * @param macAddresses
-     *            the mac addresses
-     * @return a list of ListenableFutures
+     * Uninstall l2gw macs from other l2gw devices in the elanName provided.
+     * @param elanName - Elan Name for which other l2gw devices will be scanned.
+     * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
+     * @param macAddresses - Mac address to be cleared.
      */
-    public List<ListenableFuture<Void>> unInstallL2GwUcastMacFromElan(final ElanInstance elan,
-                                                                      final L2GatewayDevice l2GwDevice,
-                                                                      final Collection<MacAddress> macAddresses) {
+    public void unInstallL2GwUcastMacFromL2gwDevices(final String elanName,
+                                                     final L2GatewayDevice l2GwDevice,
+                                                     final Collection<MacAddress> macAddresses) {
         if (macAddresses == null || macAddresses.isEmpty()) {
-            return Collections.emptyList();
+            return;
+        }
+
+        if (elanName == null) {
+            return;
         }
-        final String elanName = elan.getElanInstanceName();
 
-        final List<DpnInterfaces> elanDpns = getElanDpns(elanName);
+        DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(elanName, l2GwDevice,
+                macAddresses);
+        elanClusterUtils.runOnlyInOwnerNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
+    }
+
+    /**
+     * Uninstall l2gw macs from other DPNs in the elan instance provided.
+     * @param elan - Elan Instance for which other DPNs will be scanned.
+     * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
+     * @param macAddresses - Mac address to be cleared.
+     */
+    public void unInstallL2GwUcastMacFromElanDpns(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
+                                                  final Collection<MacAddress> macAddresses) {
+        if (macAddresses == null || macAddresses.isEmpty()) {
+            return;
+        }
+        if (elan == null || elan.getElanInstanceName() == null) {
+            LOG.error("Could not delete l2gw ucast macs, Failed to find the elan for device {}",
+                    l2GwDevice.getHwvtepNodeId());
+            return;
+        }
+
+        final List<DpnInterfaces> elanDpns = getElanDpns(elan.getElanInstanceName());
 
-        List<ListenableFuture<Void>> result = new ArrayList<>();
         // Retrieve all participating DPNs in this Elan. Populate this MAC in
         // DMAC table. Looping through all DPNs in order to add/remove mac flows
         // in their DMAC table
+        List<ListenableFuture<Void>> result = new ArrayList<>();
         for (final MacAddress mac : macAddresses) {
-            for (DpnInterfaces elanDpn : elanDpns) {
-                BigInteger dpnId = elanDpn.getDpId();
-                result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
-                        l2GwDevice.getHwvtepNodeId(), mac.getValue().toLowerCase(Locale.getDefault())));
-            }
+            elanClusterUtils.runOnlyInOwnerNode(elan.getElanInstanceName() + ":" + mac.getValue(),
+                    "delete remote ucast macs in elan DPNs", () -> {
+                    for (DpnInterfaces elanDpn : elanDpns) {
+                        BigInteger dpnId = elanDpn.getDpId();
+                        result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
+                                l2GwDevice.getHwvtepNodeId(), mac.getValue().toLowerCase(Locale.getDefault())));
+                    }
+                    return result;
+                });
         }
-
-        //Batched job
-        result.addAll(new DeleteL2GwDeviceMacsFromElanJob(elanName, l2GwDevice, macAddresses).call());
-        return result;
     }
 
     /**
@@ -457,7 +476,7 @@ public class ElanL2GatewayUtils {
      *            the elan name
      * @param dpnId
      *            the dpn id
-     * @throws ReadFailedException if a read fails
+     * @throws ReadFailedException if a read fails throws ReadFailedException
      */
     public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId)
             throws ReadFailedException {
@@ -502,29 +521,28 @@ public class ElanL2GatewayUtils {
 
         InstanceIdentifier<Node> nodeIid = HwvtepSouthboundUtils.createInstanceIdentifier(
                 new NodeId(l2gwDevice.getHwvtepNodeId()));
-        ListenableFuture<Optional<Node>> ft
-                = broker.newReadOnlyTransaction().read(LogicalDatastoreType.CONFIGURATION, nodeIid);
-        Futures.addCallback(ft, new FutureCallback<Optional<Node>>() {
-            @Override
-            public void onSuccess(Optional<Node> configNode) {
-                if (configNode != null && configNode.isPresent()) {
-                    HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(
-                            HwvtepGlobalAugmentation.class);
-                    if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
-                        macs.addAll(augmentation.getLocalUcastMacs().stream()
-                                .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
-                                .map(mac -> mac.getMacEntryKey())
-                                .collect(Collectors.toSet()));
+        Futures.addCallback(broker.newReadOnlyTransaction().read(LogicalDatastoreType.CONFIGURATION, nodeIid),
+                new FutureCallback<Optional<Node>>() {
+                    @Override
+                    public void onSuccess(Optional<Node> configNode) {
+                        if (configNode != null && configNode.isPresent()) {
+                            HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(
+                                    HwvtepGlobalAugmentation.class);
+                            if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
+                                macs.addAll(augmentation.getLocalUcastMacs().stream()
+                                        .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
+                                        .map(mac -> mac.getMacEntryKey())
+                                        .collect(Collectors.toSet()));
+                            }
+                            function.apply(macs);
+                        }
                     }
-                    function.apply(macs);
-                }
-            }
 
-            @Override
-            public void onFailure(Throwable throwable) {
-                LOG.error("Failed to read config topology node ", nodeIid);
-            }
-        }, MoreExecutors.directExecutor());
+                    @Override
+                    public void onFailure(Throwable throwable) {
+                        LOG.error("Failed to read config topology node ", nodeIid);
+                    }
+                }, MoreExecutors.directExecutor());
     }
 
     private String getLogicalSwitchName(LocalUcastMacs mac) {
@@ -943,10 +961,9 @@ public class ElanL2GatewayUtils {
      *            from elan
      * @param elanName
      *            the elan name
-     * @return the listenable future
      * @throws ReadFailedException if a read fails
      */
-    public List<ListenableFuture<Void>> deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
+    public void deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
             String elanName) throws ReadFailedException {
         LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(),
                 elanName);
@@ -954,27 +971,12 @@ public class ElanL2GatewayUtils {
         ElanInstance elan = ElanUtils.getElanInstanceByName(broker, elanName);
         if (elan == null) {
             LOG.error("Could not find Elan by name: {}", elanName);
-            return Collections.emptyList();
+            return;
         }
 
-        SettableFuture<Void> settableFuture = SettableFuture.create();
-        getL2GwDeviceLocalMacsAndRunCallback(elanName, l2GatewayDevice, (localMacs) -> {
-            Futures.addCallback(
-                    Futures.allAsList(unInstallL2GwUcastMacFromElan(elan, l2GatewayDevice, localMacs)),
-                    new FutureCallback<List<Void>>() {
-                        @Override
-                        public void onSuccess(List<Void> voids) {
-                            settableFuture.set(null);
-                        }
-
-                        @Override
-                        public void onFailure(Throwable throwable) {
-                            settableFuture.setException(throwable);
-                        }
-                    }, MoreExecutors.directExecutor());
-            return null;
-        });
-        return Collections.singletonList(settableFuture);
+        Collection<MacAddress> localMacs = getL2GwDeviceLocalMacs(elanName, l2GatewayDevice);
+        unInstallL2GwUcastMacFromL2gwDevices(elanName, l2GatewayDevice, localMacs);
+        unInstallL2GwUcastMacFromElanDpns(elan, l2GatewayDevice, localMacs);
     }
 
     public static void createItmTunnels(ItmRpcService itmRpcService, String hwvtepId, String psName,
@@ -1061,4 +1063,37 @@ public class ElanL2GatewayUtils {
         }
         return new ArrayList<>(dpnInterfaces);
     }
+
+    /**
+     * Gets the l2 gw device local macs.
+     * @param elanName
+     *            name of the elan
+     * @param l2gwDevice
+     *            the l2gw device
+     * @return the l2 gw device local macs
+     */
+    public Collection<MacAddress> getL2GwDeviceLocalMacs(String elanName, L2GatewayDevice l2gwDevice) {
+        if (l2gwDevice == null) {
+            return Collections.emptyList();
+        }
+        Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
+        Set<MacAddress> macs = new HashSet<>();
+        if (!lstUcastLocalMacs.isEmpty()) {
+            macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
+                    .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase()))
+                    .collect(Collectors.toList()));
+        }
+        Optional<Node> configNode = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION,
+                HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2gwDevice.getHwvtepNodeId())));
+        if (configNode.isPresent()) {
+            HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(HwvtepGlobalAugmentation.class);
+            if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
+                macs.addAll(augmentation.getLocalUcastMacs().stream()
+                        .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
+                        .map(mac -> mac.getMacEntryKey())
+                        .collect(Collectors.toSet()));
+            }
+        }
+        return macs;
+    }
 }
index b927e67d6ae9836a19eb3c059376c77e171a697f..9a8ae7dbac4ea100e0079b130fe8bae472e9976d 100644 (file)
@@ -31,11 +31,12 @@ import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
+import org.opendaylight.netvirt.elan.l2gw.ha.listeners.HAOpClusteredListener;
 import org.opendaylight.netvirt.elan.l2gw.jobs.AssociateHwvtepToElanJob;
 import org.opendaylight.netvirt.elan.l2gw.jobs.DisAssociateHwvtepFromElanJob;
 import org.opendaylight.netvirt.elan.l2gw.listeners.ElanInstanceListener;
-import org.opendaylight.netvirt.elan.l2gw.listeners.HwvtepLocalUcastMacListener;
 import org.opendaylight.netvirt.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
+import org.opendaylight.netvirt.elan.l2gw.listeners.LocalUcastMacListener;
 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
@@ -70,12 +71,13 @@ public class L2GatewayConnectionUtils implements AutoCloseable {
     private final JobCoordinator jobCoordinator;
     private final L2GatewayCache l2GatewayCache;
     private final List<AutoCloseable> closeables = new CopyOnWriteArrayList<>();
+    private final HAOpClusteredListener haOpClusteredListener;
 
     @Inject
     public L2GatewayConnectionUtils(DataBroker dataBroker, ElanInstanceManager elanInstanceManager,
             ElanClusterUtils elanClusterUtils, ElanL2GatewayUtils elanL2GatewayUtils,
             JobCoordinator jobCoordinator, ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
-            L2GatewayCache l2GatewayCache) {
+            L2GatewayCache l2GatewayCache, HAOpClusteredListener haOpClusteredListener) {
         this.broker = dataBroker;
         this.elanInstanceManager = elanInstanceManager;
         this.elanL2GatewayUtils = elanL2GatewayUtils;
@@ -83,6 +85,7 @@ public class L2GatewayConnectionUtils implements AutoCloseable {
         this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
         this.jobCoordinator = jobCoordinator;
         this.l2GatewayCache = l2GatewayCache;
+        this.haOpClusteredListener = haOpClusteredListener;
     }
 
     @Override
@@ -297,7 +300,7 @@ public class L2GatewayConnectionUtils implements AutoCloseable {
 
                 // Add L2 Gateway device to 'ElanL2GwDevice' cache
                 boolean createLogicalSwitch;
-                LogicalSwitches logicalSwitch = HwvtepUtils.getLogicalSwitch(broker, LogicalDatastoreType.OPERATIONAL,
+                LogicalSwitches logicalSwitch = HwvtepUtils.getLogicalSwitch(broker, LogicalDatastoreType.CONFIGURATION,
                         hwvtepNodeId, elanName);
                 if (logicalSwitch == null) {
                     HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
@@ -365,8 +368,9 @@ public class L2GatewayConnectionUtils implements AutoCloseable {
                     nodeIid), new SettableFutureCallback<Optional<Node>>(settableFuture) {
                         @Override
                         public void onSuccess(@Nonnull Optional<Node> resultNode) {
-                            HwvtepLocalUcastMacListener localUcastMacListener =
-                                    new HwvtepLocalUcastMacListener(broker, elanL2GatewayUtils);
+                            LocalUcastMacListener localUcastMacListener =
+                                    new LocalUcastMacListener(broker, haOpClusteredListener,
+                                            elanL2GatewayUtils, jobCoordinator);
                             settableFuture.set(resultNode);
                             Optional<Node> nodeOptional = resultNode;
                             if (nodeOptional.isPresent()) {
index 453823bece5892fea6ebaf0b444a0fb2f98f2760..c615ff86af3af4f105ce7d1fb615ec39ab9139d6 100755 (executable)
@@ -288,6 +288,11 @@ public class ElanUtils {
      *
      * @deprecated Consider using {@link #read2(LogicalDatastoreType, InstanceIdentifier)} with proper exception
      *             handling instead
+     * @param broker dataBroker
+     * @param datastoreType Logical DataStore type
+     * @param path IID to read
+     * @param <T> T extends DataObject
+     * @return the read value T
      */
     @Deprecated
     @SuppressWarnings("checkstyle:IllegalCatch")
@@ -1038,6 +1043,8 @@ public class ElanUtils {
      *            macAddress
      * @param displayName
      *            display Name
+     * @param elanInstance
+     *            elanInstance
      * @return the flow remote Dmac
      * @throws ElanException in case of issues creating the flow objects
      */
@@ -1538,6 +1545,13 @@ public class ElanUtils {
     /**
      * Add Mac Address to ElanInterfaceForwardingEntries and ElanForwardingTables
      * Install SMAC and DMAC flows.
+     * @param interfaceName interface name
+     * @param macAddress mac addresses
+     * @param elanName elan Name
+     * @param interfaceTx write transaction
+     * @param flowTx flow write transaction
+     * @param macTimeOut timeout value
+     * @throws ElanException elan exception is thrown upon write failure
      */
     public void addMacEntryToDsAndSetupFlows(String interfaceName,
             String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx, int macTimeOut)
@@ -1562,6 +1576,11 @@ public class ElanUtils {
     /**
      * Remove Mac Address from ElanInterfaceForwardingEntries and ElanForwardingTables
      * Remove SMAC and DMAC flows.
+     * @param interfaceName interface name
+     * @param macAddress mac addresses
+     * @param elanName elan name
+     * @param interfaceTx write transaction
+     * @param flowTx flow write transaction
      */
     public void deleteMacEntryFromDsAndRemoveFlows(String interfaceName,
             String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx) {
index 1e2a0a114788b39d40231105c272795c99d1a7ee..9e8ed751295b8b744c75b8794833ea3e20931944 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeFlat;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
@@ -32,6 +33,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.instances.elan.instance.ElanSegmentsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
 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;
@@ -187,21 +189,29 @@ public class NeutronNetworkChangeListener
     @Nonnull
     private List<ElanSegments> buildSegments(Network input) {
         Long numSegments = NeutronUtils.getNumberSegmentsFromNeutronNetwork(input);
-        Long index = 0L;
         List<ElanSegments> segments = new ArrayList<>();
-        while (index < numSegments) {
-            index++;
+
+        for (long index = 0L; index < numSegments; index++) {
             ElanSegmentsBuilder elanSegmentsBuilder = new ElanSegmentsBuilder();
-            elanSegmentsBuilder.setSegmentationId(Long.valueOf(NeutronUtils.getSegmentationIdFromNeutronNetworkSegment(
-                    input, index)));
+            elanSegmentsBuilder.setSegmentationId(0L);
+            if (NeutronUtils.getSegmentationIdFromNeutronNetworkSegment(input, index) != null) {
+                try {
+                    elanSegmentsBuilder.setSegmentationId(
+                            Long.valueOf(NeutronUtils.getSegmentationIdFromNeutronNetworkSegment(input, index)));
+                } catch (NumberFormatException error) {
+                    LOG.error("Failed to get the segment id for network {}", input);
+                }
+            }
             if (NeutronUtils.isNetworkSegmentType(input, index, NetworkTypeVxlan.class)) {
                 elanSegmentsBuilder.setSegmentType(SegmentTypeVxlan.class);
             } else if (NeutronUtils.isNetworkSegmentType(input, index, NetworkTypeVlan.class)) {
                 elanSegmentsBuilder.setSegmentType(SegmentTypeVlan.class);
+            } else if (NeutronUtils.isNetworkSegmentType(input, index, NetworkTypeFlat.class)) {
+                elanSegmentsBuilder.setSegmentType(SegmentTypeFlat.class);
             }
             elanSegmentsBuilder.setSegmentationIndex(index);
             segments.add(elanSegmentsBuilder.build());
-            LOG.debug("Added segment {} to ELANInstance{}", segments.get(Integer.valueOf(index.intValue() - 1)));
+            LOG.debug("Added segment {} to ELANInstance{}", segments.get((int)index - 1));
         }
         return segments;
     }