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