Remove unused parameters
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / utils / ElanDmacUtils.java
1 /*
2  * Copyright © 2017 Red Hat, Inc. and others.
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.collect.Lists;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.genius.mdsalutil.MDSALUtil;
22 import org.opendaylight.genius.mdsalutil.MatchInfo;
23 import org.opendaylight.genius.mdsalutil.NwConstants;
24 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
25 import org.opendaylight.netvirt.elan.ElanException;
26 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 @Singleton
39 public class ElanDmacUtils {
40     private static final Logger LOG = LoggerFactory.getLogger(ElanDmacUtils.class);
41
42     private static final boolean SH_FLAG_SET = true;
43     private static final boolean SH_FLAG_UNSET = false;
44
45     private final DataBroker broker;
46     private final ElanItmUtils elanItmUtils;
47     private final ElanEtreeUtils elanEtreeUtils;
48     private final ElanInterfaceCache elanInterfaceCache;
49
50     @Inject
51     public ElanDmacUtils(DataBroker broker, ElanItmUtils elanItmUtils, ElanEtreeUtils elanEtreeUtils,
52             ElanInterfaceCache elanInterfaceCache) {
53         this.broker = broker;
54         this.elanItmUtils = elanItmUtils;
55         this.elanEtreeUtils = elanEtreeUtils;
56         this.elanInterfaceCache = elanInterfaceCache;
57     }
58
59     /**
60      * Builds a Flow to be programmed in a DPN's DMAC table. This method must be
61      * used when the MAC is located in an External Device (TOR). The flow
62      * matches on the specified MAC and 1) sends the packet over the CSS-TOR
63      * tunnel if SHFlag is not set, or 2) drops it if SHFlag is set (what means
64      * the packet came from an external tunnel)
65      *
66      * @param dpId
67      *            DPN whose DMAC table is going to be modified
68      * @param extDeviceNodeId
69      *            Hwvtep node where the mac is attached to
70      * @param elanTag
71      *            ElanId to which the MAC is being added to
72      * @param vni
73      *            the vni
74      * @param dstMacAddress
75      *            The mac address to be programmed
76      * @param displayName
77      *            the display name
78      * @return the flow
79      */
80     @SuppressWarnings("checkstyle:IllegalCatch")
81     public Flow buildDmacFlowForExternalRemoteMac(BigInteger dpId, String extDeviceNodeId, long elanTag,
82             Long vni, String dstMacAddress, String displayName) {
83         List<MatchInfo> mkMatches =
84                 ElanUtils.buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, dstMacAddress);
85         List<Instruction> mkInstructions = new ArrayList<>();
86         try {
87             List<Action> actions =
88                     elanItmUtils.getExternalTunnelItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni);
89             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
90         } catch (Exception e) {
91             LOG.error("Could not get Egress Actions for DpId=" + dpId + ", externalNode=" + extDeviceNodeId, e);
92         }
93
94         return MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
95                 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, dstMacAddress,
96                         elanTag, false),
97                 20, /* prio */
98                 displayName, 0, /* idleTimeout */
99                 0, /* hardTimeout */
100                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
101     }
102
103     /**
104      * Installs a Flow in the specified DPN's DMAC table. The flow is for a MAC
105      * that is connected remotely in an External Device (TOR) and that is
106      * accessible through an external tunnel. It also installs the flow for
107      * dropping the packet if it came over an ITM tunnel (that is, if the
108      * Split-Horizon flag is set)
109      *
110      * @param dpnId
111      *            Id of the DPN where the flow must be installed
112      * @param extDeviceNodeId
113      *            the ext device node id
114      * @param elanTag
115      *            the elan tag
116      * @param vni
117      *            the vni
118      * @param macAddress
119      *            the mac address
120      * @param displayName
121      *            the display name
122      * @param interfaceName
123      *            the interface name
124      *
125      * @return the dmac flows
126      * @throws ElanException in case of issues creating the flow objects
127      */
128     public List<ListenableFuture<Void>> installDmacFlowsToExternalRemoteMac(BigInteger dpnId,
129             String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
130             String interfaceName) throws ElanException {
131         synchronized (ElanUtils.getElanMacDPNKey(elanTag, macAddress, dpnId)) {
132             Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress,
133                     displayName);
134             ResourceBatchingManager.getInstance().put(
135                     ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flow, dpnId), flow);
136
137             Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress);
138             ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
139                     ElanUtils.getFlowIid(dropFlow, dpnId), dropFlow);
140             installEtreeDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName,
141                     interfaceName);
142         }
143         return Collections.emptyList();
144     }
145
146     /**
147      * Installs or removes flows in DMAC table for MACs that are/were located in
148      * an external Elan Device.
149      *
150      * @param dpId
151      *            Id of the DPN where the DMAC table is going to be modified
152      * @param extNodeId
153      *            Id of the External Device where the MAC is located
154      * @param elanTag
155      *            Id of the ELAN
156      * @param vni
157      *            VNI of the LogicalSwitch to which the MAC belongs to, and that
158      *            is associated with the ELAN
159      * @param macAddress
160      *            the mac address
161      * @param elanInstanceName
162      *            the elan instance name
163      * @param addOrRemove
164      *            Indicates if flows must be installed or removed.
165      * @param interfaceName
166      *            the interface name
167      * @throws ElanException in case of issues creating the flow objects
168      * @see org.opendaylight.genius.mdsalutil.MDSALUtil.MdsalOp
169      */
170     public void setupDmacFlowsToExternalRemoteMac(BigInteger dpId, String extNodeId, Long elanTag, Long vni,
171             String macAddress, String elanInstanceName, MDSALUtil.MdsalOp addOrRemove, String interfaceName)
172             throws ElanException {
173         if (addOrRemove == MDSALUtil.MdsalOp.CREATION_OP) {
174             installDmacFlowsToExternalRemoteMac(dpId, extNodeId, elanTag, vni, macAddress, elanInstanceName,
175                     interfaceName);
176         } else if (addOrRemove == MDSALUtil.MdsalOp.REMOVAL_OP) {
177             deleteDmacFlowsToExternalMac(elanTag, dpId, extNodeId, macAddress);
178         }
179     }
180
181     /**
182      * Delete dmac flows to external mac.
183      *
184      * @param elanTag
185      *            the elan tag
186      * @param dpId
187      *            the dp id
188      * @param extDeviceNodeId
189      *            the ext device node id
190      * @param macToRemove
191      *            the mac to remove
192      * @return dmac flow
193      */
194     public List<ListenableFuture<Void>> deleteDmacFlowsToExternalMac(long elanTag, BigInteger dpId,
195             String extDeviceNodeId, String macToRemove) {
196         List<ListenableFuture<Void>> result = Lists.newArrayList(
197             removeFlowThatSendsThePacketOnAnExternalTunnel(elanTag, dpId, extDeviceNodeId, macToRemove),
198             removeTheDropFlow(elanTag, dpId, extDeviceNodeId, macToRemove));
199         result.addAll(deleteEtreeDmacFlowsToExternalMac(elanTag, dpId, extDeviceNodeId, macToRemove));
200         return result;
201     }
202
203     private List<ListenableFuture<Void>> deleteEtreeDmacFlowsToExternalMac(
204             long elanTag, BigInteger dpId, String extDeviceNodeId, String macToRemove) {
205         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
206         if (etreeLeafTag != null) {
207             return Lists.newArrayList(
208                     removeFlowThatSendsThePacketOnAnExternalTunnel(
209                             etreeLeafTag.getEtreeLeafTag().getValue(), dpId, extDeviceNodeId, macToRemove),
210                     removeTheDropFlow(etreeLeafTag.getEtreeLeafTag().getValue(), dpId, extDeviceNodeId, macToRemove));
211         }
212         return Collections.emptyList();
213     }
214
215     private ListenableFuture<Void> removeTheDropFlow(
216             long elanTag, BigInteger dpId, String extDeviceNodeId, String macToRemove) {
217         String flowId =
218                 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
219                         elanTag, true);
220         Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
221         return ResourceBatchingManager.getInstance().delete(
222                 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flowToRemove, dpId));
223     }
224
225     private ListenableFuture<Void> removeFlowThatSendsThePacketOnAnExternalTunnel(long elanTag, BigInteger dpId,
226             String extDeviceNodeId, String macToRemove) {
227         String flowId =
228                 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
229                         elanTag, false);
230         Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
231         return ResourceBatchingManager.getInstance().delete(
232                 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flowToRemove, dpId));
233     }
234
235     private List<ListenableFuture<Void>> installEtreeDmacFlowsToExternalRemoteMac(
236             BigInteger dpnId, String extDeviceNodeId, Long elanTag,
237             Long vni, String macAddress, String displayName, String interfaceName) throws ElanException {
238         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
239         if (etreeLeafTag != null) {
240             return Lists.newArrayList(
241                 buildEtreeDmacFlowDropIfPacketComingFromTunnel(
242                     dpnId, extDeviceNodeId, macAddress, etreeLeafTag),
243                 buildEtreeDmacFlowForExternalRemoteMac(
244                         dpnId, extDeviceNodeId, vni, macAddress, displayName, interfaceName, etreeLeafTag));
245         }
246         return Collections.emptyList();
247     }
248
249     private ListenableFuture<Void> buildEtreeDmacFlowForExternalRemoteMac(
250             BigInteger dpnId, String extDeviceNodeId, Long vni,
251             String macAddress, String displayName, String interfaceName,
252             EtreeLeafTagName etreeLeafTag) {
253         boolean isRoot;
254         if (interfaceName == null) {
255             isRoot = true;
256         } else {
257             Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName);
258             isRoot = etreeInterface.isPresent() ? etreeInterface.get().getEtreeInterfaceType()
259                     == EtreeInterface.EtreeInterfaceType.Root : false;
260         }
261         if (isRoot) {
262             Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId,
263                     etreeLeafTag.getEtreeLeafTag().getValue(), vni, macAddress, displayName);
264             return ResourceBatchingManager.getInstance().put(
265                     ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flow, dpnId), flow);
266         }
267         return Futures.immediateFuture(null);
268     }
269
270     private ListenableFuture<Void> buildEtreeDmacFlowDropIfPacketComingFromTunnel(
271             BigInteger dpnId, String extDeviceNodeId, String macAddress, EtreeLeafTagName etreeLeafTag) {
272         if (etreeLeafTag != null) {
273             Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId,
274                     etreeLeafTag.getEtreeLeafTag().getValue(), macAddress);
275             return ResourceBatchingManager.getInstance().put(
276                     ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(dropFlow, dpnId),
277                     dropFlow);
278         }
279         return Futures.immediateFuture(null);
280     }
281
282     /**
283      * Builds the flow that drops the packet if it came through an external
284      * tunnel, that is, if the Split-Horizon flag is set.
285      *
286      * @param dpnId
287      *            DPN whose DMAC table is going to be modified
288      * @param extDeviceNodeId
289      *            Hwvtep node where the mac is attached to
290      * @param elanTag
291      *            ElanId to which the MAC is being added to
292      * @param dstMacAddress
293      *            The mac address to be programmed
294      */
295     private static Flow buildDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId,
296             Long elanTag, String dstMacAddress) {
297         List<MatchInfo> mkMatches =
298                 ElanUtils.buildMatchesForElanTagShFlagAndDstMac(elanTag, SH_FLAG_SET, dstMacAddress);
299         List<Instruction> mkInstructions = MDSALUtil.buildInstructionsDrop();
300         String flowId =
301                 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress,
302                         elanTag, true);
303
304         return MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, flowId, 20, /* prio */
305                 "Drop", 0, /* idleTimeout */
306                 0, /* hardTimeout */
307                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
308     }
309
310     private ListenableFuture<Void> buildEtreeDmacFlowForExternalRemoteMacWithBatch(
311             BigInteger dpnId, String extDeviceNodeId, Long vni, String macAddress, String displayName,
312             String interfaceName, EtreeLeafTagName etreeLeafTag) {
313
314         boolean isRoot;
315         if (interfaceName == null) {
316             isRoot = true;
317         } else {
318             Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName);
319             isRoot = etreeInterface.isPresent() ? etreeInterface.get().getEtreeInterfaceType()
320                     == EtreeInterface.EtreeInterfaceType.Root : false;
321         }
322         if (isRoot) {
323             Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId,
324                     etreeLeafTag.getEtreeLeafTag().getValue(), vni, macAddress, displayName);
325             return ResourceBatchingManager.getInstance().put(
326                     ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flow, dpnId), flow);
327         }
328         return Futures.immediateFuture(null);
329     }
330
331     private ListenableFuture<Void> buildEtreeDmacFlowDropIfPacketComingFromTunnelwithBatch(
332             BigInteger dpnId, String extDeviceNodeId, String macAddress, EtreeLeafTagName etreeLeafTag) {
333         if (etreeLeafTag != null) {
334             Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId,
335                     etreeLeafTag.getEtreeLeafTag().getValue(), macAddress);
336             return ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
337                     ElanUtils.getFlowIid(dropFlow, dpnId),dropFlow);
338         }
339         return Futures.immediateFuture(null);
340     }
341
342     public List<ListenableFuture<Void>> installDmacFlowsToExternalRemoteMacInBatch(
343             BigInteger dpnId, String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
344             String interfaceName) throws ElanException {
345
346         Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress,
347                 displayName);
348         Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress);
349         List<ListenableFuture<Void>> result = Lists.newArrayList(
350                 ResourceBatchingManager.getInstance().put(
351                     ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flow, dpnId), flow),
352                 ResourceBatchingManager.getInstance().put(
353                     ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(dropFlow, dpnId),
354                         dropFlow));
355         result.addAll(installEtreeDmacFlowsToExternalRemoteMacInBatch(
356                 dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName, interfaceName));
357         return result;
358     }
359
360     private List<ListenableFuture<Void>> installEtreeDmacFlowsToExternalRemoteMacInBatch(
361             BigInteger dpnId, String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
362             String interfaceName) throws ElanException {
363
364         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
365         if (etreeLeafTag != null) {
366             return Lists.newArrayList(
367                 buildEtreeDmacFlowDropIfPacketComingFromTunnelwithBatch(
368                         dpnId, extDeviceNodeId, macAddress, etreeLeafTag),
369                 buildEtreeDmacFlowForExternalRemoteMacWithBatch(
370                         dpnId, extDeviceNodeId, vni, macAddress, displayName, interfaceName, etreeLeafTag));
371         }
372         return Collections.emptyList();
373     }
374 }