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