add interface for VpnFootprintService
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnManagerImpl.java
1 /*
2  * Copyright (c) 2015 - 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.vpnmanager;
9
10 import java.math.BigInteger;
11 import java.util.Collection;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.Future;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
20 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
21 import org.opendaylight.genius.mdsalutil.NwConstants;
22 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
23 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
24 import org.opendaylight.netvirt.elanmanager.api.IElanService;
25 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
26 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
27 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
28 import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderUtil;
29 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
40 import org.opendaylight.yangtools.yang.common.RpcError;
41 import org.opendaylight.yangtools.yang.common.RpcResult;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class VpnManagerImpl implements IVpnManager {
46
47     private static final Logger LOG = LoggerFactory.getLogger(VpnManagerImpl.class);
48     private final DataBroker dataBroker;
49     private final VpnInterfaceManager vpnInterfaceManager;
50     private final VpnInstanceListener vpnInstanceListener;
51     private final IdManagerService idManager;
52     private final IMdsalApiManager mdsalManager;
53     private final VpnFootprintService vpnFootprintService;
54     private final OdlInterfaceRpcService ifaceMgrRpcService;
55     private final IElanService elanService;
56     private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
57
58     public VpnManagerImpl(final DataBroker dataBroker,
59                           final IdManagerService idManagerService,
60                           final VpnInstanceListener vpnInstanceListener,
61                           final VpnInterfaceManager vpnInterfaceManager,
62                           final IMdsalApiManager mdsalManager,
63                           final VpnFootprintService vpnFootprintService,
64                           final OdlInterfaceRpcService ifaceMgrRpcService,
65                           final IElanService elanService,
66                           final VpnSubnetRouteHandler vpnSubnetRouteHandler) {
67         this.dataBroker = dataBroker;
68         this.vpnInterfaceManager = vpnInterfaceManager;
69         this.vpnInstanceListener = vpnInstanceListener;
70         this.idManager = idManagerService;
71         this.mdsalManager = mdsalManager;
72         this.vpnFootprintService = vpnFootprintService;
73         this.ifaceMgrRpcService = ifaceMgrRpcService;
74         this.elanService = elanService;
75         this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
76     }
77
78     public void start() {
79         LOG.info("{} start", getClass().getSimpleName());
80         createIdPool();
81     }
82
83     private void createIdPool() {
84         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
85             .setPoolName(VpnConstants.VPN_IDPOOL_NAME)
86             .setLow(VpnConstants.VPN_IDPOOL_LOW)
87             .setHigh(VpnConstants.VPN_IDPOOL_HIGH)
88             .build();
89         try {
90             Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
91             if (result != null && result.get().isSuccessful()) {
92                 LOG.info("Created IdPool for VPN Service");
93             }
94         } catch (InterruptedException | ExecutionException e) {
95             LOG.error("Failed to create idPool for VPN Service", e);
96         }
97
98         // Now an IdPool for InterVpnLink endpoint's pseudo ports
99         CreateIdPoolInput createPseudoLporTagPool =
100             new CreateIdPoolInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME)
101                 .setLow(VpnConstants.LOWER_PSEUDO_LPORT_TAG)
102                 .setHigh(VpnConstants.UPPER_PSEUDO_LPORT_TAG)
103                 .build();
104         try {
105             Future<RpcResult<Void>> result = idManager.createIdPool(createPseudoLporTagPool);
106             if (result != null && result.get().isSuccessful()) {
107                 LOG.debug("Created IdPool for Pseudo Port tags");
108             } else {
109                 Collection<RpcError> errors = result.get().getErrors();
110                 StringBuilder errMsg = new StringBuilder();
111                 for (RpcError err : errors) {
112                     errMsg.append(err.getMessage()).append("\n");
113                 }
114                 LOG.error("IdPool creation for PseudoPort tags failed. Reasons: {}", errMsg);
115             }
116         } catch (InterruptedException | ExecutionException e) {
117             LOG.error("Failed to create idPool for Pseudo Port tags", e);
118         }
119     }
120
121     @Override
122     public void setFibManager(IFibManager fibManager) {
123
124     }
125
126     @Override
127     public void addExtraRoute(String vpnName, String destination, String nextHop, String rd, String routerID,
128         int label,RouteOrigin origin) {
129         LOG.info("Adding extra route with destination {}, nextHop {}, label{} and origin {}",
130             destination, nextHop, label, origin);
131         VpnInstanceOpDataEntry vpnOpEntry = VpnUtil.getVpnInstanceOpData(dataBroker, rd);
132         Boolean isVxlan = VpnUtil.isL3VpnOverVxLan(vpnOpEntry.getL3vni());
133         VrfEntry.EncapType encapType = VpnUtil.getEncapType(isVxlan);
134         vpnInterfaceManager.addExtraRoute(vpnName, destination, nextHop, rd, routerID, label, vpnOpEntry.getL3vni(),
135                 origin,/*intfName*/ null, null /*Adjacency*/, encapType, null);
136     }
137
138     @Override
139     public void delExtraRoute(String vpnName, String destination, String nextHop, String rd, String routerID) {
140         LOG.info("Deleting extra route with destination {} and nextHop {}", destination, nextHop);
141         vpnInterfaceManager.delExtraRoute(vpnName, destination, nextHop, rd, routerID, null, null);
142     }
143
144     @Override
145     public boolean isVPNConfigured() {
146         return vpnInstanceListener.isVPNConfigured();
147     }
148
149     @Override
150     public List<BigInteger> getDpnsOnVpn(String vpnInstanceName) {
151         return VpnUtil.getDpnsOnVpn(dataBroker, vpnInstanceName);
152     }
153
154     @Override
155     public boolean existsVpn(String vpnName) {
156         return VpnUtil.getVpnInstance(dataBroker, vpnName) != null;
157     }
158
159     @Override
160     public long getArpCacheTimeoutMillis() {
161         return ArpConstants.ARP_CACHE_TIMEOUT_MILLIS;
162     }
163
164     @Override
165     public void setupSubnetMacIntoVpnInstance(String vpnName, String subnetVpnName, String srcMacAddress,
166         BigInteger dpnId, WriteTransaction writeTx, int addOrRemove) {
167         if (vpnName == null) {
168             LOG.warn("Cannot setup subnet MAC {} on DPN {}, null vpnName", srcMacAddress, dpnId);
169             return;
170         }
171
172         VpnUtil.setupSubnetMacIntoVpnInstance(dataBroker, mdsalManager, vpnName, subnetVpnName,
173                 srcMacAddress, dpnId, writeTx, addOrRemove);
174     }
175
176     @Override
177     public void setupRouterGwMacFlow(String routerName, String routerGwMac, BigInteger dpnId, Uuid extNetworkId,
178             WriteTransaction writeTx, int addOrRemove) {
179         if (routerGwMac == null) {
180             LOG.warn("Failed to handle router GW flow in GW-MAC table. MAC address is missing for router-id {}",
181                     routerName);
182             return;
183         }
184
185         if (dpnId == null || BigInteger.ZERO.equals(dpnId)) {
186             LOG.error("Failed to handle router GW flow in GW-MAC table. DPN id is missing for router-id", routerName);
187             return;
188         }
189
190         Uuid vpnId = VpnUtil.getExternalNetworkVpnId(dataBroker, extNetworkId);
191         if (vpnId == null) {
192             LOG.warn("Network {} is not associated with VPN", extNetworkId.getValue());
193             return;
194         }
195
196         LOG.info("{} router GW MAC flow for router-id {} on switch {}",
197                 addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", routerName, dpnId);
198         boolean submit = false;
199         if (writeTx == null) {
200             submit = true;
201             writeTx = dataBroker.newWriteOnlyTransaction();
202         }
203
204         setupSubnetMacIntoVpnInstance(vpnId.getValue(), null, routerGwMac, dpnId, writeTx,
205                 addOrRemove);
206         if (submit) {
207             writeTx.submit();
208         }
209     }
210
211     @Override
212     public void setupArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps, String macAddress,
213             BigInteger dpnId, Uuid extNetworkId, WriteTransaction writeTx, int addOrRemove) {
214
215         if (dpnId == null || BigInteger.ZERO.equals(dpnId)) {
216             LOG.warn("Failed to install arp responder flows for router {}. DPN id is missing.", id);
217             return;
218         }
219
220         String extInterfaceName = elanService.getExternalElanInterface(extNetworkId.getValue(), dpnId);
221         if (extInterfaceName == null) {
222             LOG.warn("Failed to install responder flows for {}. No external interface found for DPN id {}", id, dpnId);
223             return;
224         }
225
226         Interface extInterfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, extInterfaceName);
227         if (extInterfaceState == null) {
228             LOG.debug("No interface state found for interface {}. Delaying responder flows for {}", extInterfaceName,
229                     id);
230             return;
231         }
232
233         Integer lportTag = extInterfaceState.getIfIndex();
234         if (lportTag == null) {
235             LOG.debug("No Lport tag found for interface {}. Delaying flows for router-id {}", extInterfaceName, id);
236             return;
237         }
238
239         long vpnId = (addOrRemove == NwConstants.ADD_FLOW) ? getVpnIdFromExtNetworkId(extNetworkId)
240                 : VpnConstants.INVALID_ID;
241         setupArpResponderFlowsToExternalNetworkIps(id, fixedIps, macAddress, dpnId, vpnId, extInterfaceName, lportTag,
242                 writeTx, addOrRemove);
243     }
244
245
246     @Override
247     public void setupArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps, String macAddress,
248             BigInteger dpnId, long vpnId, String extInterfaceName, int lportTag, WriteTransaction writeTx,
249             int addOrRemove) {
250         if (fixedIps == null || fixedIps.isEmpty()) {
251             LOG.debug("No external IPs defined for {}", id);
252             return;
253         }
254
255         LOG.info("{} ARP responder flows for {} fixed-ips {} on switch {}",
256                 addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", id, fixedIps, dpnId);
257
258         boolean submit = false;
259         if (writeTx == null) {
260             submit = true;
261             writeTx = dataBroker.newWriteOnlyTransaction();
262         }
263
264         for (String fixedIp : fixedIps) {
265             if (addOrRemove == NwConstants.ADD_FLOW) {
266                 installArpResponderFlowsToExternalNetworkIp(macAddress, dpnId, extInterfaceName, lportTag, vpnId,
267                         fixedIp, writeTx);
268             } else {
269                 removeArpResponderFlowsToExternalNetworkIp(dpnId, lportTag, fixedIp, writeTx);
270             }
271         }
272
273         if (submit) {
274             writeTx.submit();
275         }
276     }
277
278     @Override
279     public List<MatchInfoBase> getEgressMatchesForVpn(String vpnName) {
280         long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
281         if (vpnId == VpnConstants.INVALID_ID) {
282             LOG.warn("No VPN id found for {}", vpnName);
283             return Collections.emptyList();
284         }
285
286         return Collections
287                 .singletonList(new NxMatchRegister(VpnConstants.VPN_REG_ID, vpnId, MetaDataUtil.getVpnIdMaskForReg()));
288     }
289
290     private void installArpResponderFlowsToExternalNetworkIp(String macAddress, BigInteger dpnId,
291             String extInterfaceName, Integer lportTag, long vpnId, String fixedIp, WriteTransaction writeTx) {
292         String flowId = ArpResponderUtil.getFlowID(lportTag, fixedIp);
293         List<Instruction> instructions = ArpResponderUtil.getExtInterfaceInstructions(ifaceMgrRpcService,
294                 extInterfaceName, fixedIp, macAddress);
295         ArpResponderUtil.installFlow(mdsalManager, writeTx, dpnId, flowId, flowId,
296                 NwConstants.DEFAULT_ARP_FLOW_PRIORITY, ArpResponderUtil.generateCookie(lportTag, fixedIp),
297                 ArpResponderUtil.getMatchCriteria(lportTag, vpnId, fixedIp), instructions);
298     }
299
300     private void removeArpResponderFlowsToExternalNetworkIp(BigInteger dpnId, Integer lportTag, String fixedIp,
301             WriteTransaction writeTx) {
302         String flowId = ArpResponderUtil.getFlowID(lportTag, fixedIp);
303         ArpResponderUtil.removeFlow(mdsalManager, writeTx, dpnId, flowId);
304     }
305
306     private long getVpnIdFromExtNetworkId(Uuid extNetworkId) {
307         Uuid vpnInstanceId = VpnUtil.getExternalNetworkVpnId(dataBroker, extNetworkId);
308         if (vpnInstanceId == null) {
309             LOG.debug("Network {} is not associated with VPN", extNetworkId.getValue());
310             return VpnConstants.INVALID_ID;
311         }
312
313         return VpnUtil.getVpnId(dataBroker, vpnInstanceId.getValue());
314     }
315
316     @Override
317     public void onSubnetAddedToVpn(Subnetmap subnetmap, boolean isBgpVpn, Long elanTag) {
318         vpnSubnetRouteHandler.onSubnetAddedToVpn(subnetmap, isBgpVpn, elanTag);
319     }
320
321     @Override
322     public void onSubnetDeletedFromVpn(Subnetmap subnetmap, boolean isBgpVpn) {
323         vpnSubnetRouteHandler.onSubnetDeletedFromVpn(subnetmap, isBgpVpn);
324     }
325
326 }