2 * Copyright © 2017 Red Hat, Inc. and others.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.elan.utils;
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;
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;
41 public class ElanDmacUtils {
42 private static final Logger LOG = LoggerFactory.getLogger(ElanDmacUtils.class);
44 private static final boolean SH_FLAG_SET = true;
45 private static final boolean SH_FLAG_UNSET = false;
47 private final ElanItmUtils elanItmUtils;
48 private final ElanEtreeUtils elanEtreeUtils;
49 private final ElanInterfaceCache elanInterfaceCache;
52 public ElanDmacUtils(ElanItmUtils elanItmUtils, ElanEtreeUtils elanEtreeUtils,
53 ElanInterfaceCache elanInterfaceCache) {
54 this.elanItmUtils = elanItmUtils;
55 this.elanEtreeUtils = elanEtreeUtils;
56 this.elanInterfaceCache = elanInterfaceCache;
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)
67 * DPN whose DMAC table is going to be modified
68 * @param extDeviceNodeId
69 * Hwvtep node where the mac is attached to
71 * ElanId to which the MAC is being added to
74 * @param dstMacAddress
75 * The mac address to be programmed
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<>();
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);
94 return MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
95 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, dstMacAddress,
98 displayName, 0, /* idleTimeout */
100 Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
101 mkMatches, mkInstructionsMap);
105 * Delete dmac flows to external mac.
111 * @param extDeviceNodeId
112 * the ext device node id
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));
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));
136 return Collections.emptyList();
139 private static ListenableFuture<Void> removeTheDropFlow(
140 long elanTag, Uint64 dpId, String extDeviceNodeId, String macToRemove) {
142 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
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));
149 private static ListenableFuture<Void> removeFlowThatSendsThePacketOnAnExternalTunnel(long elanTag, Uint64 dpId,
150 String extDeviceNodeId, String macToRemove) {
152 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
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));
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.
164 * DPN whose DMAC table is going to be modified
165 * @param extDeviceNodeId
166 * Hwvtep node where the mac is attached to
168 * ElanId to which the MAC is being added to
169 * @param dstMacAddress
170 * The mac address to be programmed
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);
183 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress,
186 return MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, flowId, 20, /* prio */
187 "Drop", 0, /* idleTimeout */
189 Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
190 mkMatches, mkInstructionsMap);
193 private ListenableFuture<Void> buildEtreeDmacFlowForExternalRemoteMacWithBatch(
194 Uint64 dpnId, String extDeviceNodeId, Long vni, String macAddress, String displayName,
195 @Nullable String interfaceName, EtreeLeafTagName etreeLeafTag) {
198 if (interfaceName == null) {
201 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName);
202 isRoot = etreeInterface.isPresent()
203 && etreeInterface.get().getEtreeInterfaceType() == EtreeInterface.EtreeInterfaceType.Root;
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);
211 return Futures.immediateFuture(null);
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);
222 return Futures.immediateFuture(null);
225 public List<ListenableFuture<Void>> installDmacFlowsToExternalRemoteMacInBatch(
226 Uint64 dpnId, String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
227 @Nullable String interfaceName) {
229 Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress,
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),
238 result.addAll(installEtreeDmacFlowsToExternalRemoteMacInBatch(
239 dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName, interfaceName));
243 private List<ListenableFuture<Void>> installEtreeDmacFlowsToExternalRemoteMacInBatch(
244 Uint64 dpnId, String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
245 @Nullable String interfaceName) {
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));
255 return Collections.emptyList();