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.netvirt.dhcpservice;
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.HashSet;
17 import java.util.LinkedList;
18 import java.util.List;
19 import java.util.Locale;
20 import java.util.Map.Entry;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ConcurrentMap;
24 import java.util.concurrent.CopyOnWriteArraySet;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.Future;
27 import javax.annotation.PostConstruct;
28 import javax.inject.Inject;
29 import javax.inject.Named;
30 import javax.inject.Singleton;
31 import org.apache.commons.lang3.tuple.ImmutablePair;
32 import org.apache.commons.lang3.tuple.Pair;
33 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
34 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
35 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
37 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
38 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
39 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
40 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
41 import org.opendaylight.genius.mdsalutil.MDSALUtil;
42 import org.opendaylight.genius.mdsalutil.NwConstants;
43 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
44 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
45 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
46 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
47 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
48 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
49 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
50 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
51 import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
52 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
53 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
54 import org.opendaylight.netvirt.elanmanager.api.IElanService;
55 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
56 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
57 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
58 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInputBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
88 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
89 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
90 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
91 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
92 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
93 import org.opendaylight.yangtools.yang.common.RpcResult;
94 import org.slf4j.Logger;
95 import org.slf4j.LoggerFactory;
98 public class DhcpExternalTunnelManager {
100 private static final Logger LOG = LoggerFactory.getLogger(DhcpExternalTunnelManager.class);
101 public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
103 private final DataBroker broker;
104 private final ManagedNewTransactionRunner txRunner;
105 private final IMdsalApiManager mdsalUtil;
106 private final ItmRpcService itmRpcService;
107 private final EntityOwnershipUtils entityOwnershipUtils;
108 private final IInterfaceManager interfaceManager;
109 private final JobCoordinator jobCoordinator;
110 private final L2GatewayCache l2GatewayCache;
111 private IElanService elanService;
113 private final ConcurrentMap<BigInteger, Set<Pair<IpAddress, String>>> designatedDpnsToTunnelIpElanNameCache =
114 new ConcurrentHashMap<>();
115 private final ConcurrentMap<Pair<IpAddress, String>, Set<String>> tunnelIpElanNameToVmMacCache =
116 new ConcurrentHashMap<>();
117 private final ConcurrentMap<Pair<IpAddress, String>, Set<String>> availableVMCache = new ConcurrentHashMap<>();
118 private final ConcurrentMap<Pair<BigInteger, String>, Port> vniMacAddressToPortCache = new ConcurrentHashMap<>();
121 public DhcpExternalTunnelManager(final DataBroker broker,
122 final IMdsalApiManager mdsalUtil, final ItmRpcService itmRpcService,
123 final EntityOwnershipService entityOwnershipService, final IInterfaceManager interfaceManager,
124 final JobCoordinator jobCoordinator, final L2GatewayCache l2GatewayCache,
125 @Named("elanService") IElanService ielanService) {
126 this.broker = broker;
127 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
128 this.mdsalUtil = mdsalUtil;
129 this.itmRpcService = itmRpcService;
130 this.entityOwnershipUtils = new EntityOwnershipUtils(entityOwnershipService);
131 this.interfaceManager = interfaceManager;
132 this.jobCoordinator = jobCoordinator;
133 this.l2GatewayCache = l2GatewayCache;
134 this.elanService = ielanService;
142 private void initilizeCaches() {
143 LOG.trace("Loading designatedDpnsToTunnelIpElanNameCache");
144 InstanceIdentifier<DesignatedSwitchesForExternalTunnels> instanceIdentifier =
145 InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).build();
146 Optional<DesignatedSwitchesForExternalTunnels> designatedSwitchForTunnelOptional =
147 MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
148 if (designatedSwitchForTunnelOptional.isPresent()) {
149 List<DesignatedSwitchForTunnel> list =
150 designatedSwitchForTunnelOptional.get().getDesignatedSwitchForTunnel();
151 for (DesignatedSwitchForTunnel designatedSwitchForTunnel : list) {
152 Set<Pair<IpAddress, String>> setOfTunnelIpElanNamePair =
153 designatedDpnsToTunnelIpElanNameCache
154 .get(BigInteger.valueOf(designatedSwitchForTunnel.getDpId()));
155 if (setOfTunnelIpElanNamePair == null) {
156 setOfTunnelIpElanNamePair = new CopyOnWriteArraySet<>();
158 Pair<IpAddress, String> tunnelIpElanNamePair =
159 new ImmutablePair<>(designatedSwitchForTunnel.getTunnelRemoteIpAddress(),
160 designatedSwitchForTunnel.getElanInstanceName());
161 setOfTunnelIpElanNamePair.add(tunnelIpElanNamePair);
162 designatedDpnsToTunnelIpElanNameCache.put(BigInteger.valueOf(designatedSwitchForTunnel.getDpId()),
163 setOfTunnelIpElanNamePair);
166 LOG.trace("Loading vniMacAddressToPortCache");
167 InstanceIdentifier<Ports> inst = InstanceIdentifier.builder(Neutron.class).child(Ports.class).build();
168 Optional<Ports> optionalPorts = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
169 if (optionalPorts.isPresent()) {
170 List<Port> list = optionalPorts.get().getPort();
171 for (Port port : list) {
172 if (NeutronUtils.isPortVnicTypeNormal(port)) {
175 String macAddress = port.getMacAddress().getValue();
176 Uuid networkId = port.getNetworkId();
177 String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
178 if (segmentationId == null) {
181 updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, port);
186 public BigInteger designateDpnId(IpAddress tunnelIp, String elanInstanceName, List<BigInteger> dpns) {
187 BigInteger designatedDpnId = readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
188 if (designatedDpnId != null && !designatedDpnId.equals(DhcpMConstants.INVALID_DPID)) {
189 LOG.trace("Dpn {} already designated for tunnelIp - elan : {} - {}", designatedDpnId, tunnelIp,
191 return designatedDpnId;
193 return chooseDpn(tunnelIp, elanInstanceName, dpns);
196 public void installDhcpFlowsForVms(final IpAddress tunnelIp, String elanInstanceName, final List<BigInteger> dpns,
197 final BigInteger designatedDpnId, final String vmMacAddress) {
198 LOG.trace("In installDhcpFlowsForVms ipAddress {}, elanInstanceName {}, dpn {}, vmMacAddress {}", tunnelIp,
199 elanInstanceName, designatedDpnId, vmMacAddress);
201 String tunnelIpDpnKey = getTunnelIpDpnKey(tunnelIp, designatedDpnId);
202 jobCoordinator.enqueueJob(getJobKey(tunnelIpDpnKey), () -> {
203 if (entityOwnershipUtils.isEntityOwner(HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
204 HwvtepSouthboundConstants.ELAN_ENTITY_NAME)) {
205 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
206 dpns.remove(designatedDpnId);
207 for (BigInteger dpn : dpns) {
208 installDhcpDropAction(dpn, vmMacAddress, tx);
210 installDhcpEntries(designatedDpnId, vmMacAddress, tx);
213 LOG.trace("Exiting installDhcpEntries since this cluster node is not the owner for dpn");
216 return Collections.emptyList();
219 updateLocalCache(tunnelIp, elanInstanceName, vmMacAddress);
222 public void installDhcpFlowsForVms(BigInteger designatedDpnId, Set<String> listVmMacAddress, WriteTransaction tx) {
223 for (String vmMacAddress : listVmMacAddress) {
224 installDhcpEntries(designatedDpnId, vmMacAddress, tx);
228 public void unInstallDhcpFlowsForVms(String elanInstanceName, List<BigInteger> dpns, String vmMacAddress) {
229 unInstallDhcpEntriesOnDpns(dpns, vmMacAddress);
230 removeFromLocalCache(elanInstanceName, vmMacAddress);
233 public void unInstallDhcpFlowsForVms(String elanInstanceName, IpAddress tunnelIp, List<BigInteger> dpns) {
234 Pair<IpAddress, String> tunnelIpElanNamePair = new ImmutablePair<>(tunnelIp, elanInstanceName);
235 Set<String> vmMacs = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
236 LOG.trace("In unInstallFlowsForVms elanInstanceName {}, tunnelIp {}, dpns {}, vmMacs {}",
237 elanInstanceName, tunnelIp, dpns, vmMacs);
238 if (vmMacs == null) {
241 for (String vmMacAddress : vmMacs) {
242 unInstallDhcpEntriesOnDpns(dpns, vmMacAddress);
244 tunnelIpElanNameToVmMacCache.remove(tunnelIpElanNamePair);
247 public BigInteger readDesignatedSwitchesForExternalTunnel(IpAddress tunnelIp, String elanInstanceName) {
248 if (tunnelIp == null || elanInstanceName == null || elanInstanceName.isEmpty()) {
251 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier =
252 InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class)
253 .child(DesignatedSwitchForTunnel.class,
254 new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp)).build();
255 Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional =
256 MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
257 if (designatedSwitchForTunnelOptional.isPresent()) {
258 return BigInteger.valueOf(designatedSwitchForTunnelOptional.get().getDpId());
263 public void writeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp,
264 String elanInstanceName) {
265 DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey =
266 new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
267 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier =
268 InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class)
269 .child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
270 DesignatedSwitchForTunnel designatedSwitchForTunnel =
271 new DesignatedSwitchForTunnelBuilder().setDpId(dpnId.longValue())
272 .setElanInstanceName(elanInstanceName).setTunnelRemoteIpAddress(tunnelIp)
273 .setKey(designatedSwitchForTunnelKey).build();
274 LOG.trace("Writing into CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp, elanInstanceName,
276 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier, designatedSwitchForTunnel);
277 updateLocalCache(dpnId, tunnelIp, elanInstanceName);
280 public void removeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp,
281 String elanInstanceName) {
282 DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey =
283 new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
284 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier =
285 InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class)
286 .child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
287 LOG.trace("Removing from CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp,
288 elanInstanceName, dpnId);
289 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
290 removeFromLocalCache(dpnId, tunnelIp, elanInstanceName);
293 // This method is called whenever new OVS Switch is added.
294 public void installDhcpDropActionOnDpn(BigInteger dpId) {
295 // During controller restart we'll get add for designatedDpns as well and we
296 // need not install drop flows for those dpns
297 if (designatedDpnsToTunnelIpElanNameCache.get(dpId) != null) {
298 LOG.trace("The dpn {} is designated DPN need not install drop flows");
301 // Read from DS since the cache may not get loaded completely in restart scenario
302 if (isDpnDesignatedDpn(dpId)) {
303 LOG.trace("The dpn {} is designated DPN need not install drop flows");
306 List<String> vmMacs = getAllVmMacs();
307 LOG.trace("Installing drop actions to this new DPN {} VMs {}", dpId, vmMacs);
308 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
309 for (String vmMacAddress : vmMacs) {
310 installDhcpDropAction(dpId, vmMacAddress, tx);
312 }), LOG, "Error writing to the datastore");
315 private boolean isDpnDesignatedDpn(BigInteger dpId) {
316 InstanceIdentifier<DesignatedSwitchesForExternalTunnels> instanceIdentifier =
317 InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).build();
318 Optional<DesignatedSwitchesForExternalTunnels> designatedSwitchForTunnelOptional =
319 MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
320 if (designatedSwitchForTunnelOptional.isPresent()) {
321 List<DesignatedSwitchForTunnel> list =
322 designatedSwitchForTunnelOptional.get().getDesignatedSwitchForTunnel();
323 for (DesignatedSwitchForTunnel designatedSwitchForTunnel : list) {
324 if (dpId.equals(BigInteger.valueOf(designatedSwitchForTunnel.getDpId()))) {
332 private List<String> getAllVmMacs() {
333 List<String> vmMacs = new LinkedList<>();
334 Collection<Set<String>> listOfVmMacs = tunnelIpElanNameToVmMacCache.values();
335 for (Set<String> list : listOfVmMacs) {
341 public void updateLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
342 Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<>(tunnelIp, elanInstanceName);
343 Set<Pair<IpAddress, String>> tunnelIpElanNameSet;
344 tunnelIpElanNameSet = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
345 if (tunnelIpElanNameSet == null) {
346 tunnelIpElanNameSet = new CopyOnWriteArraySet<>();
348 tunnelIpElanNameSet.add(tunnelIpElanName);
349 LOG.trace("Updating designatedDpnsToTunnelIpElanNameCache for designatedDpn {} value {}", designatedDpnId,
350 tunnelIpElanNameSet);
351 designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameSet);
354 public void updateLocalCache(IpAddress tunnelIp, String elanInstanceName, String vmMacAddress) {
355 Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<>(tunnelIp, elanInstanceName);
356 Set<String> setOfExistingVmMacAddress;
357 setOfExistingVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanName);
358 if (setOfExistingVmMacAddress == null) {
359 setOfExistingVmMacAddress = new CopyOnWriteArraySet<>();
361 setOfExistingVmMacAddress.add(vmMacAddress);
362 LOG.trace("Updating tunnelIpElanNameToVmMacCache for tunnelIpElanName {} value {}", tunnelIpElanName,
363 setOfExistingVmMacAddress);
364 tunnelIpElanNameToVmMacCache.put(tunnelIpElanName, setOfExistingVmMacAddress);
365 updateExistingVMTunnelIPCache(tunnelIp, elanInstanceName, vmMacAddress);
368 public void updateExistingVMTunnelIPCache(IpAddress tunnelIp, String elanInstanceName, String vmMacAddress) {
369 Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<>(tunnelIp, elanInstanceName);
370 Set<String> listExistingVmMacAddress;
371 listExistingVmMacAddress = availableVMCache.get(tunnelIpElanName);
372 if (listExistingVmMacAddress == null) {
373 listExistingVmMacAddress = new CopyOnWriteArraySet<>();
375 listExistingVmMacAddress.add(vmMacAddress);
376 LOG.trace("Updating availableVMCache for tunnelIpElanName {} value {}", tunnelIpElanName,
377 listExistingVmMacAddress);
378 availableVMCache.put(tunnelIpElanName, listExistingVmMacAddress);
381 public void handleDesignatedDpnDown(BigInteger dpnId, List<BigInteger> listOfDpns) {
382 LOG.trace("In handleDesignatedDpnDown dpnId {}, listOfDpns {}", dpnId, listOfDpns);
383 Set<Pair<IpAddress, String>> setOfTunnelIpElanNamePairs = designatedDpnsToTunnelIpElanNameCache.get(dpnId);
384 if (setOfTunnelIpElanNamePairs == null || setOfTunnelIpElanNamePairs.isEmpty()) {
385 LOG.trace("No tunnelIpElanName to handle for dpn {}. Returning", dpnId);
387 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
388 if (!dpnId.equals(DhcpMConstants.INVALID_DPID)) {
389 List<String> listOfVms = getAllVmMacs();
390 for (String vmMacAddress : listOfVms) {
391 unInstallDhcpEntries(dpnId, vmMacAddress, tx);
394 for (Pair<IpAddress, String> pair : setOfTunnelIpElanNamePairs) {
395 updateCacheAndInstallNewFlows(listOfDpns, pair, tx);
397 }), LOG, "Error writing to datastore");
401 public void updateCacheAndInstallNewFlows(List<BigInteger> listOfDpns, Pair<IpAddress, String> pair,
402 WriteTransaction tx) {
403 BigInteger newDesignatedDpn = chooseDpn(pair.getLeft(), pair.getRight(), listOfDpns);
404 if (newDesignatedDpn.equals(DhcpMConstants.INVALID_DPID)) {
407 Set<String> setOfVmMacs = tunnelIpElanNameToVmMacCache.get(pair);
408 if (setOfVmMacs != null && !setOfVmMacs.isEmpty()) {
409 LOG.trace("Updating DHCP flows for VMs {} with new designated DPN {}", setOfVmMacs, newDesignatedDpn);
410 installDhcpFlowsForVms(newDesignatedDpn, setOfVmMacs, tx);
412 java.util.Optional<SubnetToDhcpPort> subnetDhcpData = getSubnetDhcpPortData(pair.getRight());
413 if (subnetDhcpData.isPresent()) {
414 configureDhcpArpRequestResponseFlow(newDesignatedDpn, pair.getRight(), true,
415 pair.getLeft(), subnetDhcpData.get().getPortFixedip(), subnetDhcpData.get().getPortMacaddress());
419 private void changeExistingFlowToDrop(Pair<IpAddress, String> tunnelIpElanNamePair, BigInteger dpnId,
420 WriteTransaction tx) {
421 Set<String> setOfVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
422 if (setOfVmMacAddress == null || setOfVmMacAddress.isEmpty()) {
425 for (String vmMacAddress : setOfVmMacAddress) {
426 installDhcpDropAction(dpnId, vmMacAddress, tx);
431 * Choose a dpn among the list of elanDpns such that it has lowest count of being the designated dpn.
432 * @param tunnelIp The tunnel Ip address
433 * @param elanInstanceName The elan instance name
434 * @param dpns The data path nodes
435 * @return The designated dpn
437 private BigInteger chooseDpn(IpAddress tunnelIp, String elanInstanceName,
438 List<BigInteger> dpns) {
439 BigInteger designatedDpnId = DhcpMConstants.INVALID_DPID;
440 if (dpns != null && dpns.size() != 0) {
441 List<BigInteger> candidateDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
442 candidateDpns.retainAll(dpns);
443 LOG.trace("Choosing new dpn for tunnelIp {}, elanInstanceName {}, among elanDpns {}",
444 tunnelIp, elanInstanceName, candidateDpns);
445 boolean elanDpnAvailableFlag = true;
446 if (candidateDpns.isEmpty()) {
447 candidateDpns = dpns;
448 elanDpnAvailableFlag = false;
451 L2GatewayDevice device = getDeviceFromTunnelIp(tunnelIp);
452 if (device == null) {
453 LOG.trace("Could not find any device for elanInstanceName {} and tunnelIp {}",
454 elanInstanceName, tunnelIp);
455 handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
456 return designatedDpnId;
458 for (BigInteger dpn : candidateDpns) {
459 String hwvtepNodeId = device.getHwvtepNodeId();
460 if (!elanDpnAvailableFlag) {
461 if (!isTunnelConfigured(dpn, hwvtepNodeId)) {
462 LOG.trace("Tunnel is not configured on dpn {} to TOR {}", dpn, hwvtepNodeId);
465 } else if (!isTunnelUp(hwvtepNodeId, dpn)) {
466 LOG.trace("Tunnel is not up between dpn {} and TOR {}", dpn, hwvtepNodeId);
469 Set<Pair<IpAddress, String>> tunnelIpElanNameSet = designatedDpnsToTunnelIpElanNameCache.get(dpn);
470 if (tunnelIpElanNameSet == null) {
471 designatedDpnId = dpn;
474 if (size == 0 || tunnelIpElanNameSet.size() < size) {
475 size = tunnelIpElanNameSet.size();
476 designatedDpnId = dpn;
479 writeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
480 return designatedDpnId;
482 handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
483 return designatedDpnId;
486 private void handleUnableToDesignateDpn(IpAddress tunnelIp, String elanInstanceName) {
487 writeDesignatedSwitchForExternalTunnel(DhcpMConstants.INVALID_DPID, tunnelIp, elanInstanceName);
490 private void installDhcpEntries(BigInteger dpnId, String vmMacAddress, WriteTransaction tx) {
491 DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL,
492 vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil, tx);
495 public void addOrRemoveDhcpArpFlowforElan(String elanInstanceName, boolean addFlow, String dhcpIpAddress,
496 String dhcpMacAddress) {
497 LOG.trace("Configure DHCP SR-IOV Arp flows for Elan {} dpns .", elanInstanceName);
498 for (Entry<BigInteger, Set<Pair<IpAddress,String>>> entry : designatedDpnsToTunnelIpElanNameCache.entrySet()) {
499 BigInteger dpn = entry.getKey();
500 Set<Pair<IpAddress,String>> tunnelIpElanNameSet = entry.getValue();
501 for (Pair<IpAddress, String> pair : tunnelIpElanNameSet) {
502 if (pair.getRight().equalsIgnoreCase(elanInstanceName)) {
504 LOG.trace("Adding SR-IOV DHCP Arp Flows for Elan {} and tunnelIp {}",
505 elanInstanceName, pair.getLeft());
506 configureDhcpArpRequestResponseFlow(dpn, elanInstanceName, true,
507 pair.getLeft(), dhcpIpAddress, dhcpMacAddress);
509 LOG.trace("Deleting SR-IOV DHCP Arp Flows for Elan {} and tunnelIp {}",
510 elanInstanceName, pair.getLeft());
511 configureDhcpArpRequestResponseFlow(dpn, elanInstanceName, false,
512 pair.getLeft(), dhcpIpAddress, dhcpMacAddress);
520 public void configureDhcpArpRequestResponseFlow(BigInteger dpnId, String elanInstanceName, boolean addFlow,
521 IpAddress tunnelIp, String dhcpIpAddress, String dhcpMacAddress) {
522 L2GatewayDevice device = getDeviceFromTunnelIp(tunnelIp);
523 if (device == null) {
524 LOG.error("Unable to get L2Device for tunnelIp {} and elanInstanceName {}", tunnelIp,
527 jobCoordinator.enqueueJob(getJobKey(elanInstanceName), () -> {
528 if (entityOwnershipUtils.isEntityOwner(HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
529 HwvtepSouthboundConstants.ELAN_ENTITY_NAME)) {
530 String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpnId),
531 device.getHwvtepNodeId());
532 int lportTag = interfaceManager.getInterfaceInfo(tunnelInterfaceName).getInterfaceTag();
533 InstanceIdentifier<ElanInstance> elanIdentifier = InstanceIdentifier.builder(ElanInstances.class)
534 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
535 Optional<ElanInstance> optElan = MDSALUtil.read(broker,
536 LogicalDatastoreType.CONFIGURATION, elanIdentifier);
537 if (optElan.isPresent()) {
538 LOG.trace("Configuring the SR-IOV Arp request/response flows for LPort {} ElanTag {}.",
539 lportTag, optElan.get().getElanTag());
540 Uuid nwUuid = new Uuid(elanInstanceName);
541 String strVni = DhcpServiceUtils.getSegmentationId(nwUuid, broker);
542 BigInteger vni = strVni != null ? new BigInteger(strVni) : BigInteger.ZERO;
543 if (!vni.equals(BigInteger.ZERO)) {
545 LOG.trace("Installing the SR-IOV DHCP Arp flow for DPN {} Port Ip {}, Lport {}.",
546 dpnId, dhcpIpAddress, lportTag);
547 installDhcpArpRequestFlows(dpnId, vni, dhcpIpAddress, lportTag,
548 optElan.get().getElanTag());
549 installDhcpArpResponderFlows(dpnId, tunnelInterfaceName, lportTag, elanInstanceName,
550 dhcpIpAddress, dhcpMacAddress);
552 LOG.trace("Uninstalling the SR-IOV DHCP Arp flows for DPN {} Port Ip {}, Lport {}.",
553 dpnId, dhcpIpAddress, lportTag);
554 uninstallDhcpArpRequestFlows(dpnId, vni, dhcpIpAddress, lportTag);
555 uninstallDhcpArpResponderFlows(dpnId, tunnelInterfaceName, lportTag, dhcpIpAddress);
564 public java.util.Optional<SubnetToDhcpPort> getSubnetDhcpPortData(String elanInstanceName) {
565 java.util.Optional<SubnetToDhcpPort> optSubnetDhcp = java.util.Optional.empty();
566 Uuid nwUuid = new Uuid(elanInstanceName);
567 List<Uuid> subnets = DhcpServiceUtils.getSubnetIdsFromNetworkId(broker, nwUuid);
568 for (Uuid subnet : subnets) {
569 if (DhcpServiceUtils.isIpv4Subnet(broker, subnet)) {
570 optSubnetDhcp = DhcpServiceUtils.getSubnetDhcpPortData(broker, subnet.getValue());
571 return optSubnetDhcp;
574 return optSubnetDhcp;
577 private void installDhcpArpRequestFlows(BigInteger dpnId, BigInteger vni, String dhcpIpAddress,
578 int lportTag, Long elanTag) {
579 DhcpServiceUtils.setupDhcpArpRequest(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE, vni, dhcpIpAddress,
580 lportTag, elanTag, true, mdsalUtil);
583 private void installDhcpArpResponderFlows(BigInteger dpnId, String interfaceName, int lportTag,
584 String elanInstanceName, String dhcpIpAddress, String dhcpMacAddress) {
585 LOG.trace("Adding SR-IOV DHCP ArpResponder for elan {} Lport {} Port Ip {}.",
586 elanInstanceName, lportTag, dhcpIpAddress);
587 ArpResponderInput.ArpReponderInputBuilder builder = new ArpResponderInput.ArpReponderInputBuilder();
588 builder.setDpId(dpnId).setInterfaceName(interfaceName).setSpa(dhcpIpAddress).setSha(dhcpMacAddress)
589 .setLportTag(lportTag);
590 builder.setInstructions(ArpResponderUtil.getInterfaceInstructions(interfaceManager, interfaceName,
591 dhcpIpAddress, dhcpMacAddress));
592 elanService.addExternalTunnelArpResponderFlow(builder.buildForInstallFlow(), elanInstanceName);
595 private void uninstallDhcpArpResponderFlows(BigInteger dpnId, String interfaceName, int lportTag,
596 String dhcpIpAddress) {
597 LOG.trace("Removing SR-IOV DHCP ArpResponder flow for interface {} on DPN {}", interfaceName, dpnId);
598 ArpResponderInput arpInput = new ArpResponderInput.ArpReponderInputBuilder().setDpId(dpnId)
599 .setInterfaceName(interfaceName).setSpa(dhcpIpAddress)
600 .setLportTag(lportTag).buildForRemoveFlow();
601 elanService.removeArpResponderFlow(arpInput);
604 private void uninstallDhcpArpRequestFlows(BigInteger dpnId, BigInteger vni, String dhcpIpAddress,
606 DhcpServiceUtils.setupDhcpArpRequest(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE, vni, dhcpIpAddress,
607 lportTag, null, false, mdsalUtil);
611 public void unInstallDhcpEntries(BigInteger dpnId, String vmMacAddress, WriteTransaction tx) {
612 DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL,
613 vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil, tx);
616 private void installDhcpDropAction(BigInteger dpn, String vmMacAddress, WriteTransaction tx) {
617 DhcpServiceUtils.setupDhcpDropAction(dpn, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL,
618 vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil, tx);
621 public List<ListenableFuture<Void>> handleTunnelStateDown(IpAddress tunnelIp, BigInteger interfaceDpn) {
622 LOG.trace("In handleTunnelStateDown tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
623 if (interfaceDpn == null) {
624 return Collections.emptyList();
626 synchronized (getTunnelIpDpnKey(tunnelIp, interfaceDpn)) {
627 Set<Pair<IpAddress, String>> tunnelElanPairSet =
628 designatedDpnsToTunnelIpElanNameCache.get(interfaceDpn);
629 if (tunnelElanPairSet == null || tunnelElanPairSet.isEmpty()) {
630 return Collections.emptyList();
632 for (Pair<IpAddress, String> tunnelElanPair : tunnelElanPairSet) {
633 IpAddress tunnelIpInDpn = tunnelElanPair.getLeft();
634 if (tunnelIpInDpn.equals(tunnelIp)) {
635 if (!checkL2GatewayConnection(tunnelElanPair)) {
636 LOG.trace("Couldn't find device for given tunnelIpElanPair {} in L2GwConnCache",
638 return Collections.emptyList();
642 return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
643 for (Pair<IpAddress, String> tunnelElanPair : tunnelElanPairSet) {
644 IpAddress tunnelIpInDpn = tunnelElanPair.getLeft();
645 String elanInstanceName = tunnelElanPair.getRight();
646 if (tunnelIpInDpn.equals(tunnelIp)) {
647 if (!checkL2GatewayConnection(tunnelElanPair)) {
648 LOG.trace("Couldn't find device for given tunnelIpElanPair {} in L2GwConnCache",
651 List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
652 dpns.remove(interfaceDpn);
653 changeExistingFlowToDrop(tunnelElanPair, interfaceDpn, tx);
654 java.util.Optional<SubnetToDhcpPort> subnetDhcpData = getSubnetDhcpPortData(elanInstanceName);
655 if (subnetDhcpData.isPresent()) {
656 configureDhcpArpRequestResponseFlow(interfaceDpn, elanInstanceName, false,
657 tunnelIpInDpn, subnetDhcpData.get().getPortFixedip(),
658 subnetDhcpData.get().getPortMacaddress());
660 updateCacheAndInstallNewFlows(dpns, tunnelElanPair, tx);
667 private boolean checkL2GatewayConnection(Pair<IpAddress, String> tunnelElanPair) {
668 ConcurrentMap<String, L2GatewayDevice> l2GwDevices =
669 ElanL2GwCacheUtils.getInvolvedL2GwDevices(tunnelElanPair.getRight());
670 for (L2GatewayDevice device : l2GwDevices.values()) {
671 if (device.getTunnelIp().equals(tunnelElanPair.getLeft())) {
678 private String getTunnelIpDpnKey(IpAddress tunnelIp, BigInteger interfaceDpn) {
679 return tunnelIp.toString() + interfaceDpn;
682 private void removeFromLocalCache(String elanInstanceName, String vmMacAddress) {
683 for (Entry<Pair<IpAddress, String>, Set<String>> entry : tunnelIpElanNameToVmMacCache.entrySet()) {
684 Pair<IpAddress, String> pair = entry.getKey();
685 if (pair.getRight().trim().equalsIgnoreCase(elanInstanceName.trim())) {
686 Set<String> setOfExistingVmMacAddress = entry.getValue();
687 if (setOfExistingVmMacAddress == null || setOfExistingVmMacAddress.isEmpty()) {
690 LOG.trace("Removing vmMacAddress {} from listOfMacs {} for elanInstanceName {}", vmMacAddress,
691 setOfExistingVmMacAddress, elanInstanceName);
692 setOfExistingVmMacAddress.remove(vmMacAddress);
693 if (setOfExistingVmMacAddress.size() > 0) {
694 tunnelIpElanNameToVmMacCache.put(pair, setOfExistingVmMacAddress);
697 tunnelIpElanNameToVmMacCache.remove(pair);
702 public void removeFromLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
703 Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<>(tunnelIp, elanInstanceName);
704 Set<Pair<IpAddress, String>> tunnelIpElanNameSet;
705 tunnelIpElanNameSet = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
706 if (tunnelIpElanNameSet != null) {
707 LOG.trace("Removing tunnelIpElan {} from designatedDpnsToTunnelIpElanNameCache. Existing list {} for "
708 + "designatedDpnId {}",
709 tunnelIpElanName, tunnelIpElanNameSet, designatedDpnId);
710 tunnelIpElanNameSet.remove(tunnelIpElanName);
711 if (tunnelIpElanNameSet.size() != 0) {
712 designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameSet);
714 designatedDpnsToTunnelIpElanNameCache.remove(designatedDpnId);
719 public void updateVniMacToPortCache(BigInteger vni, String macAddress, Port port) {
720 if (macAddress == null) {
723 Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<>(
724 vni, macAddress.toUpperCase(Locale.getDefault()));
725 LOG.trace("Updating vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}", vni,
726 macAddress.toUpperCase(Locale.getDefault()), vniMacAddressPair, port);
727 vniMacAddressToPortCache.put(vniMacAddressPair, port);
730 public void removeVniMacToPortCache(BigInteger vni, String macAddress) {
731 if (macAddress == null) {
734 Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<>(
735 vni, macAddress.toUpperCase(Locale.getDefault()));
736 vniMacAddressToPortCache.remove(vniMacAddressPair);
739 public Port readVniMacToPortCache(BigInteger vni, String macAddress) {
740 if (macAddress == null) {
743 Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<>(
744 vni, macAddress.toUpperCase(Locale.getDefault()));
745 LOG.trace("Reading vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}",
746 vni, macAddress.toUpperCase(Locale.getDefault()), vniMacAddressPair,
747 vniMacAddressToPortCache.get(vniMacAddressPair));
748 return vniMacAddressToPortCache.get(vniMacAddressPair);
751 public String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
752 String tunnelInterfaceName = null;
753 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
755 Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
756 .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
757 .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
759 RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
760 if (rpcResult.isSuccessful()) {
761 tunnelInterfaceName = rpcResult.getResult().getInterfaceName();
762 LOG.trace("Tunnel interface name: {}", tunnelInterfaceName);
764 LOG.warn("RPC call to ITM.GetExternalTunnelInterfaceName failed with error: {}", rpcResult.getErrors());
766 } catch (NullPointerException | InterruptedException | ExecutionException e) {
767 LOG.error("Failed to get external tunnel interface name for sourceNode: {} and dstNode: {}",
768 sourceNode, dstNode, e);
770 return tunnelInterfaceName;
773 public static Optional<Node> getNode(DataBroker dataBroker, String physicalSwitchNodeId) {
774 InstanceIdentifier<Node> psNodeId = HwvtepSouthboundUtils
775 .createInstanceIdentifier(new NodeId(physicalSwitchNodeId));
776 return MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, psNodeId, dataBroker);
779 public RemoteMcastMacs createRemoteMcastMac(Node dstDevice, String logicalSwitchName, IpAddress internalTunnelIp) {
780 Set<LocatorSet> locators = new HashSet<>();
781 TerminationPointKey terminationPointKey = HwvtepSouthboundUtils.getTerminationPointKey(
782 internalTunnelIp.getIpv4Address().getValue());
783 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
784 HwvtepSouthboundUtils.createInstanceIdentifier(dstDevice.getNodeId()).child(TerminationPoint.class,
785 terminationPointKey));
786 locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
788 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
789 .createLogicalSwitchesInstanceIdentifier(dstDevice.getNodeId(), new HwvtepNodeName(logicalSwitchName)));
791 RemoteMcastMacs remoteMcastMacs = new RemoteMcastMacsBuilder()
792 .setMacEntryKey(new MacAddress(UNKNOWN_DMAC))
793 .setLogicalSwitchRef(lsRef).build();
794 InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(
795 dstDevice.getNodeId(), remoteMcastMacs.getKey());
796 ReadOnlyTransaction transaction = broker.newReadOnlyTransaction();
798 //TODO do async mdsal read
799 remoteMcastMacs = transaction.read(LogicalDatastoreType.CONFIGURATION, iid).checkedGet().get();
800 locators.addAll(remoteMcastMacs.getLocatorSet());
801 return new RemoteMcastMacsBuilder(remoteMcastMacs).setLocatorSet(new ArrayList<>(locators)).build();
802 } catch (ReadFailedException e) {
803 LOG.error("Failed to read the macs {}", iid);
808 private WriteTransaction putRemoteMcastMac(WriteTransaction transaction, String elanName,
809 L2GatewayDevice device, IpAddress internalTunnelIp) {
810 Optional<Node> optionalNode = getNode(broker, device.getHwvtepNodeId());
811 Node dstNode = optionalNode.get();
812 if (dstNode == null) {
813 LOG.trace("could not get device node {} ", device.getHwvtepNodeId());
816 RemoteMcastMacs macs = createRemoteMcastMac(dstNode, elanName, internalTunnelIp);
817 HwvtepUtils.putRemoteMcastMac(transaction, dstNode.getNodeId(), macs);
821 public void installRemoteMcastMac(final BigInteger designatedDpnId, final IpAddress tunnelIp,
822 final String elanInstanceName) {
823 if (designatedDpnId.equals(DhcpMConstants.INVALID_DPID)) {
827 jobCoordinator.enqueueJob(getJobKey(elanInstanceName), () -> {
828 if (!entityOwnershipUtils.isEntityOwner(HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
829 HwvtepSouthboundConstants.ELAN_ENTITY_NAME)) {
830 LOG.info("Installing remote McastMac is not executed for this node.");
831 return Collections.emptyList();
834 LOG.info("Installing remote McastMac");
835 L2GatewayDevice device = getDeviceFromTunnelIp(tunnelIp);
836 if (device == null) {
837 LOG.error("Unable to get L2Device for tunnelIp {} and elanInstanceName {}", tunnelIp,
839 return Collections.emptyList();
841 String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(designatedDpnId),
842 device.getHwvtepNodeId());
843 if (tunnelInterfaceName != null) {
844 Interface tunnelInterface =
845 interfaceManager.getInterfaceInfoFromConfigDataStore(tunnelInterfaceName);
846 if (tunnelInterface == null) {
847 LOG.trace("Tunnel Interface is not present {}", tunnelInterfaceName);
848 return Collections.emptyList();
850 return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(
851 tx -> putRemoteMcastMac(tx, elanInstanceName, device,
852 tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource())));
854 return Collections.emptyList();
858 private L2GatewayDevice getDeviceFromTunnelIp(IpAddress tunnelIp) {
859 Collection<L2GatewayDevice> devices = l2GatewayCache.getAll();
860 LOG.trace("In getDeviceFromTunnelIp devices {}", devices);
861 for (L2GatewayDevice device : devices) {
862 if (tunnelIp.equals(device.getTunnelIp())) {
869 private boolean isTunnelUp(String nodeName, BigInteger dpn) {
870 String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), nodeName);
871 if (tunnelInterfaceName == null) {
872 LOG.trace("Tunnel Interface is not present on node {} with dpn {}", nodeName, dpn);
875 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
876 .Interface tunnelInterface =
877 DhcpServiceUtils.getInterfaceFromOperationalDS(tunnelInterfaceName, broker);
878 if (tunnelInterface == null) {
879 LOG.trace("Interface {} is not present in interface state", tunnelInterfaceName);
882 return tunnelInterface.getOperStatus() == OperStatus.Up;
885 public List<ListenableFuture<Void>> handleTunnelStateUp(IpAddress tunnelIp, BigInteger interfaceDpn) {
886 LOG.trace("In handleTunnelStateUp tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
887 synchronized (getTunnelIpDpnKey(tunnelIp, interfaceDpn)) {
888 Set<Pair<IpAddress, String>> tunnelIpElanPair =
889 designatedDpnsToTunnelIpElanNameCache.get(DhcpMConstants.INVALID_DPID);
890 List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
891 if (tunnelIpElanPair == null || tunnelIpElanPair.isEmpty()) {
892 LOG.trace("There are no undesignated DPNs");
893 return Collections.emptyList();
895 return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
896 for (Pair<IpAddress, String> pair : tunnelIpElanPair) {
897 if (tunnelIp.equals(pair.getLeft())) {
898 String elanInstanceName = pair.getRight();
899 BigInteger newDesignatedDpn = designateDpnId(tunnelIp, elanInstanceName, dpns);
900 if (newDesignatedDpn != null && !newDesignatedDpn.equals(DhcpMConstants.INVALID_DPID)) {
901 Set<String> vmMacAddress = tunnelIpElanNameToVmMacCache.get(pair);
902 if (vmMacAddress != null && !vmMacAddress.isEmpty()) {
903 LOG.trace("Updating DHCP flow for macAddress {} with newDpn {}",
904 vmMacAddress, newDesignatedDpn);
905 installDhcpFlowsForVms(newDesignatedDpn, vmMacAddress, tx);
908 java.util.Optional<SubnetToDhcpPort> subnetDhcpData = getSubnetDhcpPortData(elanInstanceName);
909 if (subnetDhcpData.isPresent()) {
910 configureDhcpArpRequestResponseFlow(newDesignatedDpn, elanInstanceName,
911 true, tunnelIp, subnetDhcpData.get().getPortFixedip(),
912 subnetDhcpData.get().getPortMacaddress());
920 private boolean isTunnelConfigured(BigInteger dpn, String hwVtepNodeId) {
921 String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), hwVtepNodeId);
922 if (tunnelInterfaceName == null) {
925 Interface tunnelInterface = interfaceManager.getInterfaceInfoFromConfigDataStore(tunnelInterfaceName);
926 if (tunnelInterface == null) {
927 LOG.trace("Tunnel Interface is not present {}", tunnelInterfaceName);
933 public void removeFromAvailableCache(Pair<IpAddress, String> tunnelIpElanName) {
934 availableVMCache.remove(tunnelIpElanName);
937 private void unInstallDhcpEntriesOnDpns(final List<BigInteger> dpns, final String vmMacAddress) {
938 jobCoordinator.enqueueJob(getJobKey(vmMacAddress), () -> {
939 if (entityOwnershipUtils.isEntityOwner(HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
940 HwvtepSouthboundConstants.ELAN_ENTITY_NAME)) {
941 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
942 for (final BigInteger dpn : dpns) {
943 unInstallDhcpEntries(dpn, vmMacAddress, tx);
947 LOG.trace("Exiting unInstallDhcpEntries since this cluster node is not the owner for dpn");
950 return Collections.emptyList();
954 public IpAddress getTunnelIpBasedOnElan(String elanInstanceName, String vmMacAddress) {
955 LOG.trace("DhcpExternalTunnelManager getTunnelIpBasedOnElan elanInstanceName {}", elanInstanceName);
956 IpAddress tunnelIp = null;
957 for (Entry<Pair<IpAddress, String>, Set<String>> entry : availableVMCache.entrySet()) {
958 Pair<IpAddress, String> pair = entry.getKey();
959 LOG.trace("DhcpExternalTunnelManager getTunnelIpBasedOnElan left {} right {}", pair.getLeft(),
961 if (pair.getRight().trim().equalsIgnoreCase(elanInstanceName.trim())) {
962 Set<String> listExistingVmMacAddress = entry.getValue();
963 if (listExistingVmMacAddress != null && !listExistingVmMacAddress.isEmpty()
964 && listExistingVmMacAddress.contains(vmMacAddress)) {
965 tunnelIp = pair.getLeft();
970 LOG.trace("DhcpExternalTunnelManager getTunnelIpBasedOnElan returned tunnelIP {}", tunnelIp);
974 private String getJobKey(final String jobKeySuffix) {
975 return DhcpMConstants.DHCP_JOB_KEY_PREFIX + jobKeySuffix;