Allow MDSALManager exceptions
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / AbstractSnatService.java
1 /*
2  * Copyright (c) 2017 Red Hat, Inc. 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.natservice.internal;
9
10 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Objects;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.Future;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
22 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
23 import org.opendaylight.genius.infra.Datastore.Configuration;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
25 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
26 import org.opendaylight.genius.infra.TransactionAdapter;
27 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
28 import org.opendaylight.genius.infra.TypedWriteTransaction;
29 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
30 import org.opendaylight.genius.mdsalutil.ActionInfo;
31 import org.opendaylight.genius.mdsalutil.BucketInfo;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
33 import org.opendaylight.genius.mdsalutil.GroupEntity;
34 import org.opendaylight.genius.mdsalutil.InstructionInfo;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.mdsalutil.MatchInfo;
37 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
38 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
39 import org.opendaylight.genius.mdsalutil.NWUtil;
40 import org.opendaylight.genius.mdsalutil.NwConstants;
41 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
42 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadMetadata;
43 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
44 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
45 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
46 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
47 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
48 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
49 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
50 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
51 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
52 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
53 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
54 import org.opendaylight.netvirt.natservice.api.SnatServiceListener;
55 import org.opendaylight.netvirt.natservice.ha.NatDataUtil;
56 import org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService;
57 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
58 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfacesBuilder;
59 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
60 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortDataBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
84 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
85 import org.opendaylight.yangtools.yang.common.RpcResult;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89 public abstract class AbstractSnatService implements SnatServiceListener {
90     private static final Logger LOG = LoggerFactory.getLogger(AbstractSnatService.class);
91
92     static final int LOAD_START = mostSignificantBit(MetaDataUtil.METADATA_MASK_SH_FLAG.intValue());
93     static final int LOAD_END = mostSignificantBit(MetaDataUtil.METADATA_MASK_VRFID.intValue() | MetaDataUtil
94             .METADATA_MASK_SH_FLAG.intValue());
95
96     protected final DataBroker dataBroker;
97     protected final ManagedNewTransactionRunner txRunner;
98     protected final IMdsalApiManager mdsalManager;
99     protected final IdManagerService idManager;
100     protected final NAPTSwitchSelector naptSwitchSelector;
101     protected final ItmRpcService itmManager;
102     protected final OdlInterfaceRpcService odlInterfaceRpcService;
103     protected final IInterfaceManager interfaceManager;
104     protected final IVpnFootprintService vpnFootprintService;
105     protected final IFibManager fibManager;
106     protected final NatDataUtil natDataUtil;
107
108     protected AbstractSnatService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
109                                   final ItmRpcService itmManager, final OdlInterfaceRpcService odlInterfaceRpcService,
110                                   final IdManagerService idManager, final NAPTSwitchSelector naptSwitchSelector,
111                                   final IInterfaceManager interfaceManager,
112                                   final IVpnFootprintService vpnFootprintService,
113                                   final IFibManager fibManager, final NatDataUtil natDataUtil) {
114         this.dataBroker = dataBroker;
115         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
116         this.mdsalManager = mdsalManager;
117         this.itmManager = itmManager;
118         this.interfaceManager = interfaceManager;
119         this.idManager = idManager;
120         this.naptSwitchSelector = naptSwitchSelector;
121         this.odlInterfaceRpcService = odlInterfaceRpcService;
122         this.vpnFootprintService = vpnFootprintService;
123         this.fibManager = fibManager;
124         this.natDataUtil = natDataUtil;
125     }
126
127     protected DataBroker getDataBroker() {
128         return dataBroker;
129     }
130
131     public void init() {
132         LOG.info("{} init", getClass().getSimpleName());
133     }
134
135     public void close() {
136         LOG.debug("AbstractSnatService Closed");
137     }
138
139     @Override
140     public boolean addSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
141         BigInteger primarySwitchId) {
142         LOG.info("handleSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
143         String routerName = routers.getRouterName();
144         List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
145         /*
146          * Primary switch handled separately since the pseudo port created may
147          * not be present in the switch list on delete.
148          */
149         addSnat(confTx, routers, primarySwitchId, primarySwitchId);
150         for (BigInteger dpnId : switches) {
151             if (!Objects.equals(primarySwitchId, dpnId)) {
152                 addSnat(confTx, routers, primarySwitchId, dpnId);
153             }
154         }
155         return true;
156     }
157
158     @Override
159     public boolean removeSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
160         BigInteger primarySwitchId) {
161         LOG.info("handleSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
162         String routerName = routers.getRouterName();
163         List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
164         /*
165          * Primary switch handled separately since the pseudo port created may
166          * not be present in the switch list on delete.
167          */
168         boolean isLastRouterDelete =
169             NatUtil.isLastExternalRouter(routers.getNetworkId().getValue(), routers.getRouterName(), natDataUtil);
170         LOG.info("handleSnatAllSwitch : action is delete for router {} and isLastRouterDelete is {}",
171             routers.getRouterName(), isLastRouterDelete);
172         removeSnat(confTx, routers, primarySwitchId, primarySwitchId);
173         for (BigInteger dpnId : switches) {
174             if (!Objects.equals(primarySwitchId, dpnId)) {
175                 removeSnat(confTx, routers, primarySwitchId, dpnId);
176             }
177         }
178         if (isLastRouterDelete) {
179             removeLearntIpPorts(routers);
180             removeMipAdjacencies(routers);
181         }
182         return true;
183     }
184
185     @Override
186     public boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers, BigInteger primarySwitchId,
187         BigInteger dpnId) {
188
189         // Handle non NAPT switches and NAPT switches separately
190         if (!dpnId.equals(primarySwitchId)) {
191             LOG.info("handleSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
192             addSnatCommonEntriesForNonNaptSwitch(confTx, routers, primarySwitchId, dpnId);
193             addSnatSpecificEntriesForNonNaptSwitch(confTx, routers, dpnId);
194         } else {
195             LOG.info("handleSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
196             addSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
197             addSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
198         }
199         return true;
200     }
201
202     @Override
203     public boolean removeSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
204         BigInteger primarySwitchId, BigInteger dpnId) {
205
206         // Handle non NAPT switches and NAPT switches separately
207         if (!dpnId.equals(primarySwitchId)) {
208             LOG.info("handleSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
209             removeSnatCommonEntriesForNonNaptSwitch(confTx, routers, dpnId);
210             removeSnatSpecificEntriesForNonNaptSwitch(confTx, routers, dpnId);
211         } else {
212             LOG.info("handleSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
213             removeSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
214             removeSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
215
216         }
217         return true;
218     }
219
220     protected void addSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
221         BigInteger dpnId) {
222         String routerName = routers.getRouterName();
223         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
224         addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
225         String externalGwMac = routers.getExtGwMacAddress();
226         for (ExternalIps externalIp : routers.getExternalIps()) {
227             if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
228                 // In this class we handle only IPv4 use-cases.
229                 continue;
230             }
231             //The logic now handle only one external IP per router, others if present will be ignored.
232             long extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker, externalIp.getSubnetId());
233             addInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId, extSubnetId,
234                 routers.getNetworkId().getValue(), externalIp.getSubnetId().getValue(), externalGwMac);
235             addInboundTerminatingServiceTblEntry(confTx, dpnId, routerId, extSubnetId);
236             break;
237         }
238     }
239
240     protected void removeSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
241         Routers routers, BigInteger dpnId) {
242         String routerName = routers.getRouterName();
243         Long routerId = NatUtil.getVpnId(confTx, routerName);
244         removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
245         for (ExternalIps externalIp : routers.getExternalIps()) {
246             if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
247                 // In this class we handle only IPv4 use-cases.
248                 continue;
249             }
250             //The logic now handle only one external IP per router, others if present will be ignored.
251             removeInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId,
252                 externalIp.getSubnetId().getValue());
253             removeInboundTerminatingServiceTblEntry(confTx, dpnId, routerId);
254             break;
255         }
256     }
257
258     protected void addSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
259         Routers routers, BigInteger primarySwitchId, BigInteger dpnId) {
260         String routerName = routers.getRouterName();
261         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
262         addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
263         addSnatMissEntry(confTx, dpnId, routerId, routerName, primarySwitchId);
264     }
265
266     protected void removeSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
267         Routers routers, BigInteger dpnId) {
268         String routerName = routers.getRouterName();
269         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
270         removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
271         removeSnatMissEntry(confTx, dpnId, routerId, routerName);
272     }
273
274     protected abstract void addSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
275         Routers routers, BigInteger dpnId);
276
277     protected abstract void removeSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
278         Routers routers, BigInteger dpnId);
279
280     protected abstract void addSnatSpecificEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
281         Routers routers, BigInteger dpnId);
282
283     protected abstract void removeSnatSpecificEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
284         Routers routers, BigInteger dpnId);
285
286     protected void addInboundFibEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, String externalIp,
287         Long routerId, long extSubnetId, String externalNetId, String subNetId, String routerMac) {
288
289         List<MatchInfo> matches = new ArrayList<>();
290         matches.add(MatchEthernetType.IPV4);
291         if (extSubnetId == NatConstants.INVALID_ID) {
292             LOG.error("ConntrackBasedSnatService : installInboundFibEntry : external subnet id is invalid.");
293             return;
294         }
295         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extSubnetId),
296                 MetaDataUtil.METADATA_MASK_VRFID));
297         matches.add(new MatchIpv4Destination(externalIp, "32"));
298
299         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
300         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
301         listActionInfo.add(new ActionNxResubmit(NwConstants.INBOUND_NAPT_TABLE));
302         instructionInfo.add(new InstructionApplyActions(listActionInfo));
303
304         String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
305         flowRef = flowRef + "inbound" + externalIp;
306         addFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef, NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
307                 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
308         String rd = NatUtil.getVpnRd(dataBroker, subNetId);
309         String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
310         String ipPrefix = externalIp + "/32";
311         NatUtil.addPrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, subNetId),
312                 null, ipPrefix, dpnId, new Uuid(subNetId), Prefixes.PrefixCue.Nat);
313
314         fibManager.addOrUpdateFibEntry(rd, routerMac, ipPrefix,
315                 Collections.singletonList(nextHopIp), VrfEntry.EncapType.Mplsgre, extSubnetId,
316                 0, null, externalNetId, RouteOrigin.STATIC, null);
317     }
318
319     protected void removeInboundFibEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
320         String externalIp, Long routerId, String subNetId) {
321
322         String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
323         flowRef = flowRef + "inbound" + externalIp;
324         removeFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
325         String rd = NatUtil.getVpnRd(dataBroker, subNetId);
326         String ipPrefix = externalIp + "/32";
327         fibManager.removeFibEntry(rd, ipPrefix, TransactionAdapter.toWriteTransaction(confTx));
328         NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, subNetId), ipPrefix);
329     }
330
331     protected void addSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
332         Long routerId, String routerName, BigInteger primarySwitchId) {
333         LOG.debug("installSnatMissEntry : Installing SNAT miss entry in switch {}", dpnId);
334         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
335         String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
336         List<BucketInfo> listBucketInfo = new ArrayList<>();
337         if (ifNamePrimary != null) {
338             LOG.debug("installSnatMissEntry : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
339             listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
340                 interfaceManager, ifNamePrimary, routerId, true);
341         }
342         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
343         listBucketInfo.add(0, bucketPrimary);
344         LOG.debug("installSnatMissEntry : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId,
345             listBucketInfo.get(0));
346         // Install the select group
347         long groupId = createGroupId(getGroupIdKey(routerName));
348
349         GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll,
350             listBucketInfo);
351         LOG.debug("installing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId);
352         mdsalManager.addGroup(confTx, groupEntity);
353
354         // Install miss entry pointing to group
355         LOG.debug("installSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
356             dpnId, routerName, groupId);
357         List<MatchInfo> matches = new ArrayList<>();
358         matches.add(new MatchEthernetType(0x0800L));
359         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
360
361
362         List<ActionInfo> actionsInfo = new ArrayList<>();
363         actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(routerId)));
364         LOG.debug("installSnatMissEntry : Setting the tunnel to the list of action infos {}", actionsInfo);
365         actionsInfo.add(new ActionGroup(groupId));
366         List<InstructionInfo> instructions = new ArrayList<>();
367         instructions.add(new InstructionApplyActions(actionsInfo));
368         String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
369         addFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef,  NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
370             NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
371     }
372
373     // TODO skitt Fix the exception handling here
374     @SuppressWarnings("checkstyle:IllegalCatch")
375     @SuppressFBWarnings("REC_CATCH_EXCEPTION")
376     protected void removeSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
377         Long routerId, String routerName) {
378         LOG.debug("installSnatMissEntry : Removing SNAT miss entry from switch {}", dpnId);
379         // Install the select group
380         long groupId = createGroupId(getGroupIdKey(routerName));
381
382         LOG.debug("removing the PSNAT to NAPTSwitch on DPN {} with GroupId: {}", dpnId, groupId);
383         try {
384             mdsalManager.removeGroup(confTx, dpnId, groupId);
385         } catch (Exception e) {
386             LOG.error("Error removing flow", e);
387             throw new RuntimeException("Error removing flow", e);
388         }
389
390         // Install miss entry pointing to group
391         LOG.debug("installSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
392             dpnId, routerName, groupId);
393
394         String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
395         removeFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef);
396     }
397
398     protected void addInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
399         BigInteger dpnId, Long routerId, long extSubnetId) {
400
401         //Install the tunnel table entry in NAPT switch for inbound traffic to SNAP IP from a non a NAPT switch.
402         LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
403                 + "for switch {}, routerId {}", dpnId, routerId);
404         List<MatchInfo> matches = new ArrayList<>();
405         matches.add(MatchEthernetType.IPV4);
406         List<ActionInfo> actionsInfos = new ArrayList<>();
407         if (extSubnetId == NatConstants.INVALID_ID) {
408             LOG.error("installInboundTerminatingServiceTblEntry : external subnet id is invalid.");
409             return;
410         }
411         matches.add(new MatchTunnelId(BigInteger.valueOf(extSubnetId)));
412         ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
413                 .getVpnIdMetadata(extSubnetId), LOAD_START, LOAD_END);
414         actionsInfos.add(actionLoadMeta);
415         actionsInfos.add(new ActionNxResubmit(NwConstants.INBOUND_NAPT_TABLE));
416         List<InstructionInfo> instructions = new ArrayList<>();
417         instructions.add(new InstructionApplyActions(actionsInfos));
418         String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue()) + "INBOUND";
419         addFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
420                  NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
421     }
422
423     protected void removeInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
424         BigInteger dpnId, Long routerId) {
425
426         //Install the tunnel table entry in NAPT switch for inbound traffic to SNAP IP from a non a NAPT switch.
427         LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
428             + "for switch {}, routerId {}", dpnId, routerId);
429         String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue()) + "INBOUND";
430         removeFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
431     }
432
433     protected void addDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
434         Long extNetId) {
435
436         List<MatchInfo> matches = new ArrayList<>();
437         matches.add(MatchEthernetType.IPV4);
438         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extNetId),
439             MetaDataUtil.METADATA_MASK_VRFID));
440
441         List<InstructionInfo> instructions = new ArrayList<>();
442         instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
443
444         String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
445         addFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef, NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef,
446             NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
447     }
448
449     protected void removeDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
450         Long extNetId) {
451
452         String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
453         removeFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
454     }
455
456     protected String getFlowRef(BigInteger dpnId, short tableId, long routerID) {
457         return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants
458                 .FLOWID_SEPARATOR).append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
459     }
460
461     protected void syncFlow(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpId, short tableId,
462         String flowId, int priority, String flowName, BigInteger cookie, List<? extends MatchInfoBase> matches,
463         List<InstructionInfo> instructions, int addOrRemove) {
464         if (addOrRemove == NwConstants.DEL_FLOW) {
465             removeFlow(confTx, dpId, tableId, flowId);
466         } else {
467             addFlow(confTx, dpId, tableId, flowId, priority, flowName, cookie, matches, instructions);
468         }
469     }
470
471     protected void addFlow(TypedWriteTransaction<Configuration> confTx, BigInteger dpId, short tableId,
472         String flowId, int priority, String flowName, BigInteger cookie, List<? extends MatchInfoBase> matches,
473         List<InstructionInfo> instructions) {
474         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
475                 NatConstants.DEFAULT_IDLE_TIMEOUT, NatConstants.DEFAULT_IDLE_TIMEOUT, cookie, matches,
476                 instructions);
477         LOG.trace("syncFlow : Installing DpnId {}, flowId {}", dpId, flowId);
478         mdsalManager.addFlow(confTx, flowEntity);
479     }
480
481     // TODO skitt Fix the exception handling here
482     @SuppressWarnings("checkstyle:IllegalCatch")
483     @SuppressFBWarnings("REC_CATCH_EXCEPTION")
484     protected void removeFlow(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpId, short tableId,
485         String flowId) {
486         LOG.trace("syncFlow : Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
487         try {
488             mdsalManager.removeFlow(confTx, dpId, flowId, tableId);
489         } catch (Exception e) {
490             LOG.error("Error removing flow", e);
491             throw new RuntimeException("Error removing flow", e);
492         }
493     }
494
495     protected long createGroupId(String groupIdKey) {
496         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
497             .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
498             .build();
499         try {
500             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
501             RpcResult<AllocateIdOutput> rpcResult = result.get();
502             return rpcResult.getResult().getIdValue();
503         } catch (NullPointerException | InterruptedException | ExecutionException e) {
504             LOG.error("createGroupId: Exception while creating group with key : {}",groupIdKey, e);
505         }
506         return 0;
507     }
508
509     protected String getGroupIdKey(String routerName) {
510         return "snatmiss." + routerName;
511     }
512
513     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
514         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
515         RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
516         try {
517             Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager
518                     .getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId)
519                             .setDestinationDpid(dstDpId).setTunnelType(tunType).build());
520             rpcResult = result.get();
521             if (!rpcResult.isSuccessful()) {
522                 tunType = TunnelTypeGre.class ;
523                 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
524                         .setSourceDpid(srcDpId)
525                         .setDestinationDpid(dstDpId)
526                         .setTunnelType(tunType)
527                         .build());
528                 rpcResult = result.get();
529                 if (!rpcResult.isSuccessful()) {
530                     LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
531                             rpcResult.getErrors());
532                 } else {
533                     return rpcResult.getResult().getInterfaceName();
534                 }
535                 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
536                         rpcResult.getErrors());
537             } else {
538                 return rpcResult.getResult().getInterfaceName();
539             }
540         } catch (InterruptedException | ExecutionException | NullPointerException e) {
541             LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
542                     + "between {} and {}", srcDpId, dstDpId);
543         }
544         return null;
545     }
546
547     protected void removeMipAdjacencies(Routers routers) {
548         LOG.info("removeMipAdjacencies for router {}", routers.getRouterName());
549         String externalSubNetId  = null;
550         for (ExternalIps externalIp : routers.getExternalIps()) {
551             if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
552                 // In this class we handle only IPv4 use-cases.
553                 continue;
554             }
555             externalSubNetId = externalIp.getSubnetId().getValue();
556             break;
557         }
558         if (externalSubNetId == null) {
559             LOG.info("removeMipAdjacencies no external Ipv4 address present on router {}",
560                     routers.getRouterName());
561             return;
562         }
563         InstanceIdentifier<VpnInterfaces> vpnInterfacesId =
564                 InstanceIdentifier.builder(VpnInterfaces.class).build();
565         try {
566             VpnInterfaces vpnInterfaces = SingleTransactionDataBroker.syncRead(dataBroker,
567                     LogicalDatastoreType.CONFIGURATION, vpnInterfacesId);
568             List<VpnInterface> updatedVpnInterface = new ArrayList<>();
569             for (VpnInterface vpnInterface : vpnInterfaces.getVpnInterface()) {
570                 List<Adjacency> updatedAdjacencies = new ArrayList<>();
571                 Adjacencies adjacencies = vpnInterface.augmentation(Adjacencies.class);
572                 if (null != adjacencies) {
573                     for (Adjacency adjacency : adjacencies.getAdjacency()) {
574                         if (!adjacency.getSubnetId().getValue().equals(externalSubNetId)) {
575                             updatedAdjacencies.add(adjacency);
576                         }
577                     }
578                 }
579                 AdjacenciesBuilder adjacenciesBuilder = new AdjacenciesBuilder();
580                 adjacenciesBuilder.setAdjacency(updatedAdjacencies);
581                 VpnInterfaceBuilder vpnInterfaceBuilder = new VpnInterfaceBuilder(vpnInterface);
582                 vpnInterfaceBuilder.addAugmentation(Adjacencies.class, adjacenciesBuilder.build());
583                 updatedVpnInterface.add(vpnInterfaceBuilder.build());
584             }
585             VpnInterfacesBuilder vpnInterfacesBuilder = new VpnInterfacesBuilder();
586             vpnInterfacesBuilder.setVpnInterface(updatedVpnInterface);
587
588             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
589                     vpnInterfacesId, vpnInterfacesBuilder.build());
590         } catch (ReadFailedException e) {
591             LOG.warn("Failed to read removeMipAdjacencies with error {}", e.getMessage());
592         } catch (TransactionCommitFailedException e) {
593             LOG.warn("Failed to remove removeMipAdjacencies with error {}", e.getMessage());
594         }
595     }
596
597     private void removeLearntIpPorts(Routers routers) {
598         LOG.info("removeLearntIpPorts for router {} and network {}", routers.getRouterName(), routers.getNetworkId());
599         String networkId = routers.getNetworkId().getValue();
600         LearntVpnVipToPortData learntVpnVipToPortData = NatUtil.getLearntVpnVipToPortData(dataBroker);
601         if (learntVpnVipToPortData == null) {
602             LOG.info("removeLearntIpPorts, no learned ports present");
603             return;
604         }
605         LearntVpnVipToPortDataBuilder learntVpnVipToPortDataBuilder = new LearntVpnVipToPortDataBuilder();
606         List<LearntVpnVipToPort> learntVpnVipToPortList = new ArrayList<>();
607         for (LearntVpnVipToPort learntVpnVipToPort : learntVpnVipToPortData.getLearntVpnVipToPort()) {
608             if (!learntVpnVipToPort.getVpnName().equals(networkId)) {
609                 LOG.info("The learned port belongs to Vpn {} hence not removing", learntVpnVipToPort.getVpnName());
610                 learntVpnVipToPortList.add(learntVpnVipToPort);
611             } else {
612                 String externalSubNetId = null;
613                 for (ExternalIps externalIp : routers.getExternalIps()) {
614                     if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
615                         // In this class we handle only IPv4 use-cases.
616                         continue;
617                     }
618                     externalSubNetId = externalIp.getSubnetId().getValue();
619                     break;
620                 }
621                 if (externalSubNetId == null) {
622                     LOG.info("removeLearntIpPorts no external Ipv4 address present on router {}",
623                             routers.getRouterName());
624                     return;
625                 }
626                 String prefix = learntVpnVipToPort.getPortFixedip() + "/32";
627                 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker,
628                         externalSubNetId), prefix);
629             }
630         }
631
632         try {
633             learntVpnVipToPortDataBuilder.setLearntVpnVipToPort(learntVpnVipToPortList);
634             InstanceIdentifier<LearntVpnVipToPortData> learntVpnVipToPortDataId = NatUtil
635                     .getLearntVpnVipToPortDataId();
636             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
637                     learntVpnVipToPortDataId, learntVpnVipToPortDataBuilder.build());
638
639         } catch (TransactionCommitFailedException e) {
640             LOG.warn("Failed to remove removeLearntIpPorts with error {}", e.getMessage());
641         }
642     }
643
644     static int mostSignificantBit(int value) {
645         return 31 - Integer.numberOfLeadingZeros(value);
646     }
647 }