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