EVPN RT2 Installing flows for RT2 received in prior
[netvirt.git] / vpnservice / elanmanager / 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
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.List;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
23 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
24 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
25 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
26 import org.opendaylight.netvirt.elan.utils.ElanConstants;
27 import org.opendaylight.netvirt.elan.utils.ElanUtils;
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;
42
43
44 @Singleton
45 public class EvpnMacVrfUtils {
46
47     private static final Logger LOG = LoggerFactory.getLogger(EvpnMacVrfUtils.class);
48     private final DataBroker dataBroker;
49     private final ElanUtils elanUtils;
50     private final IdManagerService idManager;
51     private final ElanEvpnFlowUtils elanEvpnFlowUtils;
52     private final IMdsalApiManager mdsalManager;
53
54     @Inject
55     public EvpnMacVrfUtils(final DataBroker dataBroker, final ElanUtils elanUtils,
56                            final IdManagerService idManager, ElanEvpnFlowUtils elanEvpnFlowUtils,
57                            IMdsalApiManager mdsalManager) {
58         this.dataBroker = dataBroker;
59         this.elanUtils = elanUtils;
60         this.idManager = idManager;
61         this.elanEvpnFlowUtils = elanEvpnFlowUtils;
62         this.mdsalManager = mdsalManager;
63     }
64
65     public Long getElanTagByMacvrfiid(InstanceIdentifier<MacVrfEntry> macVrfEntryIid) {
66         String elanName = getElanNameByMacvrfiid(macVrfEntryIid);
67         if (elanName == null) {
68             LOG.error("getElanTag: elanName is NULL for iid = {}", macVrfEntryIid);
69         }
70         ElanInstance elanInstance = ElanUtils.getElanInstanceByName(dataBroker, elanName);
71         Long elanTag = elanInstance.getElanTag();
72         if (elanTag == null || elanTag == 0L) {
73             elanTag = elanUtils.retrieveNewElanTag(idManager, elanName);
74         }
75         return elanTag;
76     }
77
78     public String getElanNameByMacvrfiid(InstanceIdentifier<MacVrfEntry> instanceIdentifier) {
79         ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
80         String rd = instanceIdentifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
81         String elanName = null;
82         InstanceIdentifier<EvpnRdToNetwork> iidEvpnRdToNet =
83                 InstanceIdentifier.builder(EvpnRdToNetworks.class).child(EvpnRdToNetwork.class,
84                         new EvpnRdToNetworkKey(rd)).build();
85         try {
86             Optional<EvpnRdToNetwork> evpnRdToNetwork =
87                     tx.read(LogicalDatastoreType.OPERATIONAL, iidEvpnRdToNet).checkedGet();
88             if (evpnRdToNetwork.isPresent()) {
89                 elanName = evpnRdToNetwork.get().getNetworkId();
90             }
91         } catch (ReadFailedException e) {
92             LOG.error("getElanName: unable to read elanName, exception ", e);
93         }
94         return elanName;
95     }
96
97     public InstanceIdentifier<MacVrfEntry> getMacVrfEntryIid(String rd, MacVrfEntry macVrfEntry) {
98         return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
99                 .child(MacVrfEntry.class, macVrfEntry.getKey());
100     }
101
102     public void updateEvpnDmacFlows(final String elanName, final boolean install) {
103         EvpnUtils evpnUtils = null;
104         String rd = evpnUtils.getEVpnRd(ElanUtils.getElanInstanceByName(dataBroker, elanName));
105         final InstanceIdentifier<VrfTables> iid = InstanceIdentifier.create(FibEntries.class)
106                 .child(VrfTables.class, new VrfTablesKey(rd));
107         ElanClusterUtils.asyncReadAndExecute(dataBroker, LogicalDatastoreType.CONFIGURATION, iid,
108                 new StringBuilder(elanName).append(":").append(rd).toString(),
109             (vrfTablesOptional) -> {
110                 if (!vrfTablesOptional.isPresent()) {
111                     return null;
112                 }
113                 List<MacVrfEntry> macVrfEntries = vrfTablesOptional.get().getMacVrfEntry();
114                 if (macVrfEntries == null || macVrfEntries.isEmpty()) {
115                     return null;
116                 }
117                 for (MacVrfEntry macVrfEntry : macVrfEntries) {
118                     InstanceIdentifier<MacVrfEntry> macVrfEntryIid = getMacVrfEntryIid(rd, macVrfEntry);
119                     if (install) {
120                         addEvpnDmacFlow(macVrfEntryIid, macVrfEntry);
121                     } else {
122                         removeEvpnDmacFlow(macVrfEntryIid, macVrfEntry);
123                     }
124                 }
125                 return null;
126             });
127     }
128
129     public boolean checkEvpnAttachedToNet(String elanName) {
130         ElanInstance elanInfo = elanUtils.getElanInstanceByName(dataBroker, elanName);
131         String evpnName = EvpnUtils.getEvpnNameFromElan(elanInfo);
132         if (evpnName == null) {
133             LOG.error("Error : evpnName is null for elanName {}", elanName);
134             return false;
135         }
136         return true;
137     }
138
139     public void addEvpnDmacFlow(InstanceIdentifier<MacVrfEntry> instanceIdentifier, MacVrfEntry macVrfEntry) {
140         String elanName = getElanNameByMacvrfiid(instanceIdentifier);
141         if (elanName == null) {
142             LOG.error("Error : elanName is null for iid {}", instanceIdentifier);
143             return;
144         }
145
146         List<DpnInterfaces> dpnInterfaceLists = elanUtils.getInvolvedDpnsInElan(elanName);
147         if (dpnInterfaceLists == null) {
148             LOG.error("Error : dpnInterfaceLists is null for elan {}", elanName);
149             return;
150         }
151
152         if (checkEvpnAttachedToNet(elanName)) {
153             //TODO(Riyaz) : Check if accessing first nexthop address is right solution
154             String nexthopIP = macVrfEntry.getRoutePaths().get(0).getNexthopAddress();
155             Long elanTag = getElanTagByMacvrfiid(instanceIdentifier);
156             String dstMacAddress = macVrfEntry.getMac();
157             long vni = macVrfEntry.getL2vni();
158             DataStoreJobCoordinator.getInstance().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(nexthopIP).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.getInvolvedDpnsInElan(elanName);
184         if (dpnInterfaceLists == null) {
185             LOG.error("Error : dpnInterfaceLists is null for elan {}", elanName);
186             return;
187         }
188
189         if (checkEvpnAttachedToNet(elanName)) {
190             //TODO(Riyaz) : Check if accessing first nexthop address is right
191             String nexthopIP = macVrfEntry.getRoutePaths().get(0).getNexthopAddress();
192             Long elanTag = getElanTagByMacvrfiid(instanceIdentifier);
193             String macToRemove = macVrfEntry.getMac();
194             DataStoreJobCoordinator.getInstance().enqueueJob(macToRemove, () -> {
195                 List<ListenableFuture<Void>> futures = new ArrayList<>();
196                 dpnInterfaceLists.forEach(dpnInterfaces -> {
197                     BigInteger dpId = dpnInterfaces.getDpId();
198                     ElanEvpnFlowUtils.EvpnDmacFlowBuilder dmacFlowBuilder = new ElanEvpnFlowUtils.EvpnDmacFlowBuilder();
199                     dmacFlowBuilder.setDpId(dpId).setNexthopIP(nexthopIP).setElanTag(elanTag)
200                             .setDstMacAddress(macToRemove);
201                     LOG.info("REMOVE: Deleting DMAC Flows for external MAC. elanTag {}, dpId {},"
202                             + "nexthopIP {}, macToRemove {}", elanTag, dpId, nexthopIP, macToRemove);
203                     elanEvpnFlowUtils.evpnDeleteDmacFlowsToExternalMac(dmacFlowBuilder.build());
204                 });
205                 return futures;
206             }, ElanConstants.JOB_MAX_RETRIES);
207         }
208     }
209 }