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