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.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.annotation.Nullable;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
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.cache.ElanInterfaceCache;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 public class ElanDmacUtils {
39 private static final Logger LOG = LoggerFactory.getLogger(ElanDmacUtils.class);
41 private static final boolean SH_FLAG_SET = true;
42 private static final boolean SH_FLAG_UNSET = false;
44 private final ElanItmUtils elanItmUtils;
45 private final ElanEtreeUtils elanEtreeUtils;
46 private final ElanInterfaceCache elanInterfaceCache;
49 public ElanDmacUtils(ElanItmUtils elanItmUtils, ElanEtreeUtils elanEtreeUtils,
50 ElanInterfaceCache elanInterfaceCache) {
51 this.elanItmUtils = elanItmUtils;
52 this.elanEtreeUtils = elanEtreeUtils;
53 this.elanInterfaceCache = elanInterfaceCache;
57 * Builds a Flow to be programmed in a DPN's DMAC table. This method must be
58 * used when the MAC is located in an External Device (TOR). The flow
59 * matches on the specified MAC and 1) sends the packet over the CSS-TOR
60 * tunnel if SHFlag is not set, or 2) drops it if SHFlag is set (what means
61 * the packet came from an external tunnel)
64 * DPN whose DMAC table is going to be modified
65 * @param extDeviceNodeId
66 * Hwvtep node where the mac is attached to
68 * ElanId to which the MAC is being added to
71 * @param dstMacAddress
72 * The mac address to be programmed
77 @SuppressWarnings("checkstyle:IllegalCatch")
78 public Flow buildDmacFlowForExternalRemoteMac(BigInteger dpId, String extDeviceNodeId, long elanTag,
79 Long vni, String dstMacAddress, String displayName) {
80 List<MatchInfo> mkMatches =
81 ElanUtils.buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, dstMacAddress);
82 List<Instruction> mkInstructions = new ArrayList<>();
84 List<Action> actions =
85 elanItmUtils.getExternalTunnelItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni);
86 mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
87 } catch (Exception e) {
88 LOG.error("Could not get Egress Actions for DpId {} externalNode {}", dpId, extDeviceNodeId, e);
91 return MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
92 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, dstMacAddress,
95 displayName, 0, /* idleTimeout */
97 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
101 * Delete dmac flows to external mac.
107 * @param extDeviceNodeId
108 * the ext device node id
113 public List<ListenableFuture<Void>> deleteDmacFlowsToExternalMac(long elanTag, BigInteger dpId,
114 String extDeviceNodeId, String macToRemove) {
115 List<ListenableFuture<Void>> result = Lists.newArrayList(
116 removeFlowThatSendsThePacketOnAnExternalTunnel(elanTag, dpId, extDeviceNodeId, macToRemove),
117 removeTheDropFlow(elanTag, dpId, extDeviceNodeId, macToRemove));
118 result.addAll(deleteEtreeDmacFlowsToExternalMac(elanTag, dpId, extDeviceNodeId, macToRemove));
122 private List<ListenableFuture<Void>> deleteEtreeDmacFlowsToExternalMac(
123 long elanTag, BigInteger dpId, String extDeviceNodeId, String macToRemove) {
124 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
125 if (etreeLeafTag != null) {
126 return Lists.newArrayList(
127 removeFlowThatSendsThePacketOnAnExternalTunnel(
128 etreeLeafTag.getEtreeLeafTag().getValue(), dpId, extDeviceNodeId, macToRemove),
129 removeTheDropFlow(etreeLeafTag.getEtreeLeafTag().getValue(), dpId, extDeviceNodeId, macToRemove));
131 return Collections.emptyList();
134 private ListenableFuture<Void> removeTheDropFlow(
135 long elanTag, BigInteger dpId, String extDeviceNodeId, String macToRemove) {
137 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
139 Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
140 return ResourceBatchingManager.getInstance().delete(
141 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flowToRemove, dpId));
144 private ListenableFuture<Void> removeFlowThatSendsThePacketOnAnExternalTunnel(long elanTag, BigInteger dpId,
145 String extDeviceNodeId, String macToRemove) {
147 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
149 Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
150 return ResourceBatchingManager.getInstance().delete(
151 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flowToRemove, dpId));
155 * Builds the flow that drops the packet if it came through an external
156 * tunnel, that is, if the Split-Horizon flag is set.
159 * DPN whose DMAC table is going to be modified
160 * @param extDeviceNodeId
161 * Hwvtep node where the mac is attached to
163 * ElanId to which the MAC is being added to
164 * @param dstMacAddress
165 * The mac address to be programmed
167 private static Flow buildDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId,
168 Long elanTag, String dstMacAddress) {
169 List<MatchInfo> mkMatches =
170 ElanUtils.buildMatchesForElanTagShFlagAndDstMac(elanTag, SH_FLAG_SET, dstMacAddress);
171 List<Instruction> mkInstructions = MDSALUtil.buildInstructionsDrop();
173 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress,
176 return MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, flowId, 20, /* prio */
177 "Drop", 0, /* idleTimeout */
179 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
182 private ListenableFuture<Void> buildEtreeDmacFlowForExternalRemoteMacWithBatch(
183 BigInteger dpnId, String extDeviceNodeId, Long vni, String macAddress, String displayName,
184 @Nullable String interfaceName, EtreeLeafTagName etreeLeafTag) {
187 if (interfaceName == null) {
190 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName);
191 isRoot = etreeInterface.isPresent()
192 && etreeInterface.get().getEtreeInterfaceType() == EtreeInterface.EtreeInterfaceType.Root;
195 Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId,
196 etreeLeafTag.getEtreeLeafTag().getValue(), vni, macAddress, displayName);
197 return ResourceBatchingManager.getInstance().put(
198 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flow, dpnId), flow);
200 return Futures.immediateFuture(null);
203 private ListenableFuture<Void> buildEtreeDmacFlowDropIfPacketComingFromTunnelwithBatch(
204 BigInteger dpnId, String extDeviceNodeId, String macAddress, EtreeLeafTagName etreeLeafTag) {
205 if (etreeLeafTag != null) {
206 Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId,
207 etreeLeafTag.getEtreeLeafTag().getValue(), macAddress);
208 return ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
209 ElanUtils.getFlowIid(dropFlow, dpnId),dropFlow);
211 return Futures.immediateFuture(null);
214 public List<ListenableFuture<Void>> installDmacFlowsToExternalRemoteMacInBatch(
215 BigInteger dpnId, String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
216 @Nullable String interfaceName) {
218 Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress,
220 Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress);
221 List<ListenableFuture<Void>> result = Lists.newArrayList(
222 ResourceBatchingManager.getInstance().put(
223 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(flow, dpnId), flow),
224 ResourceBatchingManager.getInstance().put(
225 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, ElanUtils.getFlowIid(dropFlow, dpnId),
227 result.addAll(installEtreeDmacFlowsToExternalRemoteMacInBatch(
228 dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName, interfaceName));
232 private List<ListenableFuture<Void>> installEtreeDmacFlowsToExternalRemoteMacInBatch(
233 BigInteger dpnId, String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
234 @Nullable String interfaceName) {
236 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
237 if (etreeLeafTag != null) {
238 return Lists.newArrayList(
239 buildEtreeDmacFlowDropIfPacketComingFromTunnelwithBatch(
240 dpnId, extDeviceNodeId, macAddress, etreeLeafTag),
241 buildEtreeDmacFlowForExternalRemoteMacWithBatch(
242 dpnId, extDeviceNodeId, vni, macAddress, displayName, interfaceName, etreeLeafTag));
244 return Collections.emptyList();