Remove redundant names in paths
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / evpn / utils / EvpnMacVrfUtils.java
1 /*
2  * Copyright © 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
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.evpn.utils;
9
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.utils.ElanConstants;
24 import org.opendaylight.netvirt.elan.utils.ElanUtils;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.macvrfentries.MacVrfEntry;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.EvpnRdToNetworks;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.evpn.rd.to.networks.EvpnRdToNetwork;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.evpn.rd.to.networks.EvpnRdToNetworkKey;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 @Singleton
43 public class EvpnMacVrfUtils {
44
45     private static final Logger LOG = LoggerFactory.getLogger(EvpnMacVrfUtils.class);
46     private final DataBroker dataBroker;
47     private final IdManagerService idManager;
48     private final ElanEvpnFlowUtils elanEvpnFlowUtils;
49     private final IMdsalApiManager mdsalManager;
50     private final EvpnUtils evpnUtils;
51     private final JobCoordinator jobCoordinator;
52     private final ElanUtils elanUtils;
53
54     @Inject
55     public EvpnMacVrfUtils(final DataBroker dataBroker, final IdManagerService idManager,
56             final ElanEvpnFlowUtils elanEvpnFlowUtils, final IMdsalApiManager mdsalManager, final EvpnUtils evpnUtils,
57             final JobCoordinator jobCoordinator, final ElanUtils elanUtils) {
58         this.dataBroker = dataBroker;
59         this.idManager = idManager;
60         this.elanEvpnFlowUtils = elanEvpnFlowUtils;
61         this.mdsalManager = mdsalManager;
62         this.evpnUtils = evpnUtils;
63         this.jobCoordinator = jobCoordinator;
64         this.elanUtils = elanUtils;
65     }
66
67     public Long getElanTagByMacvrfiid(InstanceIdentifier<MacVrfEntry> macVrfEntryIid) {
68         String elanName = getElanNameByMacvrfiid(macVrfEntryIid);
69         if (elanName == null) {
70             LOG.error("getElanTag: elanName is NULL for iid = {}", macVrfEntryIid);
71         }
72         ElanInstance elanInstance = ElanUtils.getElanInstanceByName(dataBroker, elanName);
73         Long elanTag = elanInstance.getElanTag();
74         if (elanTag == null || elanTag == 0L) {
75             elanTag = ElanUtils.retrieveNewElanTag(idManager, elanName);
76         }
77         return elanTag;
78     }
79
80     public String getElanNameByMacvrfiid(InstanceIdentifier<MacVrfEntry> instanceIdentifier) {
81         ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
82         String rd = instanceIdentifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
83         String elanName = null;
84         InstanceIdentifier<EvpnRdToNetwork> iidEvpnRdToNet =
85                 InstanceIdentifier.builder(EvpnRdToNetworks.class).child(EvpnRdToNetwork.class,
86                         new EvpnRdToNetworkKey(rd)).build();
87         try {
88             Optional<EvpnRdToNetwork> evpnRdToNetwork =
89                     tx.read(LogicalDatastoreType.CONFIGURATION, iidEvpnRdToNet).checkedGet();
90             if (evpnRdToNetwork.isPresent()) {
91                 elanName = evpnRdToNetwork.get().getNetworkId();
92             }
93         } catch (ReadFailedException e) {
94             LOG.error("getElanName: unable to read elanName, exception ", e);
95         }
96         return elanName;
97     }
98
99     public InstanceIdentifier<MacVrfEntry> getMacVrfEntryIid(String rd, MacVrfEntry macVrfEntry) {
100         return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
101                 .child(MacVrfEntry.class, macVrfEntry.getKey());
102     }
103
104     public void updateEvpnDmacFlows(final ElanInstance elanInstance, final boolean install) {
105         String rd = evpnUtils.getEvpnRd(elanInstance);
106         if (rd == null) {
107             return;
108         }
109         final InstanceIdentifier<VrfTables> iid = InstanceIdentifier.create(FibEntries.class)
110                 .child(VrfTables.class, new VrfTablesKey(rd));
111         evpnUtils.asyncReadAndExecute(LogicalDatastoreType.CONFIGURATION, iid,
112                 new StringBuilder(elanInstance.getElanInstanceName()).append(":").append(rd).toString(),
113             (vrfTablesOptional) -> {
114                 if (!vrfTablesOptional.isPresent()) {
115                     return null;
116                 }
117                 List<MacVrfEntry> macVrfEntries = vrfTablesOptional.get().getMacVrfEntry();
118                 if (macVrfEntries == null || macVrfEntries.isEmpty()) {
119                     return null;
120                 }
121                 for (MacVrfEntry macVrfEntry : macVrfEntries) {
122                     InstanceIdentifier<MacVrfEntry> macVrfEntryIid = getMacVrfEntryIid(rd, macVrfEntry);
123                     if (install) {
124                         addEvpnDmacFlowOnAttach(macVrfEntryIid, macVrfEntry, elanInstance);
125                     } else {
126                         removeEvpnDmacFlowOnDetach(macVrfEntryIid, macVrfEntry, elanInstance);
127                     }
128                 }
129                 return null;
130             });
131     }
132
133     public boolean checkEvpnAttachedToNet(String elanName) {
134         ElanInstance elanInfo = ElanUtils.getElanInstanceByName(dataBroker, elanName);
135         String evpnName = EvpnUtils.getEvpnNameFromElan(elanInfo);
136         if (evpnName == null) {
137             LOG.error("Error : evpnName is null for elanName {}", elanName);
138             return false;
139         }
140         return true;
141     }
142
143     public void addEvpnDmacFlow(InstanceIdentifier<MacVrfEntry> instanceIdentifier, MacVrfEntry macVrfEntry) {
144         String elanName = getElanNameByMacvrfiid(instanceIdentifier);
145         if (elanName == null) {
146             LOG.error("Error : elanName is null for iid {}", instanceIdentifier);
147             return;
148         }
149
150         List<DpnInterfaces> dpnInterfaceLists = elanUtils.getElanDPNByName(elanName);
151         if (checkEvpnAttachedToNet(elanName)) {
152             //TODO(Riyaz) : Check if accessing first nexthop address is right solution
153             String nexthopIP = macVrfEntry.getRoutePaths().get(0).getNexthopAddress();
154             IpAddress ipAddress = new IpAddress(new Ipv4Address(nexthopIP));
155             Long elanTag = getElanTagByMacvrfiid(instanceIdentifier);
156             String dstMacAddress = macVrfEntry.getMac();
157             long vni = macVrfEntry.getL2vni();
158             jobCoordinator.enqueueJob(dstMacAddress, () -> {
159                 List<ListenableFuture<Void>> futures = new ArrayList<>();
160                 dpnInterfaceLists.forEach(dpnInterfaces -> {
161                     BigInteger dpId = dpnInterfaces.getDpId();
162                     LOG.info("ADD: Build DMAC flow with dpId {}, nexthopIP {}, elanTag {},"
163                                     + "vni {}, dstMacAddress {}, elanName {} ",
164                             dpId, nexthopIP, elanTag, vni, dstMacAddress, elanName);
165                     ElanEvpnFlowUtils.EvpnDmacFlowBuilder dmacFlowBuilder = new ElanEvpnFlowUtils.EvpnDmacFlowBuilder();
166                     dmacFlowBuilder.setDpId(dpId).setNexthopIP(ipAddress.toString()).setElanTag(elanTag).setVni(vni)
167                             .setDstMacAddress(dstMacAddress).setElanName(elanName);
168                     Flow flow = elanEvpnFlowUtils.evpnBuildDmacFlowForExternalRemoteMac(dmacFlowBuilder.build());
169
170                     futures.add(mdsalManager.installFlow(dpId, flow));
171                 });
172                 return futures;
173             }, ElanConstants.JOB_MAX_RETRIES);
174         }
175     }
176
177     public void removeEvpnDmacFlow(InstanceIdentifier<MacVrfEntry> instanceIdentifier, MacVrfEntry macVrfEntry) {
178         String elanName = getElanNameByMacvrfiid(instanceIdentifier);
179         if (elanName == null) {
180             LOG.error("Error : elanName is null for iid {}", instanceIdentifier);
181             return;
182         }
183         List<DpnInterfaces> dpnInterfaceLists = elanUtils.getElanDPNByName(elanName);
184
185         //if (checkEvpnAttachedToNet(elanName)) {
186         //TODO(Riyaz) : Check if accessing first nexthop address is right
187         String nexthopIP = macVrfEntry.getRoutePaths().get(0).getNexthopAddress();
188         IpAddress ipAddress = new IpAddress(new Ipv4Address(nexthopIP));
189         Long elanTag = getElanTagByMacvrfiid(instanceIdentifier);
190         String macToRemove = macVrfEntry.getMac();
191         jobCoordinator.enqueueJob(macToRemove, () -> {
192             List<ListenableFuture<Void>> futures = new ArrayList<>();
193             dpnInterfaceLists.forEach(dpnInterfaces -> {
194                 BigInteger dpId = dpnInterfaces.getDpId();
195                 ElanEvpnFlowUtils.EvpnDmacFlowBuilder dmacFlowBuilder = new ElanEvpnFlowUtils.EvpnDmacFlowBuilder();
196                 dmacFlowBuilder.setDpId(dpId).setNexthopIP(ipAddress.toString()).setElanTag(elanTag)
197                         .setDstMacAddress(macToRemove);
198                 LOG.info("REMOVE: Deleting DMAC Flows for external MAC. elanTag {}, dpId {},"
199                         + "nexthopIP {}, macToRemove {}", elanTag, dpId, nexthopIP, macToRemove);
200                 futures.addAll(elanEvpnFlowUtils.evpnDeleteDmacFlowsToExternalMac(dmacFlowBuilder.build()));
201             });
202             return futures;
203         }, ElanConstants.JOB_MAX_RETRIES);
204     }
205
206     public void addEvpnDmacFlowOnAttach(InstanceIdentifier<MacVrfEntry> instanceIdentifier, MacVrfEntry macVrfEntry,
207                                         ElanInstance elanInstance) {
208         //String elanName = getElanNameByMacvrfiid(instanceIdentifier);
209         if (elanInstance == null) {
210             LOG.error("Error : elanName is null for iid {}", instanceIdentifier);
211             return;
212         }
213
214         String elanName = elanInstance.getElanInstanceName();
215         List<DpnInterfaces> dpnInterfaceLists = elanUtils.getElanDPNByName(elanName);
216
217         if (checkEvpnAttachedToNet(elanName)) {
218             String nexthopIP = getRoutePathNexthopIp(macVrfEntry);
219             if (nexthopIP == null) {
220                 LOG.debug("nexthopIP is null for iid {}", instanceIdentifier);
221                 return;
222             }
223             IpAddress ipAddress = new IpAddress(new Ipv4Address(nexthopIP));
224             Long elanTag = elanInstance.getElanTag();
225             String dstMacAddress = macVrfEntry.getMac();
226             long vni = macVrfEntry.getL2vni();
227             jobCoordinator.enqueueJob(dstMacAddress, () -> {
228                 List<ListenableFuture<Void>> futures = new ArrayList<>();
229                 dpnInterfaceLists.forEach(dpnInterfaces -> {
230                     BigInteger dpId = dpnInterfaces.getDpId();
231                     LOG.info("ADD: Build DMAC flow with dpId {}, nexthopIP {}, elanTag {},"
232                                     + "vni {}, dstMacAddress {}, elanName {} ",
233                             dpId, nexthopIP, elanTag, vni, dstMacAddress, elanName);
234                     ElanEvpnFlowUtils.EvpnDmacFlowBuilder dmacFlowBuilder = new ElanEvpnFlowUtils.EvpnDmacFlowBuilder();
235                     dmacFlowBuilder.setDpId(dpId).setNexthopIP(ipAddress.toString()).setElanTag(elanTag).setVni(vni)
236                             .setDstMacAddress(dstMacAddress).setElanName(elanName);
237                     Flow flow = elanEvpnFlowUtils.evpnBuildDmacFlowForExternalRemoteMac(dmacFlowBuilder.build());
238                     futures.add(mdsalManager.installFlow(dpId, flow));
239                 });
240                 return futures;
241             }, ElanConstants.JOB_MAX_RETRIES);
242         }
243     }
244
245     public String getRoutePathNexthopIp(MacVrfEntry macVrfEntry) {
246         if (macVrfEntry.getRoutePaths() == null || macVrfEntry.getRoutePaths().isEmpty()) {
247             LOG.debug("RoutePaths is null or empty for macvrfentry {}", macVrfEntry);
248             return null;
249         }
250         return macVrfEntry.getRoutePaths().get(0).getNexthopAddress();
251     }
252
253     public void removeEvpnDmacFlowOnDetach(InstanceIdentifier<MacVrfEntry> instanceIdentifier, MacVrfEntry macVrfEntry,
254                                            ElanInstance elanInstance) {
255         //String elanName = getElanNameByMacvrfiid(instanceIdentifier);
256         if (elanInstance == null) {
257             LOG.error("Error : elanInstance is null for iid {}", instanceIdentifier);
258             return;
259         }
260         List<DpnInterfaces> dpnInterfaceLists = elanUtils.getElanDPNByName(elanInstance.getElanInstanceName());
261
262         //if (checkEvpnAttachedToNet(elanName)) {
263         String nexthopIP = getRoutePathNexthopIp(macVrfEntry);
264         if (nexthopIP == null) {
265             LOG.debug("nexthopIP is null for iid {}", instanceIdentifier);
266             return;
267         }
268         IpAddress ipAddress = new IpAddress(new Ipv4Address(nexthopIP));
269         Long elanTag = elanInstance.getElanTag();
270         String macToRemove = macVrfEntry.getMac();
271         jobCoordinator.enqueueJob(macToRemove, () -> {
272             List<ListenableFuture<Void>> futures = new ArrayList<>();
273             dpnInterfaceLists.forEach(dpnInterfaces -> {
274                 BigInteger dpId = dpnInterfaces.getDpId();
275                 ElanEvpnFlowUtils.EvpnDmacFlowBuilder dmacFlowBuilder = new ElanEvpnFlowUtils.EvpnDmacFlowBuilder();
276                 dmacFlowBuilder.setDpId(dpId).setNexthopIP(ipAddress.toString()).setElanTag(elanTag)
277                         .setDstMacAddress(macToRemove);
278                 LOG.info("REMOVE: Deleting DMAC Flows for external MAC. elanTag {}, dpId {},"
279                         + "nexthopIP {}, macToRemove {}", elanTag, dpId, nexthopIP, macToRemove);
280                 elanEvpnFlowUtils.evpnDeleteDmacFlowsToExternalMac(dmacFlowBuilder.build());
281             });
282             return futures;
283         }, ElanConstants.JOB_MAX_RETRIES);
284     }
285 }