37c9873fd435f3f05681eebf2ea91ce6db2d56f0
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / utils / ElanUtils.java
1 /*
2  * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.elan.utils;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Lists;
13 import com.google.common.primitives.Ints;
14 import com.google.common.util.concurrent.CheckedFuture;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18
19 import java.math.BigInteger;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.Future;
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32 import org.apache.commons.lang3.StringUtils;
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.clustering.EntityOwnershipService;
37 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
38 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
39 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
40 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
41 import org.opendaylight.genius.interfacemanager.globals.InterfaceServiceUtil;
42 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
43 import org.opendaylight.genius.itm.globals.ITMConstants;
44 import org.opendaylight.genius.mdsalutil.ActionInfo;
45 import org.opendaylight.genius.mdsalutil.FlowEntity;
46 import org.opendaylight.genius.mdsalutil.InstructionInfo;
47 import org.opendaylight.genius.mdsalutil.MDSALUtil;
48 import org.opendaylight.genius.mdsalutil.MDSALUtil.MdsalOp;
49 import org.opendaylight.genius.mdsalutil.MatchInfo;
50 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
51 import org.opendaylight.genius.mdsalutil.NWUtil;
52 import org.opendaylight.genius.mdsalutil.NwConstants;
53 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
54 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
55 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
56 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
57 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
58 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
59 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
60 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
61 import org.opendaylight.genius.mdsalutil.packet.ARP;
62 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
63 import org.opendaylight.genius.mdsalutil.packet.IPv4;
64 import org.opendaylight.genius.utils.ServiceIndex;
65 import org.opendaylight.netvirt.elan.ElanException;
66 import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
67 import org.opendaylight.netvirt.elan.internal.ElanInterfaceManager;
68 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
69 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
70 import org.opendaylight.netvirt.elan.l2gw.utils.L2GatewayConnectionUtils;
71 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
74 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
75 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
76 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
77 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
78 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.IfIndexesInterfaceMap;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterface;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterfaceKey;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInput;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInput;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInputBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutput;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInput;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInputBuilder;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstanceBuilder;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTag;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagNameBuilder;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaceForwardingEntries;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanState;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanTagNameMap;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeFlat;
143 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVlan;
144 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVxlan;
145 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
146 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
147 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
148 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
149 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
150 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
151 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
152 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableBuilder;
153 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
154 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
155 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
156 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
157 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegments;
158 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
159 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
160 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
161 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesBuilder;
162 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesKey;
163 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
164 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
165 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
166 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagName;
167 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameBuilder;
168 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
169 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
170 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
171 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
172 import org.opendaylight.yangtools.yang.binding.DataObject;
173 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
174 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
175 import org.opendaylight.yangtools.yang.common.RpcResult;
176 import org.slf4j.Logger;
177 import org.slf4j.LoggerFactory;
178
179 @Singleton
180 public class ElanUtils {
181
182     private static final Logger LOG = LoggerFactory.getLogger(ElanUtils.class);
183
184     private static Map<String, ElanInstance> elanInstanceLocalCache = new ConcurrentHashMap<>();
185     private static Map<String, ElanInterface> elanInterfaceLocalCache = new ConcurrentHashMap<>();
186     private static Map<String, Set<DpnInterfaces>> elanInstancToDpnsCache = new ConcurrentHashMap<>();
187
188     private final DataBroker broker;
189     private final IMdsalApiManager mdsalManager;
190     private final ElanInstanceManager elanInstanceManager;
191     private final OdlInterfaceRpcService interfaceManagerRpcService;
192     private final ItmRpcService itmRpcService;
193     private final ElanL2GatewayUtils elanL2GatewayUtils;
194     private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
195     private final L2GatewayConnectionUtils l2GatewayConnectionUtils;
196     private final IInterfaceManager interfaceManager;
197     private final ElanConfig elanConfig;
198
199     public static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
200         @Override
201         public void onSuccess(Void result) {
202             LOG.debug("Success in Datastore operation");
203         }
204
205         @Override
206         public void onFailure(Throwable error) {
207             LOG.error("Error in Datastore operation", error);
208         }
209     };
210
211     @Inject
212     public ElanUtils(DataBroker dataBroker, IMdsalApiManager mdsalManager, ElanInstanceManager elanInstanceManager,
213                      OdlInterfaceRpcService interfaceManagerRpcService, ItmRpcService itmRpcService,
214                      ElanInterfaceManager elanInterfaceManager, ElanConfig elanConfig,
215                      EntityOwnershipService entityOwnershipService, IInterfaceManager interfaceManager) {
216         this.broker = dataBroker;
217         this.mdsalManager = mdsalManager;
218         this.elanInstanceManager = elanInstanceManager;
219         this.interfaceManagerRpcService = interfaceManagerRpcService;
220         this.itmRpcService = itmRpcService;
221         this.interfaceManager = interfaceManager;
222         this.elanConfig = elanConfig;
223
224         elanL2GatewayMulticastUtils =
225                 new ElanL2GatewayMulticastUtils(broker, elanInstanceManager, elanInterfaceManager, this);
226         elanL2GatewayUtils = new ElanL2GatewayUtils(broker, itmRpcService, this,
227                 entityOwnershipService, elanL2GatewayMulticastUtils);
228         elanL2GatewayMulticastUtils.setEElanL2GatewayUtils(elanL2GatewayUtils);
229         l2GatewayConnectionUtils = new L2GatewayConnectionUtils(broker,
230                 elanInstanceManager, entityOwnershipService, this);
231     }
232
233     public void close() {
234         elanL2GatewayUtils.close();
235     }
236
237     public ElanL2GatewayUtils getElanL2GatewayUtils() {
238         return elanL2GatewayUtils;
239     }
240
241     public ElanL2GatewayMulticastUtils getElanL2GatewayMulticastUtils() {
242         return elanL2GatewayMulticastUtils;
243     }
244
245     public L2GatewayConnectionUtils getL2GatewayConnectionUtils() {
246         return l2GatewayConnectionUtils;
247     }
248
249     public final Boolean isOpenStackVniSemanticsEnforced() {
250         return elanConfig.isOpenstackVniSemanticsEnforced();
251     }
252
253     public static void addElanInstanceIntoCache(String elanInstanceName, ElanInstance elanInstance) {
254         elanInstanceLocalCache.put(elanInstanceName, elanInstance);
255     }
256
257     public static void removeElanInstanceFromCache(String elanInstanceName) {
258         elanInstanceLocalCache.remove(elanInstanceName);
259     }
260
261     public static ElanInstance getElanInstanceFromCache(String elanInstanceName) {
262         return elanInstanceLocalCache.get(elanInstanceName);
263     }
264
265     public static Set<String> getAllElanNames() {
266         return elanInstanceLocalCache.keySet();
267     }
268
269     public static void addElanInterfaceIntoCache(String interfaceName, ElanInterface elanInterface) {
270         elanInterfaceLocalCache.put(interfaceName, elanInterface);
271     }
272
273     public static void removeElanInterfaceFromCache(String interfaceName) {
274         elanInterfaceLocalCache.remove(interfaceName);
275     }
276
277     public static ElanInterface getElanInterfaceFromCache(String interfaceName) {
278         return elanInterfaceLocalCache.get(interfaceName);
279     }
280
281     /**
282      * Uses the IdManager to retrieve a brand new ElanTag.
283      *
284      * @param idManager
285      *            the id manager
286      * @param idKey
287      *            the id key
288      * @return the integer
289      */
290     public static Long retrieveNewElanTag(IdManagerService idManager, String idKey) {
291
292         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
293                 .setIdKey(idKey).build();
294
295         try {
296             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
297             RpcResult<AllocateIdOutput> rpcResult = result.get();
298             if (rpcResult.isSuccessful()) {
299                 return rpcResult.getResult().getIdValue();
300             } else {
301                 LOG.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors());
302             }
303         } catch (InterruptedException | ExecutionException e) {
304             LOG.warn("Exception when Allocating Id", e);
305         }
306         return 0L;
307     }
308
309     public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
310         ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
311         idManager.releaseId(releaseIdInput);
312     }
313
314     /**
315      * Read utility.
316      *
317      * @deprecated Consider using {@link #read2(LogicalDatastoreType, InstanceIdentifier)} with proper exception
318      *             handling instead
319      */
320     @Deprecated
321     @SuppressWarnings("checkstyle:IllegalCatch")
322     public <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
323             InstanceIdentifier<T> path) {
324         try (ReadOnlyTransaction tx = broker != null ? broker.newReadOnlyTransaction()
325                 : this.broker.newReadOnlyTransaction()) {
326             return tx.read(datastoreType, path).get();
327         } catch (Exception e) {
328             throw new RuntimeException(e);
329         }
330     }
331
332     public <T extends DataObject> Optional<T> read2(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
333             throws ReadFailedException {
334         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
335             CheckedFuture<Optional<T>, ReadFailedException> checkedFuture = tx.read(datastoreType, path);
336             return checkedFuture.checkedGet();
337         }
338     }
339
340     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
341             InstanceIdentifier<T> path) {
342         WriteTransaction tx = broker.newWriteOnlyTransaction();
343         tx.delete(datastoreType, path);
344         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
345     }
346
347     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
348             InstanceIdentifier<T> path, FutureCallback<Void> callback) {
349         WriteTransaction tx = broker.newWriteOnlyTransaction();
350         tx.delete(datastoreType, path);
351         Futures.addCallback(tx.submit(), callback);
352     }
353
354     public static InstanceIdentifier<ElanInstance> getElanInstanceIdentifier() {
355         return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class).build();
356     }
357
358     // elan-instances config container
359     public static ElanInstance getElanInstanceByName(DataBroker broker, String elanInstanceName) {
360         ElanInstance elanObj = getElanInstanceFromCache(elanInstanceName);
361         if (elanObj != null) {
362             return elanObj;
363         }
364         InstanceIdentifier<ElanInstance> elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName);
365         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orNull();
366     }
367
368     public static InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
369         return InstanceIdentifier.builder(ElanInstances.class)
370                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
371     }
372
373     // elan-interfaces Config Container
374     public static ElanInterface getElanInterfaceByElanInterfaceName(DataBroker broker, String elanInterfaceName) {
375         ElanInterface elanInterfaceObj = getElanInterfaceFromCache(elanInterfaceName);
376         if (elanInterfaceObj != null) {
377             return elanInterfaceObj;
378         }
379         InstanceIdentifier<ElanInterface> elanInterfaceId = getElanInterfaceConfigurationDataPathId(elanInterfaceName);
380         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId).orNull();
381     }
382
383     public static EtreeInterface getEtreeInterfaceByElanInterfaceName(DataBroker broker, String elanInterfaceName) {
384         ElanInterface elanInterface = getElanInterfaceByElanInterfaceName(broker, elanInterfaceName);
385         if (elanInterface == null) {
386             return null;
387         } else {
388             return elanInterface.getAugmentation(EtreeInterface.class);
389         }
390     }
391
392     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
393         return InstanceIdentifier.builder(ElanInterfaces.class)
394                 .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).build();
395     }
396
397     // elan-state Operational container
398     public static Elan getElanByName(DataBroker broker, String elanInstanceName) {
399         InstanceIdentifier<Elan> elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName);
400         return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).orNull();
401     }
402
403     public static InstanceIdentifier<Elan> getElanInstanceOperationalDataPath(String elanInstanceName) {
404         return InstanceIdentifier.builder(ElanState.class).child(Elan.class, new ElanKey(elanInstanceName)).build();
405     }
406
407     // grouping of forwarding-entries
408     public MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) {
409         InstanceIdentifier<MacEntry> existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath(
410                 interfaceName, physAddress);
411         return read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId).orNull();
412     }
413
414     public MacEntry getInterfaceMacEntriesOperationalDataPathFromId(InstanceIdentifier identifier) {
415         Optional<MacEntry> existingInterfaceMacEntry = read(broker,
416                 LogicalDatastoreType.OPERATIONAL, identifier);
417         return existingInterfaceMacEntry.orNull();
418     }
419
420     public static InstanceIdentifier<MacEntry> getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName,
421             PhysAddress physAddress) {
422         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class)
423                 .child(ElanInterfaceMac.class, new ElanInterfaceMacKey(interfaceName))
424                 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
425
426     }
427
428     // elan-forwarding-tables Operational container
429     public Optional<MacEntry> getMacEntryForElanInstance(String elanName, PhysAddress physAddress) {
430         InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanName, physAddress);
431         return read(broker, LogicalDatastoreType.OPERATIONAL, macId);
432     }
433
434     public MacEntry getMacEntryFromElanMacId(InstanceIdentifier identifier) {
435         Optional<MacEntry> existingInterfaceMacEntry = read(broker,
436                 LogicalDatastoreType.OPERATIONAL, identifier);
437         return existingInterfaceMacEntry.orNull();
438     }
439
440     public static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
441             PhysAddress physAddress) {
442         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
443                 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
444     }
445
446     public static InstanceIdentifier<MacTable> getElanMacTableOperationalDataPath(String elanName) {
447         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
448                 .build();
449     }
450
451     // elan-interface-forwarding-entries Operational container
452     public ElanInterfaceMac getElanInterfaceMacByInterfaceName(String interfaceName) {
453         InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath(
454                 interfaceName);
455         return read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orNull();
456     }
457
458     /**
459      * Gets the elan interface mac addresses.
460      *
461      * @param interfaceName
462      *            the interface name
463      * @return the elan interface mac addresses
464      */
465     public List<PhysAddress> getElanInterfaceMacAddresses(String interfaceName) {
466         List<PhysAddress> macAddresses = new ArrayList<>();
467         ElanInterfaceMac elanInterfaceMac = getElanInterfaceMacByInterfaceName(interfaceName);
468         if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
469             List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
470             for (MacEntry macEntry : macEntries) {
471                 macAddresses.add(macEntry.getMacAddress());
472             }
473         }
474         return macAddresses;
475     }
476
477     public static InstanceIdentifier<ElanInterfaceMac> getElanInterfaceMacEntriesOperationalDataPath(
478             String interfaceName) {
479         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class)
480                 .child(ElanInterfaceMac.class, new ElanInterfaceMacKey(interfaceName)).build();
481     }
482
483     /**
484      * Returns the list of Interfaces that belong to an Elan on an specific DPN.
485      * Data retrieved from Elan's operational DS: elan-dpn-interfaces container
486      *
487      * @param elanInstanceName
488      *            name of the Elan to which the interfaces must belong to
489      * @param dpId
490      *            Id of the DPN where the interfaces are located
491      * @return the elan interface Info
492      */
493     public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) {
494         InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName,
495                 dpId);
496         return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId).orNull();
497     }
498
499     /**
500      * Returns the InstanceIdentifier that points to the Interfaces of an Elan
501      * in a given DPN in the Operational DS. Data retrieved from Elans's
502      * operational DS: dpn-interfaces list
503      *
504      * @param elanInstanceName
505      *            name of the Elan to which the interfaces must belong to
506      * @param dpId
507      *            Id of the DPN where the interfaces are located
508      * @return the elan dpn interface
509      */
510     public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
511             BigInteger dpId) {
512         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
513                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
514                 .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
515     }
516
517     // elan-tag-name-map Operational Container
518     public ElanTagName getElanInfoByElanTag(long elanTag) {
519         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
520         Optional<ElanTagName> existingElanInfo = read(broker,
521                 LogicalDatastoreType.OPERATIONAL, elanId);
522         return existingElanInfo.orNull();
523     }
524
525     public EtreeLeafTagName getEtreeLeafTagByElanTag(long elanTag) {
526         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
527         Optional<ElanTagName> existingElanInfo = read(broker,
528                 LogicalDatastoreType.OPERATIONAL, elanId);
529         if (existingElanInfo.isPresent()) {
530             ElanTagName elanTagName = existingElanInfo.get();
531             return elanTagName.getAugmentation(EtreeLeafTagName.class);
532         }
533         return null;
534     }
535
536     public static InstanceIdentifier<ElanTagName> getElanInfoEntriesOperationalDataPath(long elanTag) {
537         return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class, new ElanTagNameKey(elanTag))
538                 .build();
539     }
540
541     // interface-index-tag operational container
542     public Optional<IfIndexInterface> getInterfaceInfoByInterfaceTag(long interfaceTag) {
543         InstanceIdentifier<IfIndexInterface> interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag);
544         return read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
545     }
546
547     public static InstanceIdentifier<IfIndexInterface> getInterfaceInfoEntriesOperationalDataPath(long interfaceTag) {
548         return InstanceIdentifier.builder(IfIndexesInterfaceMap.class)
549                 .child(IfIndexInterface.class, new IfIndexInterfaceKey((int) interfaceTag)).build();
550     }
551
552     public static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
553         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
554                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
555     }
556
557     public ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) {
558         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanName);
559         return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull();
560     }
561
562     public ElanDpnInterfaces getElanDpnInterfacesList() {
563         InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class)
564                 .build();
565         return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull();
566     }
567
568     /**
569      * This method is useful get all ELAN participating CSS dpIds to install
570      * program remote dmac entries and updating remote bc groups for tor
571      * integration.
572      *
573      * @param elanInstanceName
574      *            the elan instance name
575      * @return list of dpIds
576      */
577     public List<BigInteger> getParticipatingDpnsInElanInstance(String elanInstanceName) {
578         List<BigInteger> dpIds = new ArrayList<>();
579         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
580         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = read(broker,
581                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
582         if (!existingElanDpnInterfaces.isPresent()) {
583             return dpIds;
584         }
585         List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
586         for (DpnInterfaces dpnInterface : dpnInterfaces) {
587             dpIds.add(dpnInterface.getDpId());
588         }
589         return dpIds;
590     }
591
592     /**
593      * To check given dpId is already present in Elan instance. This can be used
594      * to program flow entry in external tunnel table when a new access port
595      * added for first time into the ELAN instance
596      *
597      * @param dpId
598      *            the dp id
599      * @param elanInstanceName
600      *            the elan instance name
601      * @return true if dpId is already present, otherwise return false
602      */
603     public boolean isDpnAlreadyPresentInElanInstance(BigInteger dpId, String elanInstanceName) {
604         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
605         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = read(broker,
606                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
607         if (!existingElanDpnInterfaces.isPresent()) {
608             return false;
609         }
610         List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
611         for (DpnInterfaces dpnInterface : dpnInterfaces) {
612             if (dpnInterface.getDpId().equals(dpId)) {
613                 return true;
614             }
615         }
616         return false;
617     }
618
619     public ElanForwardingTables getElanForwardingList() {
620         InstanceIdentifier<ElanForwardingTables> elanForwardingTableId = InstanceIdentifier
621                 .builder(ElanForwardingTables.class).build();
622         return read(broker, LogicalDatastoreType.OPERATIONAL, elanForwardingTableId).orNull();
623     }
624
625     public static long getElanRemoteBroadCastGroupID(long elanTag) {
626         return ElanConstants.ELAN_GID_MIN + elanTag % ElanConstants.ELAN_GID_MIN * 2;
627     }
628
629     /**
630      * Gets the elan mac table.
631      *
632      * @param elanName
633      *            the elan name
634      * @return the elan mac table
635      */
636     public MacTable getElanMacTable(String elanName) {
637         InstanceIdentifier<MacTable> elanMacTableId = getElanMacTableOperationalDataPath(elanName);
638         return read(broker, LogicalDatastoreType.OPERATIONAL, elanMacTableId).orNull();
639     }
640
641     public static long getElanLocalBCGId(long elanTag) {
642         return ElanConstants.ELAN_GID_MIN + (elanTag % ElanConstants.ELAN_GID_MIN * 2 - 1);
643     }
644
645     public static long getElanRemoteBCGId(long elanTag) {
646         return ElanConstants.ELAN_GID_MIN + elanTag % ElanConstants.ELAN_GID_MIN * 2;
647     }
648
649     public static long getEtreeLeafLocalBCGId(long etreeLeafTag) {
650         return ElanConstants.ELAN_GID_MIN + (etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2 - 1);
651     }
652
653     public static long getEtreeLeafRemoteBCGId(long etreeLeafTag) {
654         return ElanConstants.ELAN_GID_MIN + etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2;
655     }
656
657     public static BigInteger getElanMetadataLabel(long elanTag) {
658         return MetaDataUtil.getElanTagMetadata(elanTag);
659     }
660
661     public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet) {
662         int shBit = isSHFlagSet ? 1 : 0;
663         return BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit));
664     }
665
666     public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) {
667         return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag));
668     }
669
670     public static BigInteger getElanMetadataMask() {
671         return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG);
672     }
673
674     /**
675      * Setting SMAC, DMAC, UDMAC in this DPN and optionally in other DPNs.
676      *
677      * @param elanInfo
678      *            the elan info
679      * @param interfaceInfo
680      *            the interface info
681      * @param macTimeout
682      *            the mac timeout
683      * @param macAddress
684      *            the mac address
685      * @param configureRemoteFlows
686      *            true if remote dmac flows should be configured as well
687      * @param writeFlowGroupTx
688      *            the flow group tx
689      * @throws ElanException in case of issues creating the flow objects
690      */
691     public void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
692                               long macTimeout, String macAddress, boolean configureRemoteFlows,
693                               WriteTransaction writeFlowGroupTx) throws ElanException {
694         synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) {
695             setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalManager,
696                 writeFlowGroupTx);
697             setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, configureRemoteFlows, mdsalManager,
698                 broker, writeFlowGroupTx);
699         }
700     }
701
702     public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId,
703                                          String macAddress, WriteTransaction writeFlowTx) throws ElanException {
704         String elanInstanceName = elanInfo.getElanInstanceName();
705         setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(), elanInfo.getElanTag(),
706                 macAddress, elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo);
707         LOG.info("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and"
708                 + " mac address {} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(),
709                 macAddress, dstDpId);
710     }
711
712     /**
713      * Inserts a Flow in SMAC table to state that the MAC has already been
714      * learnt.
715      */
716     private void setupKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
717             String macAddress, IMdsalApiManager mdsalApiManager, WriteTransaction writeFlowGroupTx) {
718         FlowEntity flowEntity = buildKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress);
719         mdsalApiManager.addFlowToTx(flowEntity, writeFlowGroupTx);
720         LOG.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}",
721                 elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress);
722     }
723
724     public FlowEntity buildKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
725             String macAddress) {
726         int lportTag = interfaceInfo.getInterfaceTag();
727         // Matching metadata and eth_src fields
728         List<MatchInfo> mkMatches = new ArrayList<>();
729         mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanInfo.getElanTag(), lportTag), getElanMetadataMask()));
730         mkMatches.add(new MatchEthernetSource(new MacAddress(macAddress)));
731         List<InstructionInfo> mkInstructions = new ArrayList<>();
732         mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
733         BigInteger dpId = interfaceInfo.getDpId();
734         long elanTag = getElanTag(broker, elanInfo, interfaceInfo);
735         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_SMAC_TABLE,
736                 getKnownDynamicmacFlowRef(NwConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag), 20,
737                 elanInfo.getDescription(), (int) macTimeout, 0,
738                 ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
739         flowEntity.setStrictFlag(true);
740         flowEntity.setSendFlowRemFlag(macTimeout != 0); // If Mac timeout is 0,
741                                                         // the flow wont be
742                                                         // deleted
743                                                         // automatically, so no
744                                                         // need to get notified
745         return flowEntity;
746     }
747
748     private static Long getElanTag(DataBroker broker, ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
749         EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceInfo.getInterfaceName());
750         if (etreeInterface == null || etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
751             return elanInfo.getElanTag();
752         } else { // Leaf
753             EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
754             if (etreeInstance == null) {
755                 LOG.warn("EtreeInterface {} is connected to a non-Etree network: {}",
756                          interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName());
757                 return elanInfo.getElanTag();
758             } else {
759                 return etreeInstance.getEtreeLeafTagVal().getValue();
760             }
761         }
762     }
763
764     /**
765      * Installs a Flow in INTERNAL_TUNNEL_TABLE of the affected DPN that sends
766      * the packet through the specified interface if the tunnel_id matches the
767      * interface's lportTag.
768      *
769      * @param interfaceInfo
770      *            the interface info
771      * @param mdsalApiManager
772      *            the mdsal API manager
773      * @param writeFlowGroupTx
774      *            the writeFLowGroup tx
775      */
776     public void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager,
777                                    WriteTransaction writeFlowGroupTx) {
778         BigInteger dpId = interfaceInfo.getDpId();
779         int lportTag = interfaceInfo.getInterfaceTag();
780         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
781                 getIntTunnelTableFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, lportTag), 5,
782                 String.format("%s:%d", "ITM Flow Entry ", lportTag), 0, 0,
783                 ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)),
784                 getTunnelIdMatchForFilterEqualsLPortTag(lportTag),
785                 getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
786         mdsalApiManager.addFlowToTx(dpId, flow, writeFlowGroupTx);
787         LOG.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}", dpId,
788                 interfaceInfo.getPortName());
789     }
790
791     /**
792      * Constructs the FlowName for flows installed in the Internal Tunnel Table,
793      * consisting in tableId + elanTag.
794      *
795      * @param tableId
796      *            table Id
797      * @param elanTag
798      *            elan Tag
799      * @return the Internal tunnel
800      */
801     public static String getIntTunnelTableFlowRef(short tableId, int elanTag) {
802         return new StringBuffer().append(tableId).append(elanTag).toString();
803     }
804
805     /**
806      * Constructs the Matches that checks that the tunnel_id field contains a
807      * specific lportTag.
808      *
809      * @param lportTag
810      *            lportTag that must be checked against the tunnel_id field
811      * @return the list of match Info
812      */
813     public static List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) {
814         List<MatchInfo> mkMatches = new ArrayList<>();
815         // Matching metadata
816         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
817         return mkMatches;
818     }
819
820     /**
821      * Constructs the Instructions that take the packet over a given interface.
822      *
823      * @param ifName
824      *            Name of the interface where the packet must be sent over. It
825      *            can be a local interface or a tunnel interface (internal or
826      *            external)
827      * @return the Instruction
828      */
829     public List<Instruction> getInstructionsInPortForOutGroup(String ifName) {
830         List<Instruction> mkInstructions = new ArrayList<>();
831         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
832
833         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
834         return mkInstructions;
835     }
836
837     /**
838      * Returns the list of Actions to be taken when sending the packet through
839      * an Elan interface. Note that this interface can refer to an ElanInterface
840      * where the Elan VM is attached to a DPN or an ITM tunnel interface where
841      * Elan traffic can be sent through. In this latter case, the tunnelKey is
842      * mandatory and it can hold serviceId for internal tunnels or the VNI for
843      * external tunnels.
844      *
845      * @param ifName
846      *            the if name
847      * @param tunnelKey
848      *            the tunnel key
849      * @return the egress actions for interface
850      */
851     @SuppressWarnings("checkstyle:IllegalCatch")
852     public List<Action> getEgressActionsForInterface(String ifName, Long tunnelKey) {
853         List<Action> listAction = new ArrayList<>();
854         try {
855             GetEgressActionsForInterfaceInput getEgressActionInput = new GetEgressActionsForInterfaceInputBuilder()
856                     .setIntfName(ifName).setTunnelKey(tunnelKey).build();
857             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result = interfaceManagerRpcService
858                     .getEgressActionsForInterface(getEgressActionInput);
859             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
860             if (!rpcResult.isSuccessful()) {
861                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName,
862                         rpcResult.getErrors());
863             } else {
864                 List<Action> actions = rpcResult.getResult().getAction();
865                 listAction = actions;
866             }
867         } catch (Exception e) {
868             LOG.warn("Exception when egress actions for interface {}", ifName, e);
869         }
870         return listAction;
871     }
872
873     private void setupOrigDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
874                                     boolean configureRemoteFlows, IMdsalApiManager mdsalApiManager,
875                                     DataBroker broker, WriteTransaction writeFlowGroupTx)
876                                     throws ElanException {
877         BigInteger dpId = interfaceInfo.getDpId();
878         String ifName = interfaceInfo.getInterfaceName();
879         long ifTag = interfaceInfo.getInterfaceTag();
880         String elanInstanceName = elanInfo.getElanInstanceName();
881
882         Long elanTag = elanInfo.getElanTag();
883
884         setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, mdsalApiManager, ifTag,
885                 writeFlowGroupTx);
886         LOG.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} mand mac address:{} "
887                                     + "on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dpId);
888
889         if (!configureRemoteFlows) {
890             return;
891         }
892
893         List<DpnInterfaces> elanDpns = getInvolvedDpnsInElan(elanInstanceName);
894         if (elanDpns == null) {
895             return;
896         }
897
898         for (DpnInterfaces elanDpn : elanDpns) {
899
900             if (elanDpn.getDpId().equals(dpId)) {
901                 continue;
902             }
903
904             // Check for the Remote DPN present in Inventory Manager
905             if (!isDpnPresent(elanDpn.getDpId())) {
906                 continue;
907             }
908
909             // For remote DPNs a flow is needed to indicate that packets of this ELAN going to this MAC need to be
910             // forwarded through the appropriate ITM tunnel
911             setupRemoteDmacFlow(elanDpn.getDpId(), // srcDpn (the remote DPN in this case)
912                     dpId, // dstDpn (the local DPN)
913                     interfaceInfo.getInterfaceTag(), // lportTag of the local interface
914                     elanTag,  // identifier of the Elan
915                     macAddress, // MAC to be programmed in remote DPN
916                     elanInstanceName, writeFlowGroupTx, ifName, elanInfo
917             );
918             LOG.debug("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on"
919                         + " dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, elanDpn.getDpId());
920         }
921
922         // TODO: Make sure that the same is performed against the ElanDevices.
923     }
924
925     @SuppressWarnings("unchecked")
926     public List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
927         List<DpnInterfaces> dpns = elanInstanceManager.getElanDPNByName(elanName);
928         if (dpns == null) {
929             return Collections.emptyList();
930         }
931         return dpns;
932     }
933
934     private void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
935             ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) {
936         Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, elanInfo, ifTag);
937         mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
938         installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo,
939                 mdsalApiManager, ifTag, writeFlowGroupTx);
940     }
941
942     private void installEtreeLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
943             ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) {
944         EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, ifName);
945         if (etreeInterface != null) {
946             if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
947                 EtreeLeafTagName etreeTagName = getEtreeLeafTagByElanTag(elanTag);
948                 if (etreeTagName == null) {
949                     LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null",
950                              ifName, elanTag);
951                 } else {
952                     Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId, ifName,
953                             macAddress, elanInfo, ifTag);
954                     mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
955                 }
956             }
957         }
958     }
959
960     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, long lporTag, String macAddress,
961             long elanTag) {
962         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(lporTag).append(macAddress)
963                 .toString();
964     }
965
966     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, BigInteger remoteDpId,
967             String macAddress, long elanTag) {
968         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(remoteDpId).append(macAddress)
969                 .toString();
970     }
971
972     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, String macAddress, long elanTag) {
973         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(macAddress).toString();
974     }
975
976     private static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId,
977             String dstMacAddress, long elanTag, boolean shFlag) {
978         return new StringBuffer().append(elanDmacTable).append(elanTag).append(dpId).append(extDeviceNodeId)
979                 .append(dstMacAddress).append(shFlag).toString();
980     }
981
982     /**
983      * Builds the flow to be programmed in the DMAC table of the local DPN (that
984      * is, where the MAC is attached to). This flow consists in:
985      *
986      * <p>Match: + elanTag in metadata + packet goes to a MAC locally attached
987      * Actions: + optionally, pop-vlan + set-vlan-id + output to ifName's
988      * portNumber
989      *
990      * @param elanTag
991      *            the elan tag
992      * @param dpId
993      *            the dp id
994      * @param ifName
995      *            the if name
996      * @param macAddress
997      *            the mac address
998      * @param elanInfo
999      *            the elan info
1000      * @param ifTag
1001      *            the if tag
1002      * @return the flow
1003      */
1004     public Flow buildLocalDmacFlowEntry(long elanTag, BigInteger dpId, String ifName, String macAddress,
1005             ElanInstance elanInfo, long ifTag) {
1006
1007         List<MatchInfo> mkMatches = new ArrayList<>();
1008         mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
1009         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
1010
1011         List<Instruction> mkInstructions = new ArrayList<>();
1012         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
1013         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1014         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
1015                 getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, ifTag, macAddress, elanTag), 20,
1016                 elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(
1017                         BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1018
1019         return flow;
1020     }
1021
1022     public void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, String
1023             macAddress, String displayName, WriteTransaction writeFlowGroupTx, String interfaceName, ElanInstance
1024             elanInstance) throws ElanException {
1025         if (interfaceManager.isExternalInterface(interfaceName)) {
1026             LOG.debug("Ignoring install remote DMAC {} flow on provider interface {} elan {}",
1027                     macAddress, interfaceName, elanInstance.getElanInstanceName());
1028             return;
1029         }
1030         Flow flowEntity;
1031         // if openstack-vni-semantics are enforced, segmentation ID is passed as network VNI for VxLAN based provider
1032         // networks, 0 otherwise
1033         long lportTagOrVni = !isOpenStackVniSemanticsEnforced() ? lportTag : ((isVxlan(elanInstance))
1034                 ? elanInstance.getSegmentationId() : 0);
1035         flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName,
1036                 elanInstance);
1037         mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
1038         setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, interfaceName,
1039                 writeFlowGroupTx, elanInstance);
1040     }
1041
1042     private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
1043                                           String macAddress, String displayName, String interfaceName,
1044                                           WriteTransaction writeFlowGroupTx, ElanInstance elanInstance)
1045                                           throws ElanException {
1046         Flow flowEntity;
1047         EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceName);
1048         if (etreeInterface != null) {
1049             if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1050                 EtreeLeafTagName etreeTagName = getEtreeLeafTagByElanTag(elanTag);
1051                 if (etreeTagName == null) {
1052                     LOG.warn("Interface " + interfaceName
1053                             + " seems like it belongs to Etree but etreeTagName from elanTag " + elanTag + " is null.");
1054                 } else {
1055                     flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni,
1056                             etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName, elanInstance);
1057                     mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
1058                 }
1059             }
1060         }
1061     }
1062
1063     /**
1064      * Builds a Flow to be programmed in a remote DPN's DMAC table. This flow
1065      * consists in: Match: + elanTag in packet's metadata + packet going to a
1066      * MAC known to be located in another DPN Actions: + set_tunnel_id
1067      * + output ITM internal tunnel interface with the other DPN
1068      *
1069      * @param srcDpId
1070      *            the src Dpn Id
1071      * @param destDpId
1072      *            dest Dp Id
1073      * @param lportTagOrVni
1074      *            lportTag or network VNI
1075      * @param elanTag
1076      *            elan Tag
1077      * @param macAddress
1078      *            macAddress
1079      * @param displayName
1080      *            display Name
1081      * @return the flow remote Dmac
1082      * @throws ElanException in case of issues creating the flow objects
1083      */
1084     @SuppressWarnings("checkstyle:IllegalCatch")
1085     public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
1086             String macAddress, String displayName, ElanInstance elanInstance) throws ElanException {
1087         List<MatchInfo> mkMatches = new ArrayList<>();
1088         mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
1089         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
1090
1091         List<Instruction> mkInstructions = new ArrayList<>();
1092
1093         // List of Action for the provided Source and Destination DPIDs
1094         try {
1095             List<Action> actions = null;
1096             if (isVlan(elanInstance) || isFlat(elanInstance)) {
1097                 String interfaceName = getExternalElanInterface(elanInstance.getElanInstanceName(), srcDpId);
1098                 if (null == interfaceName) {
1099                     LOG.error("buildRemoteDmacFlowEntry: Could not find interfaceName for {} {}", srcDpId,
1100                             elanInstance);
1101                 }
1102                 actions = getEgressActionsForInterface(interfaceName, null);
1103             } else if (isVxlan(elanInstance)) {
1104                 actions = getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTagOrVni);
1105             }
1106             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1107         } catch (Exception e) {
1108             LOG.error("Could not get egress actions to add to flow for srcDpId=" + srcDpId + ", destDpId=" + destDpId
1109                     + ", lportTag/VNI=" + lportTagOrVni, e);
1110         }
1111
1112         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
1113                 getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcDpId, destDpId, macAddress, elanTag),
1114                 20, /* prio */
1115                 displayName, 0, /* idleTimeout */
1116                 0, /* hardTimeout */
1117                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1118
1119         return flow;
1120
1121     }
1122
1123     public void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, MacEntry macEntry,
1124             WriteTransaction deleteFlowGroupTx) {
1125         if (elanInfo == null || interfaceInfo == null) {
1126             return;
1127         }
1128         String macAddress = macEntry.getMacAddress().getValue();
1129         synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) {
1130             deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true, deleteFlowGroupTx);
1131         }
1132     }
1133
1134     public void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1135             boolean deleteSmac, WriteTransaction deleteFlowGroupTx) {
1136         String elanInstanceName = elanInfo.getElanInstanceName();
1137         List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
1138         BigInteger srcdpId = interfaceInfo.getDpId();
1139         boolean isFlowsRemovedInSrcDpn = false;
1140         for (DpnInterfaces dpnInterface : remoteFEs) {
1141             Long elanTag = elanInfo.getElanTag();
1142             BigInteger dstDpId = dpnInterface.getDpId();
1143             if (executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
1144                     elanTag, dstDpId, deleteFlowGroupTx)) {
1145                 isFlowsRemovedInSrcDpn = true;
1146             }
1147             executeEtreeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
1148                     elanTag, dstDpId, deleteFlowGroupTx);
1149         }
1150         if (!isFlowsRemovedInSrcDpn) {
1151             deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx);
1152         }
1153     }
1154
1155     private void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1156             boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
1157             WriteTransaction deleteFlowGroupTx) {
1158         EtreeLeafTagName etreeLeafTag = getEtreeLeafTagByElanTag(elanTag);
1159         if (etreeLeafTag != null) {
1160             executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
1161                     etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, deleteFlowGroupTx);
1162         }
1163     }
1164
1165     private boolean executeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1166             boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
1167             WriteTransaction deleteFlowGroupTx) {
1168         boolean isFlowsRemovedInSrcDpn = false;
1169         if (dstDpId.equals(srcdpId)) {
1170             isFlowsRemovedInSrcDpn = true;
1171             deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx);
1172         } else if (isDpnPresent(dstDpId)) {
1173             mdsalManager
1174                     .removeFlowToTx(dstDpId,
1175                             MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(
1176                                     NwConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag)),
1177                             deleteFlowGroupTx);
1178             LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}",
1179                     elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId);
1180         }
1181         return isFlowsRemovedInSrcDpn;
1182     }
1183
1184     private void deleteSmacAndDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1185             boolean deleteSmac, WriteTransaction deleteFlowGroupTx) {
1186         String elanInstanceName = elanInfo.getElanInstanceName();
1187         long ifTag = interfaceInfo.getInterfaceTag();
1188         BigInteger srcdpId = interfaceInfo.getDpId();
1189         Long elanTag = elanInfo.getElanTag();
1190         if (deleteSmac) {
1191             mdsalManager
1192                     .removeFlowToTx(srcdpId,
1193                             MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef(
1194                                     NwConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)),
1195                             deleteFlowGroupTx);
1196         }
1197         mdsalManager.removeFlowToTx(srcdpId,
1198                 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
1199                         getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)),
1200                 deleteFlowGroupTx);
1201         LOG.debug("All the required flows deleted for elan:{}, logical Interface port:{} and MAC address:{} on dpn:{}",
1202                 elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
1203     }
1204
1205     /**
1206      * Updates the Elan information in the Operational DS. It also updates the
1207      * ElanInstance in the Config DS by setting the adquired elanTag.
1208      *
1209      * @param broker
1210      *            the broker
1211      * @param idManager
1212      *            the id manager
1213      * @param elanInstanceAdded
1214      *            the elan instance added
1215      * @param elanInterfaces
1216      *            the elan interfaces
1217      * @param tx
1218      *            transaction
1219      */
1220     public static void updateOperationalDataStore(DataBroker broker, IdManagerService idManager,
1221             ElanInstance elanInstanceAdded, List<String> elanInterfaces, WriteTransaction tx) {
1222         String elanInstanceName = elanInstanceAdded.getElanInstanceName();
1223         Long elanTag = elanInstanceAdded.getElanTag();
1224         if (elanTag == null || elanTag == 0L) {
1225             elanTag = retrieveNewElanTag(idManager, elanInstanceName);
1226         }
1227         Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(elanInterfaces)
1228                 .setKey(new ElanKey(elanInstanceName)).build();
1229
1230         // Add the ElanState in the elan-state operational data-store
1231         tx.put(LogicalDatastoreType.OPERATIONAL, getElanInstanceOperationalDataPath(elanInstanceName),
1232                 elanInfo, true);
1233
1234         // Add the ElanMacTable in the elan-mac-table operational data-store
1235         MacTable elanMacTable = new MacTableBuilder().setKey(new MacTableKey(elanInstanceName)).build();
1236         tx.put(LogicalDatastoreType.OPERATIONAL, getElanMacTableOperationalDataPath(elanInstanceName),
1237                 elanMacTable, true);
1238
1239         ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag)
1240                 .setKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName);
1241         long etreeLeafTag = -1;
1242         if (isEtreeInstance(elanInstanceAdded)) {
1243             etreeLeafTag = retrieveNewElanTag(idManager, elanInstanceName + ElanConstants.LEAVES_POSTFIX);
1244             EtreeLeafTagName etreeLeafTagName = new EtreeLeafTagNameBuilder()
1245                     .setEtreeLeafTag(new EtreeLeafTag(etreeLeafTag)).build();
1246             elanTagNameBuilder.addAugmentation(EtreeLeafTagName.class, etreeLeafTagName);
1247             addTheLeafTagAsElanTag(broker, elanInstanceName, etreeLeafTag, tx);
1248         }
1249         ElanTagName elanTagName = elanTagNameBuilder.build();
1250
1251         // Add the ElanTag to ElanName in the elan-tag-name Operational
1252         // data-store
1253         tx.put(LogicalDatastoreType.OPERATIONAL,
1254                 getElanInfoEntriesOperationalDataPath(elanTag), elanTagName);
1255
1256         // Updates the ElanInstance Config DS by setting the just acquired
1257         // elanTag
1258         ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
1259                 .setDescription(elanInstanceAdded.getDescription())
1260                 .setMacTimeout(elanInstanceAdded.getMacTimeout() == null ? ElanConstants.DEFAULT_MAC_TIME_OUT
1261                         : elanInstanceAdded.getMacTimeout())
1262                 .setKey(elanInstanceAdded.getKey()).setElanTag(elanTag);
1263         if (isEtreeInstance(elanInstanceAdded)) {
1264             EtreeInstance etreeInstance = new EtreeInstanceBuilder().setEtreeLeafTagVal(new EtreeLeafTag(etreeLeafTag))
1265                     .build();
1266             elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance);
1267         }
1268         ElanInstance elanInstanceWithTag = elanInstanceBuilder.build();
1269         tx.merge(LogicalDatastoreType.CONFIGURATION, getElanInstanceConfigurationDataPath(elanInstanceName),
1270                 elanInstanceWithTag, true);
1271     }
1272
1273     private static void addTheLeafTagAsElanTag(DataBroker broker, String elanInstanceName, long etreeLeafTag,
1274             WriteTransaction tx) {
1275         ElanTagName etreeTagAsElanTag = new ElanTagNameBuilder().setElanTag(etreeLeafTag)
1276                 .setKey(new ElanTagNameKey(etreeLeafTag)).setName(elanInstanceName).build();
1277         tx.put(LogicalDatastoreType.OPERATIONAL,
1278                 getElanInfoEntriesOperationalDataPath(etreeLeafTag), etreeTagAsElanTag);
1279     }
1280
1281     private static boolean isEtreeInstance(ElanInstance elanInstanceAdded) {
1282         return elanInstanceAdded.getAugmentation(EtreeInstance.class) != null;
1283     }
1284
1285     public boolean isDpnPresent(BigInteger dpnId) {
1286         String dpn = String.format("%s:%s", "openflow", dpnId);
1287         NodeId nodeId = new NodeId(dpn);
1288
1289         InstanceIdentifier<Node> node = InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(nodeId))
1290                 .build();
1291         return read(broker, LogicalDatastoreType.CONFIGURATION, node).isPresent();
1292     }
1293
1294     public static ServicesInfo getServiceInfo(String elanInstanceName, long elanTag, String interfaceName) {
1295         int priority = ElanConstants.ELAN_SERVICE_PRIORITY;
1296         int instructionKey = 0;
1297         List<Instruction> instructions = new ArrayList<>();
1298         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(getElanMetadataLabel(elanTag),
1299                 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1300         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_SMAC_TABLE, ++instructionKey));
1301
1302         short serviceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1303         ServicesInfo serviceInfo = InterfaceServiceUtil.buildServiceInfo(
1304                 String.format("%s.%s", elanInstanceName, interfaceName), serviceIndex, priority,
1305                 NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1306         return serviceInfo;
1307     }
1308
1309     public static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
1310             InstanceIdentifier<T> path, T data) {
1311         WriteTransaction tx = broker.newWriteOnlyTransaction();
1312         tx.put(datastoreType, path, data, true);
1313         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
1314         try {
1315             futures.get();
1316         } catch (InterruptedException | ExecutionException e) {
1317             LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data);
1318             throw new RuntimeException(e.getMessage());
1319         }
1320     }
1321
1322     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
1323             BigInteger cookie, List<Instruction> instructions) {
1324         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
1325                 .setInstruction(instructions);
1326         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
1327                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
1328                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
1329     }
1330
1331     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex) {
1332         return InstanceIdentifier.builder(ServiceBindings.class)
1333                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
1334                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
1335     }
1336
1337     /**
1338      * Builds the list of actions to be taken when sending the packet over a VxLan Tunnel Interface, such as setting
1339      * the network VNI in the tunnel_id field.
1340      *
1341      * @param tunnelIfaceName
1342      *            the tunnel iface name
1343      * @param tunnelKey
1344      *            the tunnel key
1345      * @return the list
1346      */
1347     public List<Action> buildTunnelItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
1348         if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
1349             return buildItmEgressActions(tunnelIfaceName, tunnelKey);
1350         }
1351
1352         return Collections.emptyList();
1353     }
1354
1355     /**
1356      * Builds the list of actions to be taken when sending the packet over external port such as tunnel, physical
1357      * port etc.
1358      *
1359      * @param interfaceName
1360      *            the interface name
1361      * @param tunnelKey
1362      *            can be VNI for VxLAN tunnel interfaces, Gre Key for GRE
1363      *            tunnels, etc.
1364      * @return the list
1365      */
1366     @SuppressWarnings("checkstyle:IllegalCatch")
1367     public List<Action> buildItmEgressActions(String interfaceName, Long tunnelKey) {
1368         List<Action> result = Collections.emptyList();
1369         try {
1370             GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
1371                     .setIntfName(interfaceName).setTunnelKey(tunnelKey).build();
1372
1373             Future<RpcResult<GetEgressActionsForInterfaceOutput>> egressActionsOutputFuture = interfaceManagerRpcService
1374                     .getEgressActionsForInterface(getEgressActInput);
1375             if (egressActionsOutputFuture.get().isSuccessful()) {
1376                 GetEgressActionsForInterfaceOutput egressActionsOutput = egressActionsOutputFuture.get().getResult();
1377                 result = egressActionsOutput.getAction();
1378             }
1379         } catch (Exception e) {
1380             LOG.error("Error in RPC call getEgressActionsForInterface {}", e);
1381         }
1382
1383         if (result == null || result.size() == 0) {
1384             LOG.warn("Could not build Egress actions for interface {} and tunnelId {}", interfaceName, tunnelKey);
1385         }
1386         return result;
1387     }
1388
1389     /**
1390      * Builds the list of actions to be taken when sending the packet over an
1391      * external VxLan tunnel interface, such as stamping the VNI on the VxLAN
1392      * header, setting the vlanId if it proceeds and output the packet over the
1393      * right port.
1394      *
1395      * @param srcDpnId
1396      *            Dpn where the tunnelInterface is located
1397      * @param torNode
1398      *            NodeId of the ExternalDevice where the packet must be sent to.
1399      * @param vni
1400      *            Vni to be stamped on the VxLAN Header.
1401      * @return the external itm egress action
1402      */
1403     public List<Action> getExternalTunnelItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni) {
1404         List<Action> result = Collections.emptyList();
1405
1406         GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
1407                 .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString())
1408                 .setTunnelType(TunnelTypeVxlan.class).build();
1409         Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
1410                 .getExternalTunnelInterfaceName(input);
1411         try {
1412             if (output.get().isSuccessful()) {
1413                 GetExternalTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
1414                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
1415                 LOG.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
1416
1417                 result = buildTunnelItmEgressActions(tunnelIfaceName, vni);
1418             }
1419
1420         } catch (InterruptedException | ExecutionException e) {
1421             LOG.error("Error in RPC call getTunnelInterfaceName {}", e);
1422         }
1423
1424         return result;
1425     }
1426
1427     /**
1428      * Builds the list of actions to be taken when sending the packet over an internal VxLAN tunnel interface, such
1429      * as setting the serviceTag/segmentationID on the VNI field of the VxLAN header, setting the vlanId if it proceeds
1430      * and output the packet over the right port.
1431      *
1432      * @param sourceDpnId
1433      *            Dpn where the tunnelInterface is located
1434      * @param destinationDpnId
1435      *            Dpn where the packet must be sent to. It is used here in order
1436      *            to select the right tunnel interface.
1437      * @param tunnelKey
1438      *            Tunnel key to be sent on the VxLAN header.
1439      * @return the internal itm egress action
1440      */
1441     public List<Action> getInternalTunnelItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId, long
1442             tunnelKey) {
1443         List<Action> result = Collections.emptyList();
1444         LOG.trace("In getInternalItmEgressAction Action source {}, destination {}, serviceTag/Vni {}", sourceDpnId,
1445                 destinationDpnId, tunnelKey);
1446         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
1447         GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder()
1448                 .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build();
1449         Future<RpcResult<GetTunnelInterfaceNameOutput>> output = itmRpcService.getTunnelInterfaceName(input);
1450         try {
1451             if (output.get().isSuccessful()) {
1452                 GetTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
1453                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
1454                 LOG.info("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
1455                 result = buildTunnelItmEgressActions(tunnelIfaceName, tunnelKey);
1456             } else {
1457                 LOG.trace("Tunnel interface doesn't exist between srcDpId {} dstDpId {}", sourceDpnId,
1458                         destinationDpnId);
1459             }
1460         } catch (InterruptedException | ExecutionException e) {
1461             LOG.error("Error in RPC call getTunnelInterfaceName {}", e);
1462         }
1463         return result;
1464     }
1465
1466     /**
1467      * Build the list of actions to be taken when sending the packet to external
1468      * (physical) port.
1469      *
1470      * @param interfaceName
1471      *            Interface name
1472      * @return the external port itm egress actions
1473      */
1474     public List<Action> getExternalPortItmEgressAction(String interfaceName) {
1475         return buildItmEgressActions(interfaceName, null);
1476     }
1477
1478     public static List<MatchInfo> getTunnelMatchesForServiceId(int elanTag) {
1479         List<MatchInfo> mkMatches = new ArrayList<>();
1480         // Matching metadata
1481         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(elanTag)));
1482
1483         return mkMatches;
1484     }
1485
1486     public void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) {
1487         RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder()
1488                 .setDpnId(destDpId).setServiceId(serviceId).build();
1489         Future<RpcResult<Void>> futureObject = itmRpcService.removeTerminatingServiceActions(input);
1490         try {
1491             RpcResult<Void> result = futureObject.get();
1492             if (result.isSuccessful()) {
1493                 LOG.debug("Successfully completed removeTerminatingServiceActions for ELAN with serviceId {} on "
1494                                 + "dpn {}", serviceId, destDpId);
1495             } else {
1496                 LOG.debug("Failure in removeTerminatingServiceAction RPC call for ELAN with serviceId {} on "
1497                         + "dpn {}", serviceId, destDpId);
1498             }
1499         } catch (InterruptedException | ExecutionException e) {
1500             LOG.error("Error in RPC call removeTerminatingServiceActions for ELAN with serviceId {} on "
1501                     + "dpn {}: {}", serviceId, destDpId, e);
1502         }
1503     }
1504
1505     /**
1506      * Gets the external tunnel.
1507      *
1508      * @param sourceDevice
1509      *            the source device
1510      * @param destinationDevice
1511      *            the destination device
1512      * @param datastoreType
1513      *            the datastore type
1514      * @return the external tunnel
1515      */
1516     public ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
1517             LogicalDatastoreType datastoreType) {
1518         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
1519         InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
1520                 .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
1521         return read(broker, datastoreType, iid).orNull();
1522     }
1523
1524     /**
1525      * Gets the external tunnel.
1526      *
1527      * @param interfaceName
1528      *            the interface name
1529      * @param datastoreType
1530      *            the datastore type
1531      * @return the external tunnel
1532      */
1533     public ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
1534         ExternalTunnel externalTunnel = null;
1535         List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
1536         for (ExternalTunnel tunnel : externalTunnels) {
1537             if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
1538                 externalTunnel = tunnel;
1539                 break;
1540             }
1541         }
1542         return externalTunnel;
1543     }
1544
1545     /**
1546      * Gets the all external tunnels.
1547      *
1548      * @param datastoreType
1549      *            the data store type
1550      * @return the all external tunnels
1551      */
1552     public List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
1553         InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
1554         return read(broker, datastoreType, iid).transform(ExternalTunnelList::getExternalTunnel).or(
1555                 Collections.emptyList());
1556     }
1557
1558     /**
1559      * Installs a Flow in the specified DPN's DMAC table. The flow is for a MAC
1560      * that is connected remotely in an External Device (TOR) and that is
1561      * accessible through an external tunnel. It also installs the flow for
1562      * dropping the packet if it came over an ITM tunnel (that is, if the
1563      * Split-Horizon flag is set)
1564      *
1565      * @param dpnId
1566      *            Id of the DPN where the flow must be installed
1567      * @param extDeviceNodeId
1568      *            the ext device node id
1569      * @param elanTag
1570      *            the elan tag
1571      * @param vni
1572      *            the vni
1573      * @param macAddress
1574      *            the mac address
1575      * @param displayName
1576      *            the display name
1577      * @param interfaceName
1578      *            the interface name
1579      *
1580      * @return the dmac flows
1581      * @throws ElanException in case of issues creating the flow objects
1582      */
1583     public List<ListenableFuture<Void>> installDmacFlowsToExternalRemoteMac(BigInteger dpnId,
1584             String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
1585             String interfaceName) throws ElanException {
1586         List<ListenableFuture<Void>> futures = new ArrayList<>();
1587         synchronized (getElanMacDPNKey(elanTag, macAddress, dpnId)) {
1588             Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress,
1589                     displayName);
1590             futures.add(mdsalManager.installFlow(dpnId, flow));
1591
1592             Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress);
1593             futures.add(mdsalManager.installFlow(dpnId, dropFlow));
1594             installEtreeDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName,
1595                     interfaceName, futures);
1596         }
1597         return futures;
1598     }
1599
1600     private void installEtreeDmacFlowsToExternalRemoteMac(BigInteger dpnId, String extDeviceNodeId, Long elanTag,
1601             Long vni, String macAddress, String displayName, String interfaceName,
1602             List<ListenableFuture<Void>> futures) throws ElanException {
1603         EtreeLeafTagName etreeLeafTag = getEtreeLeafTagByElanTag(elanTag);
1604         if (etreeLeafTag != null) {
1605             buildEtreeDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress, futures,
1606                     etreeLeafTag);
1607             buildEtreeDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, vni, macAddress, displayName, interfaceName,
1608                     futures, etreeLeafTag);
1609         }
1610     }
1611
1612     private void buildEtreeDmacFlowForExternalRemoteMac(BigInteger dpnId, String extDeviceNodeId, Long vni,
1613             String macAddress, String displayName, String interfaceName, List<ListenableFuture<Void>> futures,
1614             EtreeLeafTagName etreeLeafTag) throws ElanException {
1615         boolean isRoot = false;
1616         if (interfaceName == null) {
1617             isRoot = true;
1618         } else {
1619             EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceName);
1620             if (etreeInterface != null) {
1621                 if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1622                     isRoot = true;
1623                 }
1624             }
1625         }
1626         if (isRoot) {
1627             Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId,
1628                     etreeLeafTag.getEtreeLeafTag().getValue(), vni, macAddress, displayName);
1629             futures.add(mdsalManager.installFlow(dpnId, flow));
1630         }
1631     }
1632
1633     private void buildEtreeDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId,
1634             Long elanTag, String macAddress, List<ListenableFuture<Void>> futures, EtreeLeafTagName etreeLeafTag) {
1635         if (etreeLeafTag != null) {
1636             Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId,
1637                     etreeLeafTag.getEtreeLeafTag().getValue(), macAddress);
1638             futures.add(mdsalManager.installFlow(dpnId, dropFlow));
1639         }
1640     }
1641
1642     public static List<MatchInfo> buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) {
1643         List<MatchInfo> mkMatches = new ArrayList<>();
1644         mkMatches.add(
1645                 new MatchMetadata(getElanMetadataLabel(elanTag, shFlag), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1646         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddr)));
1647         return mkMatches;
1648     }
1649
1650     /**
1651      * Builds a Flow to be programmed in a DPN's DMAC table. This method must be
1652      * used when the MAC is located in an External Device (TOR). The flow
1653      * matches on the specified MAC and 1) sends the packet over the CSS-TOR
1654      * tunnel if SHFlag is not set, or 2) drops it if SHFlag is set (what means
1655      * the packet came from an external tunnel)
1656      *
1657      * @param dpId
1658      *            DPN whose DMAC table is going to be modified
1659      * @param extDeviceNodeId
1660      *            Hwvtep node where the mac is attached to
1661      * @param elanTag
1662      *            ElanId to which the MAC is being added to
1663      * @param vni
1664      *            the vni
1665      * @param dstMacAddress
1666      *            The mac address to be programmed
1667      * @param displayName
1668      *            the display name
1669      * @return the flow
1670      * @throws ElanException in case of issues creating the flow objects
1671      */
1672     @SuppressWarnings("checkstyle:IllegalCatch")
1673     public Flow buildDmacFlowForExternalRemoteMac(BigInteger dpId, String extDeviceNodeId, long elanTag,
1674             Long vni, String dstMacAddress, String displayName) throws ElanException {
1675         List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, dstMacAddress);
1676         List<Instruction> mkInstructions = new ArrayList<>();
1677         try {
1678             List<Action> actions = getExternalTunnelItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni);
1679             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1680         } catch (Exception e) {
1681             LOG.error("Could not get Egress Actions for DpId=" + dpId + ", externalNode=" + extDeviceNodeId, e);
1682         }
1683
1684         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
1685                 getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, dstMacAddress, elanTag,
1686                         false),
1687                 20, /* prio */
1688                 displayName, 0, /* idleTimeout */
1689                 0, /* hardTimeout */
1690                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1691
1692         return flow;
1693     }
1694
1695     /**
1696      * Builds the flow that drops the packet if it came through an external
1697      * tunnel, that is, if the Split-Horizon flag is set.
1698      *
1699      * @param dpnId
1700      *            DPN whose DMAC table is going to be modified
1701      * @param extDeviceNodeId
1702      *            Hwvtep node where the mac is attached to
1703      * @param elanTag
1704      *            ElanId to which the MAC is being added to
1705      * @param dstMacAddress
1706      *            The mac address to be programmed
1707      */
1708     private static Flow buildDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId,
1709             Long elanTag, String dstMacAddress) {
1710         List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ true, dstMacAddress);
1711         List<Instruction> mkInstructions = MDSALUtil.buildInstructionsDrop();
1712         String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress,
1713                 elanTag, true);
1714         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, flowId, 20, /* prio */
1715                 "Drop", 0, /* idleTimeout */
1716                 0, /* hardTimeout */
1717                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1718
1719         return flow;
1720     }
1721
1722     private static String getDmacDropFlowId(Long elanTag, String dstMacAddress) {
1723         return new StringBuilder(NwConstants.ELAN_DMAC_TABLE).append(elanTag).append(dstMacAddress).append("Drop")
1724                 .toString();
1725     }
1726
1727     /**
1728      * Installs or removes flows in DMAC table for MACs that are/were located in
1729      * an external Elan Device.
1730      *
1731      * @param dpId
1732      *            Id of the DPN where the DMAC table is going to be modified
1733      * @param extNodeId
1734      *            Id of the External Device where the MAC is located
1735      * @param elanTag
1736      *            Id of the ELAN
1737      * @param vni
1738      *            VNI of the LogicalSwitch to which the MAC belongs to, and that
1739      *            is associated with the ELAN
1740      * @param macAddress
1741      *            the mac address
1742      * @param elanInstanceName
1743      *            the elan instance name
1744      * @param addOrRemove
1745      *            Indicates if flows must be installed or removed.
1746      * @param interfaceName
1747      *            the interface name
1748      * @throws ElanException in case of issues creating the flow objects
1749      * @see org.opendaylight.genius.mdsalutil.MDSALUtil.MdsalOp
1750      */
1751     public void setupDmacFlowsToExternalRemoteMac(BigInteger dpId, String extNodeId, Long elanTag, Long vni,
1752             String macAddress, String elanInstanceName, MdsalOp addOrRemove, String interfaceName)
1753             throws ElanException {
1754         if (addOrRemove == MdsalOp.CREATION_OP) {
1755             installDmacFlowsToExternalRemoteMac(dpId, extNodeId, elanTag, vni, macAddress, elanInstanceName,
1756                     interfaceName);
1757         } else if (addOrRemove == MdsalOp.REMOVAL_OP) {
1758             deleteDmacFlowsToExternalMac(elanTag, dpId, extNodeId, macAddress);
1759         }
1760     }
1761
1762     /**
1763      * Delete dmac flows to external mac.
1764      *
1765      * @param elanTag
1766      *            the elan tag
1767      * @param dpId
1768      *            the dp id
1769      * @param extDeviceNodeId
1770      *            the ext device node id
1771      * @param macToRemove
1772      *            the mac to remove
1773      * @return dmac flow
1774      */
1775     public List<ListenableFuture<Void>> deleteDmacFlowsToExternalMac(long elanTag, BigInteger dpId,
1776             String extDeviceNodeId, String macToRemove) {
1777         List<ListenableFuture<Void>> futures = new ArrayList<>();
1778         synchronized (getElanMacDPNKey(elanTag, macToRemove, dpId)) {
1779             // Removing the flows that sends the packet on an external tunnel
1780             removeFlowThatSendsThePacketOnAnExternalTunnel(elanTag, dpId, extDeviceNodeId, macToRemove, futures);
1781
1782             // And now removing the drop flow
1783             removeTheDropFlow(elanTag, dpId, extDeviceNodeId, macToRemove, futures);
1784
1785             deleteEtreeDmacFlowsToExternalMac(elanTag, dpId, extDeviceNodeId, macToRemove, futures);
1786         }
1787         return futures;
1788     }
1789
1790     private void deleteEtreeDmacFlowsToExternalMac(long elanTag, BigInteger dpId, String extDeviceNodeId,
1791             String macToRemove, List<ListenableFuture<Void>> futures) {
1792         EtreeLeafTagName etreeLeafTag = getEtreeLeafTagByElanTag(elanTag);
1793         if (etreeLeafTag != null) {
1794             removeFlowThatSendsThePacketOnAnExternalTunnel(etreeLeafTag.getEtreeLeafTag().getValue(), dpId,
1795                     extDeviceNodeId, macToRemove, futures);
1796             removeTheDropFlow(etreeLeafTag.getEtreeLeafTag().getValue(), dpId, extDeviceNodeId, macToRemove, futures);
1797         }
1798     }
1799
1800     private void removeTheDropFlow(long elanTag, BigInteger dpId, String extDeviceNodeId, String macToRemove,
1801             List<ListenableFuture<Void>> futures) {
1802         String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
1803                 elanTag, true);
1804         Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
1805         futures.add(mdsalManager.removeFlow(dpId, flowToRemove));
1806     }
1807
1808     private void removeFlowThatSendsThePacketOnAnExternalTunnel(long elanTag, BigInteger dpId,
1809             String extDeviceNodeId, String macToRemove, List<ListenableFuture<Void>> futures) {
1810         String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
1811                 elanTag, false);
1812         Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
1813         futures.add(mdsalManager.removeFlow(dpId, flowToRemove));
1814     }
1815
1816     /**
1817      * Gets the dpid from interface.
1818      *
1819      * @param interfaceName
1820      *            the interface name
1821      * @return the dpid from interface
1822      */
1823     public BigInteger getDpidFromInterface(String interfaceName) {
1824         BigInteger dpId = null;
1825         Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceManagerRpcService
1826                 .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build());
1827         try {
1828             RpcResult<GetDpidFromInterfaceOutput> rpcResult = output.get();
1829             if (rpcResult.isSuccessful()) {
1830                 dpId = rpcResult.getResult().getDpid();
1831             }
1832         } catch (NullPointerException | InterruptedException | ExecutionException e) {
1833             LOG.error("Failed to get the DPN ID: {} for interface {}: {} ", dpId, interfaceName, e);
1834         }
1835         return dpId;
1836     }
1837
1838     /**
1839      * Checks if is interface operational.
1840      *
1841      * @param interfaceName
1842      *            the interface name
1843      * @param dataBroker
1844      *            the data broker
1845      * @return true, if is interface operational
1846      */
1847     public static boolean isInterfaceOperational(String interfaceName, DataBroker dataBroker) {
1848         if (StringUtils.isBlank(interfaceName)) {
1849             return false;
1850         }
1851         Interface ifState = getInterfaceStateFromOperDS(interfaceName, dataBroker);
1852         if (ifState == null) {
1853             return false;
1854         }
1855         return ifState.getOperStatus() == OperStatus.Up && ifState.getAdminStatus() == AdminStatus.Up;
1856     }
1857
1858     /**
1859      * Gets the interface state from operational ds.
1860      *
1861      * @param interfaceName
1862      *            the interface name
1863      * @param dataBroker
1864      *            the data broker
1865      * @return the interface state from oper ds
1866      */
1867     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1868         .ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
1869             String interfaceName, DataBroker dataBroker) {
1870         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1871             .ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = createInterfaceStateInstanceIdentifier(
1872                 interfaceName);
1873         return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId).orNull();
1874     }
1875
1876     /**
1877      * Creates the interface state instance identifier.
1878      *
1879      * @param interfaceName
1880      *            the interface name
1881      * @return the instance identifier
1882      */
1883     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1884         .ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
1885             String interfaceName) {
1886         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1887             .ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder = InstanceIdentifier
1888                 .builder(InterfacesState.class)
1889                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1890                         .ietf.interfaces.rev140508.interfaces.state.Interface.class,
1891                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1892                             .ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
1893                                 interfaceName));
1894         return idBuilder.build();
1895     }
1896
1897     public static CheckedFuture<Void, TransactionCommitFailedException> waitForTransactionToComplete(
1898             WriteTransaction tx) {
1899         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
1900         try {
1901             futures.get();
1902         } catch (InterruptedException | ExecutionException e) {
1903             LOG.error("Error writing to datastore {}", e);
1904         }
1905         return futures;
1906     }
1907
1908     public static boolean isVxlanNetwork(DataBroker broker, String elanInstanceName) {
1909         ElanInstance elanInstance = getElanInstanceByName(broker, elanInstanceName);
1910         return (elanInstance != null && isVxlan(elanInstance));
1911     }
1912
1913     public static boolean isVxlan(ElanInstance elanInstance) {
1914         return elanInstance != null && elanInstance.getSegmentType() != null
1915                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
1916                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0;
1917     }
1918
1919     private static boolean isVxlanSegment(ElanInstance elanInstance) {
1920         if (elanInstance != null) {
1921             List<ElanSegments> elanSegments = elanInstance.getElanSegments();
1922             if (elanSegments != null) {
1923                 for (ElanSegments segment : elanSegments) {
1924                     if (segment != null && (segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
1925                             && segment.getSegmentationId() != null
1926                             && segment.getSegmentationId().longValue() != 0)) {
1927                         return true;
1928                     }
1929                 }
1930             }
1931         }
1932         return false;
1933     }
1934
1935     public static boolean isVxlanNetworkOrVxlanSegment(ElanInstance elanInstance) {
1936         return isVxlan(elanInstance) || isVxlanSegment(elanInstance);
1937     }
1938
1939     public static Long getVxlanSegmentationId(ElanInstance elanInstance) {
1940         Long segmentationId = 0L;
1941
1942         if (elanInstance != null && elanInstance.getSegmentType() != null
1943                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
1944                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0) {
1945             segmentationId = elanInstance.getSegmentationId();
1946         } else {
1947             for (ElanSegments segment: elanInstance.getElanSegments()) {
1948                 if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
1949                     && segment.getSegmentationId() != null
1950                     && segment.getSegmentationId().longValue() != 0) {
1951                     segmentationId = segment.getSegmentationId();
1952                 }
1953             }
1954         }
1955         return segmentationId;
1956     }
1957
1958     public static boolean isVlan(ElanInstance elanInstance) {
1959         return elanInstance != null && elanInstance.getSegmentType() != null
1960                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVlan.class)
1961                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0;
1962     }
1963
1964     public static boolean isFlat(ElanInstance elanInstance) {
1965         return elanInstance != null && elanInstance.getSegmentType() != null
1966                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class);
1967     }
1968
1969     public void handleDmacRedirectToDispatcherFlows(Long elanTag, String displayName,
1970             String macAddress, int addOrRemove, List<BigInteger> dpnIds) {
1971         for (BigInteger dpId : dpnIds) {
1972             if (addOrRemove == NwConstants.ADD_FLOW) {
1973                 WriteTransaction writeTx = broker.newWriteOnlyTransaction();
1974                 mdsalManager.addFlowToTx(buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName, elanTag),
1975                         writeTx);
1976                 writeTx.submit();
1977             } else {
1978                 String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, macAddress, elanTag);
1979                 mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, flowId));
1980             }
1981         }
1982     }
1983
1984     public static FlowEntity buildDmacRedirectToDispatcherFlow(BigInteger dpId, String dstMacAddress,
1985             String displayName, long elanTag) {
1986         List<MatchInfo> matches = new ArrayList<>();
1987         matches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
1988         matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress)));
1989         List<InstructionInfo> instructions = new ArrayList<>();
1990         List<ActionInfo> actions = new ArrayList<>();
1991         actions.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
1992
1993         instructions.add(new InstructionApplyActions(actions));
1994         String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, dstMacAddress, elanTag);
1995         FlowEntity flow  = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_DMAC_TABLE, flowId, 20, displayName, 0, 0,
1996                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1997                 matches, instructions);
1998         return flow;
1999     }
2000
2001     /**
2002      * Add Mac Address to ElanInterfaceForwardingEntries and ElanForwardingTables
2003      * Install SMAC and DMAC flows.
2004      */
2005     public void addMacEntryToDsAndSetupFlows(IInterfaceManager interfaceManager, String interfaceName,
2006             String macAddress, String elanName, WriteTransaction tx, WriteTransaction flowWritetx, int macTimeOut)
2007             throws ElanException {
2008         LOG.trace("Adding mac address {} and interface name {} to ElanInterfaceForwardingEntries and "
2009             + "ElanForwardingTables DS", macAddress, interfaceName);
2010         BigInteger timeStamp = new BigInteger(String.valueOf(System.currentTimeMillis()));
2011         PhysAddress physAddress = new PhysAddress(macAddress);
2012         MacEntry macEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
2013                 .setKey(new MacEntryKey(physAddress)).setControllerLearnedForwardingEntryTimestamp(timeStamp)
2014                 .setIsStaticAddress(false).build();
2015         InstanceIdentifier<MacEntry> macEntryId = ElanUtils
2016                 .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
2017         tx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, macEntry);
2018         InstanceIdentifier<MacEntry> elanMacEntryId = ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
2019         tx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry);
2020         ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanName);
2021         setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut, macAddress, true,
2022                 flowWritetx);
2023     }
2024
2025     /**
2026      * Remove Mac Address from ElanInterfaceForwardingEntries and ElanForwardingTables
2027      * Remove SMAC and DMAC flows.
2028      */
2029     public void deleteMacEntryFromDsAndRemoveFlows(IInterfaceManager interfaceManager, String interfaceName,
2030             String macAddress, String elanName, WriteTransaction tx, WriteTransaction deleteFlowTx) {
2031         LOG.trace("Deleting mac address {} and interface name {} from ElanInterfaceForwardingEntries "
2032                 + "and ElanForwardingTables DS", macAddress, interfaceName);
2033         PhysAddress physAddress = new PhysAddress(macAddress);
2034         MacEntry macEntry = getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress);
2035         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
2036         if (macEntry != null && interfaceInfo != null) {
2037             deleteMacFlows(ElanUtils.getElanInstanceByName(broker, elanName), interfaceInfo, macEntry, deleteFlowTx);
2038         }
2039         tx.delete(LogicalDatastoreType.OPERATIONAL,
2040                 ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress));
2041         tx.delete(LogicalDatastoreType.OPERATIONAL,
2042                 ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress));
2043     }
2044
2045     public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) {
2046         DpnInterfaces dpnInterfaces = getElanInterfaceInfoByElanDpn(elanInstanceName, dpnId);
2047         if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) {
2048             LOG.trace("Elan {} does not have interfaces in DPN {}", elanInstanceName, dpnId);
2049             return null;
2050         }
2051
2052         for (String dpnInterface : dpnInterfaces.getInterfaces()) {
2053             if (interfaceManager.isExternalInterface(dpnInterface)) {
2054                 return dpnInterface;
2055             }
2056         }
2057
2058         LOG.trace("Elan {} does not have any external interace attached to DPN {}", elanInstanceName, dpnId);
2059         return null;
2060     }
2061
2062     public static String getElanMacDPNKey(long elanTag, String macAddress, BigInteger dpnId) {
2063         String elanMacDmacDpnKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag + "DPN_ID-" + dpnId;
2064         return elanMacDmacDpnKey.intern();
2065     }
2066
2067     public static String getElanMacKey(long elanTag, String macAddress) {
2068         String elanMacKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag;
2069         return elanMacKey.intern();
2070     }
2071
2072
2073     public static void addToListenableFutureIfTxException(RuntimeException exception,
2074             List<ListenableFuture<Void>> futures) {
2075         Throwable cause = exception.getCause();
2076         if (cause != null && cause instanceof TransactionCommitFailedException) {
2077             futures.add(Futures.immediateFailedCheckedFuture((TransactionCommitFailedException) cause));
2078         }
2079     }
2080
2081     public static List<PhysAddress> getPhysAddress(List<String> macAddress) {
2082         Preconditions.checkNotNull(macAddress, "macAddress cannot be null");
2083         List<PhysAddress> physAddresses = new ArrayList<>();
2084         for (String mac : macAddress) {
2085             physAddresses.add(new PhysAddress(mac));
2086         }
2087         return physAddresses;
2088     }
2089
2090     public static List<StaticMacEntries> getStaticMacEntries(List<String> staticMacAddresses) {
2091         if (isEmpty(staticMacAddresses)) {
2092             return Collections.EMPTY_LIST;
2093         }
2094         StaticMacEntriesBuilder staticMacEntriesBuilder = new StaticMacEntriesBuilder();
2095         List<StaticMacEntries> staticMacEntries = new ArrayList<>();
2096         List<PhysAddress> physAddressList = getPhysAddress(staticMacAddresses);
2097         for (PhysAddress physAddress : physAddressList) {
2098             staticMacEntries.add(staticMacEntriesBuilder.setMacAddress(physAddress).build());
2099         }
2100         return staticMacEntries;
2101     }
2102
2103     public static InstanceIdentifier<StaticMacEntries> getStaticMacEntriesCfgDataPathIdentifier(String interfaceName,
2104                                                                                                 String macAddress) {
2105         return InstanceIdentifier.builder(ElanInterfaces.class)
2106                 .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).child(StaticMacEntries.class,
2107                         new StaticMacEntriesKey(new PhysAddress(macAddress))).build();
2108     }
2109
2110     public static List<StaticMacEntries> getDeletedEntries(List<StaticMacEntries> originalStaticMacEntries,
2111                                                            List<StaticMacEntries> updatedStaticMacEntries) {
2112         if (isEmpty(originalStaticMacEntries)) {
2113             return Collections.EMPTY_LIST;
2114         }
2115         List<StaticMacEntries> deleted = Lists.newArrayList(originalStaticMacEntries);
2116         if (isNotEmpty(updatedStaticMacEntries)) {
2117             deleted.removeAll(updatedStaticMacEntries);
2118         }
2119         return deleted;
2120     }
2121
2122     public static <T> List<T> diffOf(List<T> orig, List<T> updated) {
2123         if (isEmpty(orig)) {
2124             return Collections.EMPTY_LIST;
2125         }
2126         List<T> diff = Lists.newArrayList(orig);
2127         if (isNotEmpty(updated)) {
2128             diff.removeAll(updated);
2129         }
2130         return diff;
2131     }
2132
2133     public static void segregateToBeDeletedAndAddEntries(List<StaticMacEntries> originalStaticMacEntries,
2134                                                              List<StaticMacEntries> updatedStaticMacEntries) {
2135         if (isNotEmpty(updatedStaticMacEntries)) {
2136             List<StaticMacEntries> existingClonedStaticMacEntries = new ArrayList<>();
2137             if (isNotEmpty(originalStaticMacEntries)) {
2138                 existingClonedStaticMacEntries.addAll(0, originalStaticMacEntries);
2139                 originalStaticMacEntries.removeAll(updatedStaticMacEntries);
2140                 updatedStaticMacEntries.removeAll(existingClonedStaticMacEntries);
2141             }
2142         }
2143     }
2144
2145     public static boolean isEmpty(Collection collection) {
2146         return collection == null || collection.isEmpty();
2147     }
2148
2149     public static boolean isNotEmpty(Collection collection) {
2150         return (!isEmpty(collection));
2151     }
2152
2153     public static void setElanInstancToDpnsCache(Map<String, Set<DpnInterfaces>> elanInstancToDpnsCache) {
2154         ElanUtils.elanInstancToDpnsCache = elanInstancToDpnsCache;
2155     }
2156
2157     public static Set<DpnInterfaces> getElanInvolvedDPNsFromCache(String elanName) {
2158         return elanInstancToDpnsCache.get(elanName);
2159     }
2160
2161     public static void addDPNInterfaceToElanInCache(String elanName, DpnInterfaces dpnInterfaces) {
2162         elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<>()).add(dpnInterfaces);
2163     }
2164
2165     public static void removeDPNInterfaceFromElanInCache(String elanName, DpnInterfaces dpnInterfaces) {
2166         elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<DpnInterfaces>()).remove(dpnInterfaces);
2167     }
2168
2169     public Optional<IpAddress> getSourceIpAddress(Ethernet ethernet) {
2170         Optional<IpAddress> srcIpAddress = Optional.absent();
2171         if (ethernet.getPayload() == null) {
2172             return srcIpAddress;
2173         }
2174         byte[] ipAddrBytes = null;
2175         if (ethernet.getPayload() instanceof IPv4) {
2176             IPv4 ipv4 = (IPv4) ethernet.getPayload();
2177             ipAddrBytes = Ints.toByteArray(ipv4.getSourceAddress());
2178         } else if (ethernet.getPayload() instanceof ARP) {
2179             ipAddrBytes = ((ARP) ethernet.getPayload()).getSenderProtocolAddress();
2180         }
2181         if (ipAddrBytes != null) {
2182             String ipAddr = NWUtil.toStringIpAddress(ipAddrBytes);
2183             return Optional.of(IpAddressBuilder.getDefaultInstance(ipAddr));
2184         }
2185
2186         return srcIpAddress;
2187     }
2188 }