2 * Copyright © 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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.evpn.utils;
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
21 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
22 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
23 import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
24 import org.opendaylight.netvirt.elan.utils.ElanConstants;
25 import org.opendaylight.netvirt.elan.utils.ElanUtils;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.macvrfentries.MacVrfEntry;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.EvpnRdToNetworks;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.evpn.rd.to.networks.EvpnRdToNetwork;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.evpn.rd.to.networks.EvpnRdToNetworkKey;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 public class EvpnMacVrfUtils {
46 private static final Logger LOG = LoggerFactory.getLogger(EvpnMacVrfUtils.class);
47 private final DataBroker dataBroker;
48 private final ElanInstanceManager elanInstanceManager;
49 private final IdManagerService idManager;
50 private final ElanEvpnFlowUtils elanEvpnFlowUtils;
51 private final IMdsalApiManager mdsalManager;
52 private final EvpnUtils evpnUtils;
53 private final JobCoordinator jobCoordinator;
56 public EvpnMacVrfUtils(final DataBroker dataBroker, final ElanInstanceManager elanInstanceManager,
57 final IdManagerService idManager, final ElanEvpnFlowUtils elanEvpnFlowUtils,
58 final IMdsalApiManager mdsalManager, final EvpnUtils evpnUtils,
59 final JobCoordinator jobCoordinator) {
60 this.dataBroker = dataBroker;
61 this.elanInstanceManager = elanInstanceManager;
62 this.idManager = idManager;
63 this.elanEvpnFlowUtils = elanEvpnFlowUtils;
64 this.mdsalManager = mdsalManager;
65 this.evpnUtils = evpnUtils;
66 this.jobCoordinator = jobCoordinator;
69 public Long getElanTagByMacvrfiid(InstanceIdentifier<MacVrfEntry> macVrfEntryIid) {
70 String elanName = getElanNameByMacvrfiid(macVrfEntryIid);
71 if (elanName == null) {
72 LOG.error("getElanTag: elanName is NULL for iid = {}", macVrfEntryIid);
74 ElanInstance elanInstance = ElanUtils.getElanInstanceByName(dataBroker, elanName);
75 Long elanTag = elanInstance.getElanTag();
76 if (elanTag == null || elanTag == 0L) {
77 elanTag = ElanUtils.retrieveNewElanTag(idManager, elanName);
82 public String getElanNameByMacvrfiid(InstanceIdentifier<MacVrfEntry> instanceIdentifier) {
83 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
84 String rd = instanceIdentifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
85 String elanName = null;
86 InstanceIdentifier<EvpnRdToNetwork> iidEvpnRdToNet =
87 InstanceIdentifier.builder(EvpnRdToNetworks.class).child(EvpnRdToNetwork.class,
88 new EvpnRdToNetworkKey(rd)).build();
90 Optional<EvpnRdToNetwork> evpnRdToNetwork =
91 tx.read(LogicalDatastoreType.CONFIGURATION, iidEvpnRdToNet).checkedGet();
92 if (evpnRdToNetwork.isPresent()) {
93 elanName = evpnRdToNetwork.get().getNetworkId();
95 } catch (ReadFailedException e) {
96 LOG.error("getElanName: unable to read elanName, exception ", e);
101 public InstanceIdentifier<MacVrfEntry> getMacVrfEntryIid(String rd, MacVrfEntry macVrfEntry) {
102 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
103 .child(MacVrfEntry.class, macVrfEntry.getKey());
106 public void updateEvpnDmacFlows(final ElanInstance elanInstance, final boolean install) {
107 String rd = evpnUtils.getEvpnRd(elanInstance);
111 final InstanceIdentifier<VrfTables> iid = InstanceIdentifier.create(FibEntries.class)
112 .child(VrfTables.class, new VrfTablesKey(rd));
113 evpnUtils.asyncReadAndExecute(LogicalDatastoreType.CONFIGURATION, iid,
114 new StringBuilder(elanInstance.getElanInstanceName()).append(":").append(rd).toString(),
115 (vrfTablesOptional) -> {
116 if (!vrfTablesOptional.isPresent()) {
119 List<MacVrfEntry> macVrfEntries = vrfTablesOptional.get().getMacVrfEntry();
120 if (macVrfEntries == null || macVrfEntries.isEmpty()) {
123 for (MacVrfEntry macVrfEntry : macVrfEntries) {
124 InstanceIdentifier<MacVrfEntry> macVrfEntryIid = getMacVrfEntryIid(rd, macVrfEntry);
126 addEvpnDmacFlowOnAttach(macVrfEntryIid, macVrfEntry, elanInstance);
128 removeEvpnDmacFlowOnDetach(macVrfEntryIid, macVrfEntry, elanInstance);
135 public boolean checkEvpnAttachedToNet(String elanName) {
136 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(dataBroker, elanName);
137 String evpnName = EvpnUtils.getEvpnNameFromElan(elanInfo);
138 if (evpnName == null) {
139 LOG.error("Error : evpnName is null for elanName {}", elanName);
145 public void addEvpnDmacFlow(InstanceIdentifier<MacVrfEntry> instanceIdentifier, MacVrfEntry macVrfEntry) {
146 String elanName = getElanNameByMacvrfiid(instanceIdentifier);
147 if (elanName == null) {
148 LOG.error("Error : elanName is null for iid {}", instanceIdentifier);
152 List<DpnInterfaces> dpnInterfaceLists = elanInstanceManager.getElanDPNByName(elanName);
153 if (checkEvpnAttachedToNet(elanName)) {
154 //TODO(Riyaz) : Check if accessing first nexthop address is right solution
155 String nexthopIP = macVrfEntry.getRoutePaths().get(0).getNexthopAddress();
156 IpAddress ipAddress = new IpAddress(new Ipv4Address(nexthopIP));
157 Long elanTag = getElanTagByMacvrfiid(instanceIdentifier);
158 String dstMacAddress = macVrfEntry.getMac();
159 long vni = macVrfEntry.getL2vni();
160 jobCoordinator.enqueueJob(dstMacAddress, () -> {
161 List<ListenableFuture<Void>> futures = new ArrayList<>();
162 dpnInterfaceLists.forEach(dpnInterfaces -> {
163 BigInteger dpId = dpnInterfaces.getDpId();
164 LOG.info("ADD: Build DMAC flow with dpId {}, nexthopIP {}, elanTag {},"
165 + "vni {}, dstMacAddress {}, elanName {} ",
166 dpId, nexthopIP, elanTag, vni, dstMacAddress, elanName);
167 ElanEvpnFlowUtils.EvpnDmacFlowBuilder dmacFlowBuilder = new ElanEvpnFlowUtils.EvpnDmacFlowBuilder();
168 dmacFlowBuilder.setDpId(dpId).setNexthopIP(ipAddress.toString()).setElanTag(elanTag).setVni(vni)
169 .setDstMacAddress(dstMacAddress).setElanName(elanName);
170 Flow flow = elanEvpnFlowUtils.evpnBuildDmacFlowForExternalRemoteMac(dmacFlowBuilder.build());
172 futures.add(mdsalManager.installFlow(dpId, flow));
175 }, ElanConstants.JOB_MAX_RETRIES);
179 public void removeEvpnDmacFlow(InstanceIdentifier<MacVrfEntry> instanceIdentifier, MacVrfEntry macVrfEntry) {
180 String elanName = getElanNameByMacvrfiid(instanceIdentifier);
181 if (elanName == null) {
182 LOG.error("Error : elanName is null for iid {}", instanceIdentifier);
185 List<DpnInterfaces> dpnInterfaceLists = elanInstanceManager.getElanDPNByName(elanName);
187 //if (checkEvpnAttachedToNet(elanName)) {
188 //TODO(Riyaz) : Check if accessing first nexthop address is right
189 String nexthopIP = macVrfEntry.getRoutePaths().get(0).getNexthopAddress();
190 IpAddress ipAddress = new IpAddress(new Ipv4Address(nexthopIP));
191 Long elanTag = getElanTagByMacvrfiid(instanceIdentifier);
192 String macToRemove = macVrfEntry.getMac();
193 jobCoordinator.enqueueJob(macToRemove, () -> {
194 List<ListenableFuture<Void>> futures = new ArrayList<>();
195 dpnInterfaceLists.forEach(dpnInterfaces -> {
196 BigInteger dpId = dpnInterfaces.getDpId();
197 ElanEvpnFlowUtils.EvpnDmacFlowBuilder dmacFlowBuilder = new ElanEvpnFlowUtils.EvpnDmacFlowBuilder();
198 dmacFlowBuilder.setDpId(dpId).setNexthopIP(ipAddress.toString()).setElanTag(elanTag)
199 .setDstMacAddress(macToRemove);
200 LOG.info("REMOVE: Deleting DMAC Flows for external MAC. elanTag {}, dpId {},"
201 + "nexthopIP {}, macToRemove {}", elanTag, dpId, nexthopIP, macToRemove);
202 futures.addAll(elanEvpnFlowUtils.evpnDeleteDmacFlowsToExternalMac(dmacFlowBuilder.build()));
205 }, ElanConstants.JOB_MAX_RETRIES);
208 public void addEvpnDmacFlowOnAttach(InstanceIdentifier<MacVrfEntry> instanceIdentifier, MacVrfEntry macVrfEntry,
209 ElanInstance elanInstance) {
210 //String elanName = getElanNameByMacvrfiid(instanceIdentifier);
211 if (elanInstance == null) {
212 LOG.error("Error : elanName is null for iid {}", instanceIdentifier);
216 String elanName = elanInstance.getElanInstanceName();
217 List<DpnInterfaces> dpnInterfaceLists = elanInstanceManager.getElanDPNByName(elanName);
219 if (checkEvpnAttachedToNet(elanName)) {
220 String nexthopIP = getRoutePathNexthopIp(macVrfEntry);
221 if (nexthopIP == null) {
222 LOG.debug("nexthopIP is null for iid {}", instanceIdentifier);
225 IpAddress ipAddress = new IpAddress(new Ipv4Address(nexthopIP));
226 Long elanTag = elanInstance.getElanTag();
227 String dstMacAddress = macVrfEntry.getMac();
228 long vni = macVrfEntry.getL2vni();
229 jobCoordinator.enqueueJob(dstMacAddress, () -> {
230 List<ListenableFuture<Void>> futures = new ArrayList<>();
231 dpnInterfaceLists.forEach(dpnInterfaces -> {
232 BigInteger dpId = dpnInterfaces.getDpId();
233 LOG.info("ADD: Build DMAC flow with dpId {}, nexthopIP {}, elanTag {},"
234 + "vni {}, dstMacAddress {}, elanName {} ",
235 dpId, nexthopIP, elanTag, vni, dstMacAddress, elanName);
236 ElanEvpnFlowUtils.EvpnDmacFlowBuilder dmacFlowBuilder = new ElanEvpnFlowUtils.EvpnDmacFlowBuilder();
237 dmacFlowBuilder.setDpId(dpId).setNexthopIP(ipAddress.toString()).setElanTag(elanTag).setVni(vni)
238 .setDstMacAddress(dstMacAddress).setElanName(elanName);
239 Flow flow = elanEvpnFlowUtils.evpnBuildDmacFlowForExternalRemoteMac(dmacFlowBuilder.build());
240 futures.add(mdsalManager.installFlow(dpId, flow));
243 }, ElanConstants.JOB_MAX_RETRIES);
247 public String getRoutePathNexthopIp(MacVrfEntry macVrfEntry) {
248 if (macVrfEntry.getRoutePaths() == null || macVrfEntry.getRoutePaths().isEmpty()) {
249 LOG.debug("RoutePaths is null or empty for macvrfentry {}", macVrfEntry);
252 return macVrfEntry.getRoutePaths().get(0).getNexthopAddress();
255 public void removeEvpnDmacFlowOnDetach(InstanceIdentifier<MacVrfEntry> instanceIdentifier, MacVrfEntry macVrfEntry,
256 ElanInstance elanInstance) {
257 //String elanName = getElanNameByMacvrfiid(instanceIdentifier);
258 if (elanInstance == null) {
259 LOG.error("Error : elanInstance is null for iid {}", instanceIdentifier);
262 List<DpnInterfaces> dpnInterfaceLists =
263 elanInstanceManager.getElanDPNByName(elanInstance.getElanInstanceName());
265 //if (checkEvpnAttachedToNet(elanName)) {
266 String nexthopIP = getRoutePathNexthopIp(macVrfEntry);
267 if (nexthopIP == null) {
268 LOG.debug("nexthopIP is null for iid {}", instanceIdentifier);
271 IpAddress ipAddress = new IpAddress(new Ipv4Address(nexthopIP));
272 Long elanTag = elanInstance.getElanTag();
273 String macToRemove = macVrfEntry.getMac();
274 jobCoordinator.enqueueJob(macToRemove, () -> {
275 List<ListenableFuture<Void>> futures = new ArrayList<>();
276 dpnInterfaceLists.forEach(dpnInterfaces -> {
277 BigInteger dpId = dpnInterfaces.getDpId();
278 ElanEvpnFlowUtils.EvpnDmacFlowBuilder dmacFlowBuilder = new ElanEvpnFlowUtils.EvpnDmacFlowBuilder();
279 dmacFlowBuilder.setDpId(dpId).setNexthopIP(ipAddress.toString()).setElanTag(elanTag)
280 .setDstMacAddress(macToRemove);
281 LOG.info("REMOVE: Deleting DMAC Flows for external MAC. elanTag {}, dpId {},"
282 + "nexthopIP {}, macToRemove {}", elanTag, dpId, nexthopIP, macToRemove);
283 elanEvpnFlowUtils.evpnDeleteDmacFlowsToExternalMac(dmacFlowBuilder.build());
286 }, ElanConstants.JOB_MAX_RETRIES);