2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.vpnservice.dhcpservice;
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.HashSet;
14 import java.util.LinkedList;
15 import java.util.List;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
22 import org.apache.commons.lang3.tuple.ImmutablePair;
23 import org.apache.commons.lang3.tuple.Pair;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
29 import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
30 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
31 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
32 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
33 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
34 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
35 import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
36 import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
37 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
38 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
39 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.opendaylight.yangtools.yang.common.RpcResult;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
74 import com.google.common.base.Optional;
75 import com.google.common.util.concurrent.FutureCallback;
76 import com.google.common.util.concurrent.Futures;
77 import com.google.common.util.concurrent.ListenableFuture;
79 public class DhcpExternalTunnelManager {
81 private static final Logger logger = LoggerFactory.getLogger(DhcpExternalTunnelManager.class);
82 public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
83 private static final FutureCallback<Void> DEFAULT_CALLBACK =
84 new FutureCallback<Void>() {
86 public void onSuccess(Void result) {
87 logger.debug("Success in Datastore write operation");
90 public void onFailure(Throwable error) {
91 logger.error("Error in Datastore write operation", error);
94 private final DataBroker broker;
95 private IMdsalApiManager mdsalUtil;
97 private ConcurrentMap<BigInteger, List<Pair<IpAddress, String>>> designatedDpnsToTunnelIpElanNameCache = new ConcurrentHashMap<BigInteger, List<Pair<IpAddress, String>>>();
98 private ConcurrentMap<Pair<IpAddress, String>, Set<String>> tunnelIpElanNameToVmMacCache = new ConcurrentHashMap<Pair<IpAddress, String>, Set<String>>();
99 private ConcurrentMap<Pair<BigInteger, String>, Port> vniMacAddressToPortCache = new ConcurrentHashMap<Pair<BigInteger, String>, Port>();
100 private ItmRpcService itmRpcService;
101 private EntityOwnershipService entityOwnershipService;
103 public DhcpExternalTunnelManager(DataBroker broker, IMdsalApiManager mdsalUtil, ItmRpcService itmRpcService, EntityOwnershipService entityOwnershipService) {
104 this.broker = broker;
105 this.mdsalUtil = mdsalUtil;
106 this.itmRpcService = itmRpcService;
107 this.entityOwnershipService = entityOwnershipService;
111 private void initilizeCaches() {
112 logger.trace("Loading designatedDpnsToTunnelIpElanNameCache");
113 InstanceIdentifier<DesignatedSwitchesForExternalTunnels> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).build();
114 Optional<DesignatedSwitchesForExternalTunnels> designatedSwitchForTunnelOptional = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
115 if (designatedSwitchForTunnelOptional.isPresent()) {
116 List<DesignatedSwitchForTunnel> list = designatedSwitchForTunnelOptional.get().getDesignatedSwitchForTunnel();
117 for (DesignatedSwitchForTunnel designatedSwitchForTunnel : list) {
118 List<Pair<IpAddress, String>> listOfTunnelIpElanNamePair = designatedDpnsToTunnelIpElanNameCache.get(designatedSwitchForTunnel.getDpId());
119 if (listOfTunnelIpElanNamePair == null) {
120 listOfTunnelIpElanNamePair = new LinkedList<Pair<IpAddress, String>>();
122 Pair<IpAddress, String> tunnelIpElanNamePair = new ImmutablePair<IpAddress, String>(designatedSwitchForTunnel.getTunnelRemoteIpAddress(), designatedSwitchForTunnel.getElanInstanceName());
123 listOfTunnelIpElanNamePair.add(tunnelIpElanNamePair);
124 designatedDpnsToTunnelIpElanNameCache.put(BigInteger.valueOf(designatedSwitchForTunnel.getDpId()), listOfTunnelIpElanNamePair);
127 logger.trace("Loading vniMacAddressToPortCache");
128 InstanceIdentifier<Ports> inst = InstanceIdentifier.builder(Neutron.class).child(Ports.class).build();
129 Optional<Ports> optionalPorts = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
130 if (optionalPorts.isPresent()) {
131 List<Port> list = optionalPorts.get().getPort();
132 for (Port port : list) {
133 if(NeutronUtils.isPortVnicTypeNormal(port)) {
136 String macAddress = port.getMacAddress();
137 Uuid networkId = port.getNetworkId();
138 String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
139 if (segmentationId == null) {
142 updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, port);
149 public BigInteger designateDpnId(IpAddress tunnelIp,
150 String elanInstanceName, List<BigInteger> dpns) {
151 BigInteger designatedDpnId = readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
152 if (designatedDpnId != null && !designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
153 logger.trace("Dpn {} already designated for tunnelIp - elan : {} - {}", designatedDpnId, tunnelIp, elanInstanceName);
154 return designatedDpnId;
156 return chooseDpn(tunnelIp, elanInstanceName, dpns);
159 public void installDhcpFlowsForVms(IpAddress tunnelIp, String elanInstanceName, List<BigInteger> dpns,
160 BigInteger designatedDpnId, String vmMacAddress) {
161 installDhcpEntries(designatedDpnId, vmMacAddress, entityOwnershipService);
162 dpns.remove(designatedDpnId);
163 for (BigInteger dpn : dpns) {
164 installDhcpDropAction(dpn, vmMacAddress, entityOwnershipService);
166 updateLocalCache(tunnelIp, elanInstanceName, vmMacAddress);
169 public void installDhcpFlowsForVms(IpAddress tunnelIp,
170 String elanInstanceName, BigInteger designatedDpnId, Set<String> listVmMacAddress) {
171 for (String vmMacAddress : listVmMacAddress) {
172 installDhcpEntries(designatedDpnId, vmMacAddress);
176 public void unInstallDhcpFlowsForVms(String elanInstanceName, List<BigInteger> dpns, String vmMacAddress) {
177 for (BigInteger dpn : dpns) {
178 unInstallDhcpEntries(dpn, vmMacAddress, entityOwnershipService);
180 removeFromLocalCache(elanInstanceName, vmMacAddress);
183 public BigInteger readDesignatedSwitchesForExternalTunnel(IpAddress tunnelIp, String elanInstanceName) {
184 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp)).build();
185 Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
186 if (designatedSwitchForTunnelOptional.isPresent()) {
187 return BigInteger.valueOf(designatedSwitchForTunnelOptional.get().getDpId());
192 public void writeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp, String elanInstanceName) {
193 DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey = new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
194 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
195 DesignatedSwitchForTunnel designatedSwitchForTunnel = new DesignatedSwitchForTunnelBuilder().setDpId(dpnId.longValue()).setElanInstanceName(elanInstanceName).setTunnelRemoteIpAddress(tunnelIp).setKey(designatedSwitchForTunnelKey).build();
196 logger.trace("Writing into CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp, elanInstanceName, dpnId);
197 MDSALDataStoreUtils.asyncUpdate(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier, designatedSwitchForTunnel, DEFAULT_CALLBACK);
200 public void removeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp, String elanInstanceName) {
201 DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey = new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
202 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
203 logger.trace("Writing into CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp, elanInstanceName, dpnId);
204 MDSALDataStoreUtils.asyncRemove(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier, DEFAULT_CALLBACK);
207 public void installDhcpDropActionOnDpn(BigInteger dpId) {
208 List<String> vmMacs = getAllVmMacs();
209 logger.trace("Installing drop actions to this new DPN {} VMs {}", dpId, vmMacs);
210 for (String vmMacAddress : vmMacs) {
211 installDhcpDropAction(dpId, vmMacAddress);
215 private List<String> getAllVmMacs() {
216 List<String> vmMacs = new LinkedList<String>();
217 Collection<Set<String>> listOfVmMacs = tunnelIpElanNameToVmMacCache.values();
218 for (Set<String> list : listOfVmMacs) {
224 public void updateLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
225 Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
226 List<Pair<IpAddress, String>> tunnelIpElanNameList;
227 tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
228 if (tunnelIpElanNameList == null) {
229 tunnelIpElanNameList = new LinkedList<Pair<IpAddress, String>>();
231 tunnelIpElanNameList.add(tunnelIpElanName);
232 designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameList);
235 private void updateLocalCache(IpAddress tunnelIp, String elanInstanceName, String vmMacAddress) {
236 Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
237 Set<String> listExistingVmMacAddress;
238 listExistingVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanName);
239 if (listExistingVmMacAddress == null) {
240 listExistingVmMacAddress = new HashSet<String>();
242 listExistingVmMacAddress.add(vmMacAddress);
243 tunnelIpElanNameToVmMacCache.put(tunnelIpElanName, listExistingVmMacAddress);
246 public void handleDesignatedDpnDown(BigInteger dpnId, List<BigInteger> listOfDpns) {
247 logger.trace("In handleDesignatedDpnDown dpnId {}, listOfDpns {}", dpnId, listOfDpns);
249 List<Pair<IpAddress, String>> listOfTunnelIpElanNamePairs = designatedDpnsToTunnelIpElanNameCache.get(dpnId);
250 if (!dpnId.equals(DHCPMConstants.INVALID_DPID)) {
251 List<String> listOfVms = getAllVmMacs();
252 for (String vmMacAddress : listOfVms) {
253 unInstallDhcpEntries(dpnId, vmMacAddress);
256 if (listOfTunnelIpElanNamePairs == null || listOfTunnelIpElanNamePairs.isEmpty()) {
257 logger.trace("No tunnelIpElanName to handle for dpn {}. Returning", dpnId);
260 for (Pair<IpAddress, String> pair : listOfTunnelIpElanNamePairs) {
261 updateCacheAndInstallNewFlows(dpnId, listOfDpns, pair);
263 } catch (Exception e) {
264 logger.error("Error in handleDesignatedDpnDown {}", e);
268 public void updateCacheAndInstallNewFlows(BigInteger dpnId,
269 List<BigInteger> listOfDpns, Pair<IpAddress, String> pair)
270 throws ExecutionException {
271 BigInteger newDesignatedDpn = chooseDpn(pair.getLeft(), pair.getRight(), listOfDpns);
272 if (newDesignatedDpn.equals(DHCPMConstants.INVALID_DPID)) {
275 Set<String> listVmMacs = tunnelIpElanNameToVmMacCache.get(pair);
276 if (listVmMacs != null && !listVmMacs.isEmpty()) {
277 installDhcpFlowsForVms(pair.getLeft(), pair.getRight(), newDesignatedDpn, listVmMacs);
281 private void changeExistingFlowToDrop(Pair<IpAddress, String> tunnelIpElanNamePair, BigInteger dpnId) {
283 Set<String> listVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
284 if (listVmMacAddress == null || listVmMacAddress.isEmpty()) {
287 for (String vmMacAddress : listVmMacAddress) {
288 installDhcpDropAction(dpnId, vmMacAddress);
290 } catch (Exception e) {
291 logger.error("Error in uninstallExistingFlows {}", e);
296 * Choose a dpn among the list of elanDpns such that it has lowest count of being the designated dpn.
298 * @param elanInstanceName
302 private BigInteger chooseDpn(IpAddress tunnelIp, String elanInstanceName,
303 List<BigInteger> dpns) {
304 BigInteger designatedDpnId = DHCPMConstants.INVALID_DPID;
305 if (dpns != null && dpns.size() != 0) {
306 List<BigInteger> candidateDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
307 candidateDpns.retainAll(dpns);
308 logger.trace("Choosing new dpn for tunnelIp {}, elanInstanceName {}, among elanDpns {}", tunnelIp, elanInstanceName, candidateDpns);
309 boolean elanDpnAvailableFlag = true;
310 if (candidateDpns == null || candidateDpns.isEmpty()) {
311 candidateDpns = dpns;
312 elanDpnAvailableFlag = false;
315 L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
316 if (device == null) {
317 logger.trace("Could not find any device for elanInstanceName {} and tunnelIp {}", elanInstanceName, tunnelIp);
318 handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
319 return designatedDpnId;
321 for (BigInteger dpn : candidateDpns) {
322 String hwvtepNodeId = device.getHwvtepNodeId();
323 if (!elanDpnAvailableFlag) {
324 if (!isTunnelConfigured(dpn, hwvtepNodeId)) {
325 logger.trace("Tunnel is not configured on dpn {} to TOR {}", dpn, hwvtepNodeId);
328 } else if (!isTunnelUp(hwvtepNodeId, dpn)) {
329 logger.trace("Tunnel is not up between dpn {} and TOR {}", dpn, hwvtepNodeId);
332 List<Pair<IpAddress, String>> tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(dpn);
333 if (tunnelIpElanNameList == null) {
334 designatedDpnId = dpn;
337 if (size == 0 || tunnelIpElanNameList.size() < size) {
338 size = tunnelIpElanNameList.size();
339 designatedDpnId = dpn;
342 writeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
343 return designatedDpnId;
345 handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
346 return designatedDpnId;
349 private void handleUnableToDesignateDpn(IpAddress tunnelIp, String elanInstanceName) {
350 writeDesignatedSwitchForExternalTunnel(DHCPMConstants.INVALID_DPID, tunnelIp, elanInstanceName);
353 public void installDhcpEntries(BigInteger dpnId, String vmMacAddress) {
354 DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
357 public void installDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
358 final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
359 ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
360 eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
361 HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
362 Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
364 public void onSuccess(Boolean isOwner) {
366 installDhcpEntries(dpnId, vmMacAddress);
368 logger.trace("Exiting installDhcpEntries since this cluster node is not the owner for dpn {}", nodeId);
373 public void onFailure(Throwable error) {
374 logger.error("Error while fetching checkNodeEntityOwner", error);
379 public void unInstallDhcpEntries(BigInteger dpnId, String vmMacAddress) {
380 DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil);
383 public void unInstallDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
384 final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
385 ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
386 eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
387 HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
388 Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
390 public void onSuccess(Boolean isOwner) {
392 unInstallDhcpEntries(dpnId, vmMacAddress);
394 logger.trace("Exiting unInstallDhcpEntries since this cluster node is not the owner for dpn {}", nodeId);
399 public void onFailure(Throwable error) {
400 logger.error("Error while fetching checkNodeEntityOwner", error);
405 public void installDhcpDropAction(BigInteger dpn, String vmMacAddress) {
406 DhcpServiceUtils.setupDhcpDropAction(dpn, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
409 public void installDhcpDropAction(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
410 final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
411 ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
412 eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
413 HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
414 Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
416 public void onSuccess(Boolean isOwner) {
418 installDhcpDropAction(dpnId, vmMacAddress);
420 logger.trace("Exiting installDhcpDropAction since this cluster node is not the owner for dpn {}", nodeId);
425 public void onFailure(Throwable error) {
426 logger.error("Error while fetching checkNodeEntityOwner", error);
431 public void handleTunnelStateDown(IpAddress tunnelIp, BigInteger interfaceDpn) {
432 logger.trace("In handleTunnelStateDown tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
433 if (interfaceDpn == null) {
437 List<Pair<IpAddress, String>> tunnelElanPairList = designatedDpnsToTunnelIpElanNameCache.get(interfaceDpn);
438 if (tunnelElanPairList == null || tunnelElanPairList.isEmpty()) {
441 for (Pair<IpAddress, String> tunnelElanPair : tunnelElanPairList) {
442 IpAddress tunnelIpInDpn = tunnelElanPair.getLeft();
443 if (tunnelIpInDpn.equals(tunnelIp)) {
444 List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
445 dpns.remove(interfaceDpn);
446 changeExistingFlowToDrop(tunnelElanPair, interfaceDpn);
447 updateCacheAndInstallNewFlows(interfaceDpn, dpns, tunnelElanPair);
450 } catch (Exception e) {
451 logger.error("Error in handleTunnelStateDown {}", e.getMessage());
452 logger.trace("Exception details {}", e);
456 private void removeFromLocalCache(String elanInstanceName, String vmMacAddress) {
457 Set<Pair<IpAddress, String>> tunnelIpElanNameKeySet = tunnelIpElanNameToVmMacCache.keySet();
458 for (Pair<IpAddress, String> pair : tunnelIpElanNameKeySet) {
459 if (pair.getRight().trim().equalsIgnoreCase(elanInstanceName.trim())) {
460 Set<String> listExistingVmMacAddress;
461 listExistingVmMacAddress = tunnelIpElanNameToVmMacCache.get(pair);
462 if (listExistingVmMacAddress == null || listExistingVmMacAddress.isEmpty()) {
465 listExistingVmMacAddress.remove(vmMacAddress);
466 if (listExistingVmMacAddress.size() > 0) {
467 tunnelIpElanNameToVmMacCache.put(pair, listExistingVmMacAddress);
470 tunnelIpElanNameToVmMacCache.remove(pair);
475 public void removeFromLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
476 Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
477 List<Pair<IpAddress, String>> tunnelIpElanNameList;
478 tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
479 if (tunnelIpElanNameList != null) {
480 tunnelIpElanNameList.remove(tunnelIpElanName);
481 if (tunnelIpElanNameList.size() != 0) {
482 designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameList);
484 designatedDpnsToTunnelIpElanNameCache.remove(designatedDpnId);
489 public void updateVniMacToPortCache(BigInteger vni, String macAddress, Port port) {
490 if (macAddress == null) {
493 Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
494 logger.trace("Updating vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}", vni, macAddress.toUpperCase(), vniMacAddressPair, port);
495 vniMacAddressToPortCache.put(vniMacAddressPair, port);
498 public void removeVniMacToPortCache(BigInteger vni, String macAddress) {
499 if (macAddress == null) {
502 Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
503 vniMacAddressToPortCache.remove(vniMacAddressPair);
506 public Port readVniMacToPortCache(BigInteger vni, String macAddress) {
507 if (macAddress == null) {
510 Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
511 logger.trace("Reading vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}", vni, macAddress.toUpperCase(), vniMacAddressPair, vniMacAddressToPortCache.get(vniMacAddressPair));
512 return vniMacAddressToPortCache.get(vniMacAddressPair);
515 public String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
516 String tunnelInterfaceName = null;
517 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
519 Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
520 .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
521 .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
523 RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
524 if (rpcResult.isSuccessful()) {
525 tunnelInterfaceName = rpcResult.getResult().getInterfaceName();
526 logger.debug("Tunnel interface name: {}", tunnelInterfaceName);
528 logger.warn("RPC call to ITM.GetExternalTunnelInterfaceName failed with error: {}",
529 rpcResult.getErrors());
531 } catch (NullPointerException | InterruptedException | ExecutionException e) {
532 logger.error("Failed to get external tunnel interface name for sourceNode: {} and dstNode: {}: {} ",
533 sourceNode, dstNode, e);
535 return tunnelInterfaceName;
538 public static Optional<Node> getNode(DataBroker dataBroker, String physicalSwitchNodeId) {
539 InstanceIdentifier<Node> psNodeId = HwvtepSouthboundUtils
540 .createInstanceIdentifier(new NodeId(physicalSwitchNodeId));
541 Optional<Node> physicalSwitchOptional = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, psNodeId, dataBroker);
542 return physicalSwitchOptional;
545 public RemoteMcastMacs createRemoteMcastMac(Node dstDevice, String logicalSwitchName, IpAddress internalTunnelIp) {
546 List<LocatorSet> locators = new ArrayList<>();
547 for (TerminationPoint tp : dstDevice.getTerminationPoint()) {
548 HwvtepPhysicalLocatorAugmentation aug = tp.getAugmentation(HwvtepPhysicalLocatorAugmentation.class);
549 if (internalTunnelIp.getIpv4Address().equals(aug.getDstIp().getIpv4Address())) {
550 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
551 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(dstDevice.getNodeId(), aug));
552 locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
555 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
556 .createLogicalSwitchesInstanceIdentifier(dstDevice.getNodeId(), new HwvtepNodeName(logicalSwitchName)));
558 RemoteMcastMacs remoteUcastMacs = new RemoteMcastMacsBuilder()
559 .setMacEntryKey(new MacAddress(UNKNOWN_DMAC))
560 .setLogicalSwitchRef(lsRef).setLocatorSet(locators).build();
561 return remoteUcastMacs;
564 private WriteTransaction putRemoteMcastMac(WriteTransaction transaction, String elanName, L2GatewayDevice device, IpAddress internalTunnelIp) {
565 Optional<Node> optionalNode = getNode(broker, device.getHwvtepNodeId());
566 Node dstNode = optionalNode.get();
567 if (dstNode == null) {
568 logger.debug("could not get device node {} ", device.getHwvtepNodeId());
571 RemoteMcastMacs macs = createRemoteMcastMac(dstNode, elanName, internalTunnelIp);
572 HwvtepUtils.putRemoteMcastMac(transaction, dstNode.getNodeId(), macs);
576 public void installRemoteMcastMac(final BigInteger designatedDpnId, final IpAddress tunnelIp, final String elanInstanceName) {
577 if (designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
580 ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
581 Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
583 public void onSuccess(Boolean isOwner) {
585 logger.info("Installing remote McastMac");
586 L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
587 String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(designatedDpnId), device.getHwvtepNodeId());
588 IpAddress internalTunnelIp = null;
589 if (tunnelInterfaceName != null) {
590 Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
591 if (tunnelInterface == null) {
592 logger.trace("Tunnel Interface is not present {}", tunnelInterfaceName);
595 internalTunnelIp = tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource();
596 WriteTransaction transaction = broker.newWriteOnlyTransaction();
597 putRemoteMcastMac(transaction, elanInstanceName, device, internalTunnelIp);
598 if (transaction != null) {
599 transaction.submit();
603 logger.info("Installing remote McastMac is not executed for this node.");
608 public void onFailure(Throwable error) {
609 logger.error("Failed to install remote McastMac", error);
614 private L2GatewayDevice getDeviceFromTunnelIp(String elanInstanceName, IpAddress tunnelIp) {
615 ConcurrentMap<String, L2GatewayDevice> devices = L2GatewayCacheUtils.getCache();
616 for (L2GatewayDevice device : devices.values()) {
617 if (device.getTunnelIp().equals(tunnelIp)) {
624 private boolean isTunnelUp(String nodeName, BigInteger dpn) {
625 boolean isTunnelUp = false;
626 String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), nodeName);
627 if (tunnelInterfaceName == null) {
628 logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
631 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromOperationalDS(tunnelInterfaceName, broker);
632 if (tunnelInterface == null) {
633 logger.debug("Interface {} is not present in interface state", tunnelInterfaceName);
636 isTunnelUp = (tunnelInterface.getOperStatus() == OperStatus.Up) ? true :false;
640 public void handleTunnelStateUp(IpAddress tunnelIp, BigInteger interfaceDpn) {
641 logger.trace("In handleTunnelStateUp tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
643 List<Pair<IpAddress, String>> tunnelIpElanPair = designatedDpnsToTunnelIpElanNameCache.get(DHCPMConstants.INVALID_DPID);
644 List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
645 if (tunnelIpElanPair == null || tunnelIpElanPair.isEmpty()) {
648 for (Pair<IpAddress, String> pair : tunnelIpElanPair) {
649 if (tunnelIp.equals(pair.getLeft())) {
650 designateDpnId(tunnelIp, pair.getRight(), dpns);
653 } catch (Exception e) {
654 logger.error("Error in handleTunnelStateUp {}", e.getMessage());
655 logger.trace("Exception details {}", e);
659 private boolean isTunnelConfigured(BigInteger dpn, String hwVtepNodeId) {
660 String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), hwVtepNodeId);
661 if (tunnelInterfaceName == null) {
664 Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
665 if (tunnelInterface == null) {
666 logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
672 public void unInstallDhcpFlowsForVms(String elanInstanceName, IpAddress tunnelIp, List<BigInteger> dpns) {
673 Pair<IpAddress, String> tunnelIpElanNamePair = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
674 Set<String> vmMacs = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
675 logger.trace("In unInstallFlowsForVms elanInstanceName {}, tunnelIp {}, dpns {}, vmMacs {}", elanInstanceName, tunnelIp, dpns, vmMacs);
676 if (vmMacs == null) {
679 for (String vmMacAddress : vmMacs) {
680 for (BigInteger dpn : dpns) {
681 unInstallDhcpEntries(dpn, vmMacAddress, entityOwnershipService);
684 tunnelIpElanNameToVmMacCache.remove(tunnelIpElanNamePair);