bug 9018 l2gw designated dhcp fix 78/62078/3
authorK.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
Mon, 21 Aug 2017 11:21:27 +0000 (16:51 +0530)
committerSam Hague <shague@redhat.com>
Tue, 22 Aug 2017 11:59:05 +0000 (11:59 +0000)
Instead of listening for logical switch creation, listen for
mcast mac creation and update the mcast mac to avoid race of updating the
mcast mac.
while updating mcast mac read the existing mac and add designated dhcp tep
ip to the existing locators.

Change-Id: Id4d99471ae0b3be306a5511ee7cea975606deaa3
Signed-off-by: K.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpExternalTunnelManager.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpL2GwUtil.java [new file with mode: 0644]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpLogicalSwitchListener.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpMcastMacListener.java [new file with mode: 0644]

index 9244c36f3d7e631d611d0b21b1b7c10282a1aae3..a2fd652471c86ae4325b7a2ca6ef05ff4734af17 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.netvirt.dhcpservice;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -15,6 +16,7 @@ import com.google.common.util.concurrent.ListenableFuture;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
@@ -30,9 +32,11 @@ import javax.inject.Singleton;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
@@ -67,7 +71,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.por
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
@@ -76,6 +79,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
@@ -638,22 +642,32 @@ public class DhcpExternalTunnelManager {
     }
 
     public RemoteMcastMacs createRemoteMcastMac(Node dstDevice, String logicalSwitchName, IpAddress internalTunnelIp) {
-        List<LocatorSet> locators = new ArrayList<>();
-        for (TerminationPoint tp : dstDevice.getTerminationPoint()) {
-            HwvtepPhysicalLocatorAugmentation aug = tp.getAugmentation(HwvtepPhysicalLocatorAugmentation.class);
-            if (internalTunnelIp.getIpv4Address().equals(aug.getDstIp().getIpv4Address())) {
-                HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
-                        HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(dstDevice.getNodeId(), aug));
-                locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
-            }
-        }
+        Set<LocatorSet> locators = new HashSet<>();
+        TerminationPointKey terminationPointKey = HwvtepSouthboundUtils.getTerminationPointKey(
+                internalTunnelIp.getIpv4Address().getValue());
+        HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
+                HwvtepSouthboundUtils.createInstanceIdentifier(dstDevice.getNodeId()).child(TerminationPoint.class,
+                        terminationPointKey));
+        locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
+
         HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
                 .createLogicalSwitchesInstanceIdentifier(dstDevice.getNodeId(), new HwvtepNodeName(logicalSwitchName)));
 
-        RemoteMcastMacs remoteUcastMacs = new RemoteMcastMacsBuilder()
+        RemoteMcastMacs remoteMcastMacs = new RemoteMcastMacsBuilder()
                 .setMacEntryKey(new MacAddress(UNKNOWN_DMAC))
-                .setLogicalSwitchRef(lsRef).setLocatorSet(locators).build();
-        return remoteUcastMacs;
+                .setLogicalSwitchRef(lsRef).build();
+        InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(
+                dstDevice.getNodeId(), remoteMcastMacs.getKey());
+        ReadOnlyTransaction transaction = broker.newReadOnlyTransaction();
+        try {
+            //TODO do async mdsal read
+            remoteMcastMacs = transaction.read(LogicalDatastoreType.CONFIGURATION, iid).checkedGet().get();
+            locators.addAll(remoteMcastMacs.getLocatorSet());
+            return new RemoteMcastMacsBuilder(remoteMcastMacs).setLocatorSet(new ArrayList<>(locators)).build();
+        } catch (ReadFailedException e) {
+            LOG.error("Failed to read the macs {}", iid);
+        }
+        return null;
     }
 
     private WriteTransaction putRemoteMcastMac(WriteTransaction transaction, String elanName,
@@ -702,7 +716,7 @@ public class DhcpExternalTunnelManager {
                             WriteTransaction transaction = broker.newWriteOnlyTransaction();
                             putRemoteMcastMac(transaction, elanInstanceName, device, internalTunnelIp);
                             if (transaction != null) {
-                                transaction.submit();
+                                return Lists.newArrayList(transaction.submit());
                             }
                         }
                         return null;
diff --git a/vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpL2GwUtil.java b/vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpL2GwUtil.java
new file mode 100644 (file)
index 0000000..1948a9a
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.dhcpservice;
+
+import com.google.common.base.Optional;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Predicate;
+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.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.netvirt.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+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.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.global.attributes.Switches;
+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.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class DhcpL2GwUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DhcpL2GwUtil.class);
+
+    private static final Predicate<List> EMPTY_LIST = (list) -> list == null || list.isEmpty();
+
+    private static final Predicate<Optional<Node>> CONTAINS_GLOBAL_AUGMENTATION = (optionalNode) -> {
+        return optionalNode.isPresent() && optionalNode.get().getAugmentation(HwvtepGlobalAugmentation.class) != null;
+    };
+
+    private static final Predicate<Optional<Node>> CONTAINS_SWITCH_AUGMENTATION = (optionalNode) -> {
+        return optionalNode.isPresent() && optionalNode.get().getAugmentation(PhysicalSwitchAugmentation.class) != null;
+    };
+
+    private final DataBroker dataBroker;
+
+    @Inject
+    public DhcpL2GwUtil(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    public IpAddress getHwvtepNodeTunnelIp(InstanceIdentifier<Node> nodeIid) {
+        ConcurrentMap<String, L2GatewayDevice> devices = L2GatewayCacheUtils.getCache();
+        String nodeId = nodeIid.firstKeyOf(Node.class).getNodeId().getValue();
+        L2GatewayDevice targetDevice = null;
+        for (L2GatewayDevice device : devices.values()) {
+            if (nodeId.equals(device.getHwvtepNodeId())) {
+                targetDevice = device;
+                break;
+            }
+        }
+        return targetDevice != null ? targetDevice.getTunnelIp() : getTunnelIp(nodeIid);
+    }
+
+
+    private IpAddress getTunnelIp(InstanceIdentifier<Node> nodeIid) {
+        Optional<Node> nodeOptional =
+                MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, nodeIid);
+        if (!CONTAINS_GLOBAL_AUGMENTATION.test(nodeOptional)) {
+            return null;
+        }
+        List<Switches> switchIids = nodeOptional.get().getAugmentation(HwvtepGlobalAugmentation.class).getSwitches();
+        if (EMPTY_LIST.test(switchIids)) {
+            return null;
+        }
+        InstanceIdentifier<Node> psIid = (InstanceIdentifier<Node>) switchIids.get(0).getSwitchRef().getValue();
+        nodeOptional = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, psIid);
+        if (!CONTAINS_SWITCH_AUGMENTATION.test(nodeOptional)) {
+            return null;
+        }
+        List<TunnelIps> tunnelIps = nodeOptional.get().getAugmentation(PhysicalSwitchAugmentation.class).getTunnelIps();
+        if (EMPTY_LIST.test(tunnelIps)) {
+            return null;
+        }
+        return tunnelIps.get(0).getKey().getTunnelIpsKey();
+    }
+
+}
\ No newline at end of file
index 6366b45d896cec4b0adad1536569f9d3c24d2f4e..1da99cdf074e252cc72a7b1c8522c2ab23a68586 100644 (file)
@@ -61,14 +61,15 @@ public class DhcpLogicalSwitchListener
     @PostConstruct
     public void init() {
         if (config.isControllerDhcpEnabled()) {
-            registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
+            //Taken care by mcast mac listener
+            //registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
         }
     }
 
     @Override
     @PreDestroy
     public void close() {
-        super.close();
+        //super.close();
         LOG.info("DhcpLogicalSwitchListener Closed");
     }
 
diff --git a/vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpMcastMacListener.java b/vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpMcastMacListener.java
new file mode 100644 (file)
index 0000000..8fd8f08
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+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.genius.datastoreutils.hwvtep.HwvtepAbstractDataTreeChangeListener;
+import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
+import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
+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.params.xml.ns.yang.dhcpservice.config.rev150710.DhcpserviceConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class DhcpMcastMacListener
+        extends HwvtepAbstractDataTreeChangeListener<RemoteMcastMacs, DhcpMcastMacListener>
+        implements AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DhcpMcastMacListener.class);
+
+    private final DataBroker dataBroker;
+    private final DhcpExternalTunnelManager externalTunnelManager;
+    private final DhcpL2GwUtil dhcpL2GwUtil;
+    private final DhcpserviceConfig config;
+
+    @Inject
+    public DhcpMcastMacListener(DhcpExternalTunnelManager dhcpManager,
+                                DhcpL2GwUtil dhcpL2GwUtil,
+                                DataBroker dataBroker,
+                                final DhcpserviceConfig config) {
+        super(RemoteMcastMacs.class, DhcpMcastMacListener.class);
+        this.externalTunnelManager = dhcpManager;
+        this.dataBroker = dataBroker;
+        this.dhcpL2GwUtil = dhcpL2GwUtil;
+        this.config = config;
+    }
+
+    @PostConstruct
+    public void init() {
+        if (config.isControllerDhcpEnabled()) {
+            registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+        }
+    }
+
+    @PreDestroy
+    public void close() {
+        if (config.isControllerDhcpEnabled()) {
+            super.close();
+        }
+    }
+
+    @Override
+    protected void updated(InstanceIdentifier<RemoteMcastMacs> identifier,
+                           RemoteMcastMacs original, RemoteMcastMacs update) {
+    }
+
+    @Override
+    protected void added(InstanceIdentifier<RemoteMcastMacs> identifier,
+                         RemoteMcastMacs add) {
+        String elanInstanceName = getElanName(add);
+        IpAddress tunnelIp = dhcpL2GwUtil.getHwvtepNodeTunnelIp(identifier.firstIdentifierOf(Node.class));
+        if (tunnelIp == null) {
+            LOG.error("Could not find tunnelIp for {}", identifier);
+            return;
+        }
+        List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+        BigInteger designatedDpnId = externalTunnelManager.designateDpnId(tunnelIp, elanInstanceName, dpns);
+        if (designatedDpnId == null || designatedDpnId.equals(DhcpMConstants.INVALID_DPID)) {
+            LOG.error("Unable to designate a DPN for {}", identifier);
+        }
+    }
+
+    @Override
+    protected void removed(InstanceIdentifier<RemoteMcastMacs> identifier,
+                           RemoteMcastMacs del) {
+        String elanInstanceName = getElanName(del);
+        IpAddress tunnelIp = dhcpL2GwUtil.getHwvtepNodeTunnelIp(identifier.firstIdentifierOf(Node.class));
+        if (tunnelIp == null) {
+            LOG.error("Could not find tunnelIp for {}", identifier);
+            return;
+        }
+        BigInteger designatedDpnId = externalTunnelManager.readDesignatedSwitchesForExternalTunnel(
+                tunnelIp, elanInstanceName);
+        if (designatedDpnId == null) {
+            LOG.error("Could not find designated DPN ID elanInstanceName {}, tunnelIp {}", elanInstanceName, tunnelIp);
+            return;
+        }
+        externalTunnelManager.removeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
+    }
+
+    @Override
+    protected InstanceIdentifier<RemoteMcastMacs> getWildCardPath() {
+        return InstanceIdentifier.create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+                .child(Node.class).augmentation(HwvtepGlobalAugmentation.class)
+                .child(RemoteMcastMacs.class);
+    }
+
+    @Override
+    protected DhcpMcastMacListener getDataTreeChangeListener() {
+        return DhcpMcastMacListener.this;
+    }
+
+    String getElanName(RemoteMcastMacs mac) {
+        InstanceIdentifier<LogicalSwitches> logicalSwitchIid = (InstanceIdentifier<LogicalSwitches>)
+                mac.getLogicalSwitchRef().getValue();
+        return logicalSwitchIid.firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
+    }
+}
\ No newline at end of file