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