Remove GENIUS UTIL references in Elanmanager Module
[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.collect.Lists;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.math.BigInteger;
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Optional;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.genius.mdsalutil.MatchInfo;
24 import org.opendaylight.genius.mdsalutil.NwConstants;
25 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
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.flow.types.rev131026.instruction.list.InstructionKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
36 import org.opendaylight.yangtools.yang.common.Uint64;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 @Singleton
41 public class ElanDmacUtils {
42     private static final Logger LOG = LoggerFactory.getLogger(ElanDmacUtils.class);
43
44     private static final boolean SH_FLAG_SET = true;
45     private static final boolean SH_FLAG_UNSET = false;
46
47     private final ElanItmUtils elanItmUtils;
48     private final ElanEtreeUtils elanEtreeUtils;
49     private final ElanInterfaceCache elanInterfaceCache;
50
51     @Inject
52     public ElanDmacUtils(ElanItmUtils elanItmUtils, ElanEtreeUtils elanEtreeUtils,
53             ElanInterfaceCache elanInterfaceCache) {
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(Uint64 dpId, String extDeviceNodeId, long elanTag,
82             Long vni, String dstMacAddress, String displayName) {
83         List<MatchInfo> mkMatches =
84                 ElanUtils.buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, dstMacAddress);
85         Map<InstructionKey, Instruction> mkInstructionsMap = new HashMap<>();
86         try {
87             List<Action> actions =
88                     elanItmUtils.getExternalTunnelItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni);
89             mkInstructionsMap.put(new InstructionKey(0), MDSALUtil.buildApplyActionsInstruction(actions));
90         } catch (Exception e) {
91             LOG.error("Could not get Egress Actions for DpId {} externalNode {}", dpId, 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                 Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
101                 mkMatches, mkInstructionsMap);
102     }
103
104     /**
105      * Delete dmac flows to external mac.
106      *
107      * @param elanTag
108      *            the elan tag
109      * @param dpId
110      *            the dp id
111      * @param extDeviceNodeId
112      *            the ext device node id
113      * @param macToRemove
114      *            the mac to remove
115      * @return dmac flow
116      */
117     public List<ListenableFuture<Void>> deleteDmacFlowsToExternalMac(long elanTag, Uint64 dpId,
118             String extDeviceNodeId, String macToRemove) {
119         List<ListenableFuture<Void>> result = Lists.newArrayList(
120             removeFlowThatSendsThePacketOnAnExternalTunnel(elanTag, dpId, extDeviceNodeId, macToRemove),
121             removeTheDropFlow(elanTag, dpId, extDeviceNodeId, macToRemove));
122         result.addAll(deleteEtreeDmacFlowsToExternalMac(elanTag, dpId, extDeviceNodeId, macToRemove));
123         return result;
124     }
125
126     private List<ListenableFuture<Void>> deleteEtreeDmacFlowsToExternalMac(
127             long elanTag, Uint64 dpId, String extDeviceNodeId, String macToRemove) {
128         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
129         if (etreeLeafTag != null) {
130             return Lists.newArrayList(
131                     removeFlowThatSendsThePacketOnAnExternalTunnel(
132                             etreeLeafTag.getEtreeLeafTag().getValue().toJava(), dpId, extDeviceNodeId, macToRemove),
133                     removeTheDropFlow(etreeLeafTag.getEtreeLeafTag().getValue().toJava(), dpId,
134                             extDeviceNodeId, macToRemove));
135         }
136         return Collections.emptyList();
137     }
138
139     private static ListenableFuture<Void> removeTheDropFlow(
140             long elanTag, Uint64 dpId, String extDeviceNodeId, String macToRemove) {
141         String flowId =
142                 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
143                         elanTag, true);
144         Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
145         return ResourceBatchingManager.getInstance().delete(
146                 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flowToRemove, dpId));
147     }
148
149     private static ListenableFuture<Void> removeFlowThatSendsThePacketOnAnExternalTunnel(long elanTag, Uint64 dpId,
150             String extDeviceNodeId, String macToRemove) {
151         String flowId =
152                 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
153                         elanTag, false);
154         Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
155         return ResourceBatchingManager.getInstance().delete(
156                 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flowToRemove, dpId));
157     }
158
159     /**
160      * Builds the flow that drops the packet if it came through an external
161      * tunnel, that is, if the Split-Horizon flag is set.
162      *
163      * @param dpnId
164      *            DPN whose DMAC table is going to be modified
165      * @param extDeviceNodeId
166      *            Hwvtep node where the mac is attached to
167      * @param elanTag
168      *            ElanId to which the MAC is being added to
169      * @param dstMacAddress
170      *            The mac address to be programmed
171      */
172     private static Flow buildDmacFlowDropIfPacketComingFromTunnel(Uint64 dpnId, String extDeviceNodeId,
173             Long elanTag, String dstMacAddress) {
174         List<MatchInfo> mkMatches =
175                 ElanUtils.buildMatchesForElanTagShFlagAndDstMac(elanTag, SH_FLAG_SET, dstMacAddress);
176         List<Instruction> mkInstructions = MDSALUtil.buildInstructionsDrop();
177         Map<InstructionKey, Instruction> mkInstructionsMap = new HashMap<InstructionKey, Instruction>();
178         int instructionKey = 0;
179         for (Instruction instructionObj : mkInstructions) {
180             mkInstructionsMap.put(new InstructionKey(++instructionKey), instructionObj);
181         }
182         String flowId =
183                 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress,
184                         elanTag, true);
185
186         return MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, flowId, 20, /* prio */
187                 "Drop", 0, /* idleTimeout */
188                 0, /* hardTimeout */
189                 Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
190                 mkMatches, mkInstructionsMap);
191     }
192
193     private ListenableFuture<Void> buildEtreeDmacFlowForExternalRemoteMacWithBatch(
194             Uint64 dpnId, String extDeviceNodeId, Long vni, String macAddress, String displayName,
195             @Nullable String interfaceName, EtreeLeafTagName etreeLeafTag) {
196
197         boolean isRoot;
198         if (interfaceName == null) {
199             isRoot = true;
200         } else {
201             Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName);
202             isRoot = etreeInterface.isPresent()
203                 && etreeInterface.get().getEtreeInterfaceType() == EtreeInterface.EtreeInterfaceType.Root;
204         }
205         if (isRoot) {
206             Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId,
207                     etreeLeafTag.getEtreeLeafTag().getValue().toJava(), vni, macAddress, displayName);
208             return ResourceBatchingManager.getInstance().put(
209                     ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flow, dpnId), flow);
210         }
211         return Futures.immediateFuture(null);
212     }
213
214     private static ListenableFuture<Void> buildEtreeDmacFlowDropIfPacketComingFromTunnelwithBatch(
215             Uint64 dpnId, String extDeviceNodeId, String macAddress, EtreeLeafTagName etreeLeafTag) {
216         if (etreeLeafTag != null) {
217             Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId,
218                     etreeLeafTag.getEtreeLeafTag().getValue().toJava(), macAddress);
219             return ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
220                     ElanUtils.getFlowIid(dropFlow, dpnId),dropFlow);
221         }
222         return Futures.immediateFuture(null);
223     }
224
225     public List<ListenableFuture<Void>> installDmacFlowsToExternalRemoteMacInBatch(
226             Uint64 dpnId, String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
227             @Nullable String interfaceName) {
228
229         Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress,
230                 displayName);
231         Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress);
232         List<ListenableFuture<Void>> result = Lists.newArrayList(
233                 ResourceBatchingManager.getInstance().put(
234                     ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flow, dpnId), flow),
235                 ResourceBatchingManager.getInstance().put(
236                     ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(dropFlow, dpnId),
237                         dropFlow));
238         result.addAll(installEtreeDmacFlowsToExternalRemoteMacInBatch(
239                 dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName, interfaceName));
240         return result;
241     }
242
243     private List<ListenableFuture<Void>> installEtreeDmacFlowsToExternalRemoteMacInBatch(
244             Uint64 dpnId, String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
245             @Nullable String interfaceName) {
246
247         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
248         if (etreeLeafTag != null) {
249             return Lists.newArrayList(
250                 buildEtreeDmacFlowDropIfPacketComingFromTunnelwithBatch(
251                         dpnId, extDeviceNodeId, macAddress, etreeLeafTag),
252                 buildEtreeDmacFlowForExternalRemoteMacWithBatch(
253                         dpnId, extDeviceNodeId, vni, macAddress, displayName, interfaceName, etreeLeafTag));
254         }
255         return Collections.emptyList();
256     }
257 }