EVPN RT2 elan changes to adv/withdraw RT2 routes..
[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 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.MatchInfoBase;
19 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
22 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
23 import org.opendaylight.netvirt.elanmanager.api.IElanService;
24 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
25 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
26 import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderUtil;
27 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
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 addExtraRoute(String vpnName, String destination, String nextHop, String rd, String routerID,
123         int label,RouteOrigin origin) {
124         LOG.info("Adding extra route with destination {}, nextHop {}, label{} and origin {}",
125             destination, nextHop, label, origin);
126         VpnInstanceOpDataEntry vpnOpEntry = VpnUtil.getVpnInstanceOpData(dataBroker, rd);
127         Boolean isVxlan = VpnUtil.isL3VpnOverVxLan(vpnOpEntry.getL3vni());
128         VrfEntry.EncapType encapType = VpnUtil.getEncapType(isVxlan);
129         vpnInterfaceManager.addExtraRoute(vpnName, destination, nextHop, rd, routerID, label, vpnOpEntry.getL3vni(),
130                 origin,/*intfName*/ null, null /*Adjacency*/, encapType, null);
131     }
132
133     @Override
134     public void delExtraRoute(String vpnName, String destination, String nextHop, String rd, String routerID) {
135         LOG.info("Deleting extra route with destination {} and nextHop {}", destination, nextHop);
136         vpnInterfaceManager.delExtraRoute(vpnName, destination, nextHop, rd, routerID, null, null);
137     }
138
139     @Override
140     public boolean isVPNConfigured() {
141         return vpnInstanceListener.isVPNConfigured();
142     }
143
144     @Override
145     public List<BigInteger> getDpnsOnVpn(String vpnInstanceName) {
146         return VpnUtil.getDpnsOnVpn(dataBroker, vpnInstanceName);
147     }
148
149     @Override
150     public boolean existsVpn(String vpnName) {
151         return VpnUtil.getVpnInstance(dataBroker, vpnName) != null;
152     }
153
154     @Override
155     public void setupSubnetMacIntoVpnInstance(String vpnName, String subnetVpnName, String srcMacAddress,
156         BigInteger dpnId, WriteTransaction writeTx, int addOrRemove) {
157         if (vpnName == null) {
158             LOG.warn("Cannot setup subnet MAC {} on DPN {}, null vpnName", srcMacAddress, dpnId);
159             return;
160         }
161
162         VpnUtil.setupSubnetMacIntoVpnInstance(dataBroker, mdsalManager, vpnName, subnetVpnName,
163                 srcMacAddress, dpnId, writeTx, addOrRemove);
164     }
165
166     @Override
167     public void setupRouterGwMacFlow(String routerName, String routerGwMac, BigInteger dpnId, Uuid extNetworkId,
168             WriteTransaction writeTx, int addOrRemove) {
169         if (routerGwMac == null) {
170             LOG.warn("Failed to handle router GW flow in GW-MAC table. MAC address is missing for router-id {}",
171                     routerName);
172             return;
173         }
174
175         if (dpnId == null || BigInteger.ZERO.equals(dpnId)) {
176             LOG.error("Failed to handle router GW flow in GW-MAC table. DPN id is missing for router-id", routerName);
177             return;
178         }
179
180         Uuid vpnId = VpnUtil.getExternalNetworkVpnId(dataBroker, extNetworkId);
181         if (vpnId == null) {
182             LOG.warn("Network {} is not associated with VPN", extNetworkId.getValue());
183             return;
184         }
185
186         LOG.info("{} router GW MAC flow for router-id {} on switch {}",
187                 addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", routerName, dpnId);
188         boolean submit = false;
189         if (writeTx == null) {
190             submit = true;
191             writeTx = dataBroker.newWriteOnlyTransaction();
192         }
193
194         setupSubnetMacIntoVpnInstance(vpnId.getValue(), null, routerGwMac, dpnId, writeTx,
195                 addOrRemove);
196         if (submit) {
197             writeTx.submit();
198         }
199     }
200
201     @Override
202     public void setupArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps, String macAddress,
203             BigInteger dpnId, Uuid extNetworkId, WriteTransaction writeTx, int addOrRemove) {
204
205         if (dpnId == null || BigInteger.ZERO.equals(dpnId)) {
206             LOG.warn("Failed to install arp responder flows for router {}. DPN id is missing.", id);
207             return;
208         }
209
210         String extInterfaceName = elanService.getExternalElanInterface(extNetworkId.getValue(), dpnId);
211         if (extInterfaceName == null) {
212             LOG.warn("Failed to install responder flows for {}. No external interface found for DPN id {}", id, dpnId);
213             return;
214         }
215
216         Interface extInterfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, extInterfaceName);
217         if (extInterfaceState == null) {
218             LOG.debug("No interface state found for interface {}. Delaying responder flows for {}", extInterfaceName,
219                     id);
220             return;
221         }
222
223         Integer lportTag = extInterfaceState.getIfIndex();
224         if (lportTag == null) {
225             LOG.debug("No Lport tag found for interface {}. Delaying flows for router-id {}", extInterfaceName, id);
226             return;
227         }
228
229         long vpnId = (addOrRemove == NwConstants.ADD_FLOW) ? getVpnIdFromExtNetworkId(extNetworkId)
230                 : VpnConstants.INVALID_ID;
231         setupArpResponderFlowsToExternalNetworkIps(id, fixedIps, macAddress, dpnId, vpnId, extInterfaceName, lportTag,
232                 writeTx, addOrRemove);
233     }
234
235
236     @Override
237     public void setupArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps, String macAddress,
238             BigInteger dpnId, long vpnId, String extInterfaceName, int lportTag, WriteTransaction writeTx,
239             int addOrRemove) {
240         if (fixedIps == null || fixedIps.isEmpty()) {
241             LOG.debug("No external IPs defined for {}", id);
242             return;
243         }
244
245         LOG.info("{} ARP responder flows for {} fixed-ips {} on switch {}",
246                 addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", id, fixedIps, dpnId);
247
248         boolean submit = false;
249         if (writeTx == null) {
250             submit = true;
251             writeTx = dataBroker.newWriteOnlyTransaction();
252         }
253
254         for (String fixedIp : fixedIps) {
255             if (addOrRemove == NwConstants.ADD_FLOW) {
256                 installArpResponderFlowsToExternalNetworkIp(macAddress, dpnId, extInterfaceName, lportTag, vpnId,
257                         fixedIp, writeTx);
258             } else {
259                 removeArpResponderFlowsToExternalNetworkIp(dpnId, lportTag, fixedIp, writeTx);
260             }
261         }
262
263         if (submit) {
264             writeTx.submit();
265         }
266     }
267
268     @Override
269     public List<MatchInfoBase> getEgressMatchesForVpn(String vpnName) {
270         long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
271         if (vpnId == VpnConstants.INVALID_ID) {
272             LOG.warn("No VPN id found for {}", vpnName);
273             return Collections.emptyList();
274         }
275
276         return Collections
277                 .singletonList(new NxMatchRegister(VpnConstants.VPN_REG_ID, vpnId, MetaDataUtil.getVpnIdMaskForReg()));
278     }
279
280     private void installArpResponderFlowsToExternalNetworkIp(String macAddress, BigInteger dpnId,
281             String extInterfaceName, Integer lportTag, long vpnId, String fixedIp, WriteTransaction writeTx) {
282         String flowId = ArpResponderUtil.getFlowID(lportTag, fixedIp);
283         List<Instruction> instructions = ArpResponderUtil.getExtInterfaceInstructions(ifaceMgrRpcService,
284                 extInterfaceName, fixedIp, macAddress);
285         ArpResponderUtil.installFlow(mdsalManager, writeTx, dpnId, flowId, flowId,
286                 NwConstants.DEFAULT_ARP_FLOW_PRIORITY, ArpResponderUtil.generateCookie(lportTag, fixedIp),
287                 ArpResponderUtil.getMatchCriteria(lportTag, vpnId, fixedIp), instructions);
288     }
289
290     private void removeArpResponderFlowsToExternalNetworkIp(BigInteger dpnId, Integer lportTag, String fixedIp,
291             WriteTransaction writeTx) {
292         String flowId = ArpResponderUtil.getFlowID(lportTag, fixedIp);
293         ArpResponderUtil.removeFlow(mdsalManager, writeTx, dpnId, flowId);
294     }
295
296     private long getVpnIdFromExtNetworkId(Uuid extNetworkId) {
297         Uuid vpnInstanceId = VpnUtil.getExternalNetworkVpnId(dataBroker, extNetworkId);
298         if (vpnInstanceId == null) {
299             LOG.debug("Network {} is not associated with VPN", extNetworkId.getValue());
300             return VpnConstants.INVALID_ID;
301         }
302
303         return VpnUtil.getVpnId(dataBroker, vpnInstanceId.getValue());
304     }
305
306     @Override
307     public void onSubnetAddedToVpn(Subnetmap subnetmap, boolean isBgpVpn, Long elanTag) {
308         vpnSubnetRouteHandler.onSubnetAddedToVpn(subnetmap, isBgpVpn, elanTag);
309     }
310
311     @Override
312     public void onSubnetDeletedFromVpn(Subnetmap subnetmap, boolean isBgpVpn) {
313         vpnSubnetRouteHandler.onSubnetDeletedFromVpn(subnetmap, isBgpVpn);
314     }
315
316     public VpnInstance getVpnInstance(DataBroker broker, String vpnInstanceName) {
317         return VpnUtil.getVpnInstance(broker, vpnInstanceName);
318     }
319
320     public String getVpnRd(DataBroker broker, String vpnName) {
321         return VpnUtil.getVpnRd(broker, vpnName);
322     }
323
324     public VpnPortipToPort getNeutronPortFromVpnPortFixedIp(DataBroker broker, String vpnName, String fixedIp) {
325         return VpnUtil.getNeutronPortFromVpnPortFixedIp(broker, vpnName, fixedIp);
326     }
327 }