Ensure External Connectivity for NAPT Switch
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / VxlanGreConntrackBasedSnatService.java
1 /*
2  * Copyright © 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.concurrent.ExecutionException;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
17 import org.opendaylight.genius.infra.Datastore.Configuration;
18 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
19 import org.opendaylight.genius.infra.TypedWriteTransaction;
20 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
21 import org.opendaylight.genius.mdsalutil.ActionInfo;
22 import org.opendaylight.genius.mdsalutil.BucketInfo;
23 import org.opendaylight.genius.mdsalutil.GroupEntity;
24 import org.opendaylight.genius.mdsalutil.InstructionInfo;
25 import org.opendaylight.genius.mdsalutil.MDSALUtil;
26 import org.opendaylight.genius.mdsalutil.MatchInfo;
27 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
28 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
29 import org.opendaylight.genius.mdsalutil.NwConstants;
30 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
31 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack;
32 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack.NxCtAction;
33 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
34 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
35 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldMeta;
36 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
37 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
38 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
39 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
40 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
41 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
42 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
43 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchCtState;
44 import org.opendaylight.netvirt.elanmanager.api.IElanService;
45 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
46 import org.opendaylight.netvirt.natservice.ha.NatDataUtil;
47 import org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.types.rev160517.IpPrefixOrAddressBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.NxActionNatFlags;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.NxActionNatRangePresent;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 public class VxlanGreConntrackBasedSnatService extends ConntrackBasedSnatService {
63
64     private static final Logger LOG = LoggerFactory.getLogger(VxlanGreConntrackBasedSnatService.class);
65     private final ExternalRoutersListener externalRouterListener;
66     private final IElanService elanManager;
67
68     public VxlanGreConntrackBasedSnatService(DataBroker dataBroker, IMdsalApiManager mdsalManager,
69                                              ItmRpcService itmManager, OdlInterfaceRpcService odlInterfaceRpcService,
70                                              IdManagerService idManager, NAPTSwitchSelector naptSwitchSelector,
71                                              ExternalRoutersListener externalRouterListener, IElanService elanManager,
72                                              IInterfaceManager interfaceManager,
73                                              IVpnFootprintService vpnFootprintService,
74                                              IFibManager fibManager, NatDataUtil natDataUtil,
75                                              DataTreeEventCallbackRegistrar eventCallbacks) {
76         super(dataBroker, mdsalManager, itmManager, idManager, naptSwitchSelector, odlInterfaceRpcService,
77                 interfaceManager, vpnFootprintService, fibManager, natDataUtil, eventCallbacks);
78         this.externalRouterListener = externalRouterListener;
79         this.elanManager = elanManager;
80     }
81
82     @Override
83     public boolean addSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
84         BigInteger primarySwitchId) {
85         ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(confTx, routers.getNetworkId());
86         LOG.debug("VxlanGreConntrackBasedSnatService: handleSnatAllSwitch ProviderTypes {}", extNwProviderType);
87         if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
88             LOG.debug("handleSnatAllSwitch : Skip FLAT/VLAN provider networks.");
89             return true;
90         }
91         return super.addSnatAllSwitch(confTx, routers, primarySwitchId);
92     }
93
94     @Override
95     public boolean removeSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
96             BigInteger primarySwitchId) throws ExecutionException, InterruptedException {
97         ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(confTx, routers.getNetworkId());
98         LOG.debug("VxlanGreConntrackBasedSnatService: handleSnatAllSwitch ProviderTypes {}", extNwProviderType);
99         if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
100             LOG.debug("handleSnatAllSwitch : Skip FLAT/VLAN provider networks.");
101             return true;
102         }
103         return super.removeSnatAllSwitch(confTx, routers, primarySwitchId);
104     }
105
106     public boolean addCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
107             BigInteger primarySwitchId) {
108         ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, routers.getNetworkId());
109         LOG.debug("VxlanGreConntrackBasedSnatService: handleCentralizedRouterAllSwitch ProviderTypes {}",
110                 extNwProviderType);
111         if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
112             LOG.debug("handleCentralizedRouterAllSwitch : Skip FLAT/VLAN provider networks.");
113             return true;
114         }
115         return super.addCentralizedRouterAllSwitch(confTx, routers, primarySwitchId);
116     }
117
118     public boolean removeCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
119             BigInteger primarySwitchId)  throws ExecutionException, InterruptedException {
120         ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, routers.getNetworkId());
121         LOG.debug("VxlanGreConntrackBasedSnatService: handleCentralizedRouterAllSwitch ProviderTypes {}",
122                 extNwProviderType);
123         if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
124             LOG.debug("handleCentralizedRouterAllSwitch : Skip FLAT/VLAN provider networks.");
125             return true;
126         }
127         return super.removeCentralizedRouterAllSwitch(confTx, routers, primarySwitchId);
128     }
129
130     public boolean addCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
131             BigInteger primarySwitchId, BigInteger dpnId) {
132         ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, routers.getNetworkId());
133         LOG.debug("VxlanGreConntrackBasedSnatService: handleCentralizedRouter ProviderTypes {}", extNwProviderType);
134         if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
135             LOG.debug("handleCentralizedRouter : Skip FLAT/VLAN provider networks.");
136             return true;
137         }
138         return super.addCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
139     }
140
141     public boolean removeCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
142             BigInteger primarySwitchId, BigInteger dpnId)  throws ExecutionException, InterruptedException {
143         ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, routers.getNetworkId());
144         LOG.debug("VxlanGreConntrackBasedSnatService: handleCentralizedRouter ProviderTypes {}", extNwProviderType);
145         if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
146             LOG.debug("handleCentralizedRouter : Skip FLAT/VLAN provider networks.");
147             return true;
148         }
149         return super.removeCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
150     }
151
152     @Override
153     public boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
154         BigInteger primarySwitchId, BigInteger dpnId) {
155         ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(confTx, routers.getNetworkId());
156         LOG.debug("VxlanGreConntrackBasedSnatService: handleSnat ProviderTypes {}", extNwProviderType);
157         if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
158             LOG.debug("handleSnat : Skip FLAT/VLAN provider networks.");
159             return true;
160         }
161         return super.addSnat(confTx, routers, primarySwitchId, dpnId);
162     }
163
164     @Override
165     public boolean removeSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
166             BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException {
167         ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(confTx, routers.getNetworkId());
168         LOG.debug("VxlanGreConntrackBasedSnatService: handleSnat ProviderTypes {}", extNwProviderType);
169         if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
170             LOG.debug("handleSnat : Skip FLAT/VLAN provider networks.");
171             return true;
172         }
173         return super.removeSnat(confTx, routers, primarySwitchId, dpnId);
174     }
175
176     @Override
177     protected void addSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
178         BigInteger dpnId) {
179
180         LOG.info("installSnatSpecificEntriesForNaptSwitch for router {}",
181             routers.getRouterName());
182         String routerName = routers.getRouterName();
183         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
184         int elanId = NatUtil.getElanInstanceByName(routers.getNetworkId().getValue(), dataBroker)
185             .getElanTag().intValue();
186         /* Install Outbound NAT entries */
187
188         addSnatMissEntryForPrimrySwch(confTx, dpnId, routerId, elanId);
189         addTerminatingServiceTblEntryForVxlanGre(confTx, dpnId, routerName, routerId, elanId);
190         //Long extNetVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
191         Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, routers.getNetworkId());
192         if (vpnUuid == null) {
193             LOG.error("installSnatSpecificEntriesForNaptSwitch: Unable to retrieve external vpn_id for "
194                 + "external network {} with routerId {}", routers.getNetworkId(), routerId);
195             return;
196         }
197         Long extNetVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
198         LOG.info("installSnatSpecificEntriesForNaptSwitch: external network vpn_id {} for router {}",
199             extNetVpnId, routers.getRouterName());
200         List<ExternalIps> externalIps = routers.getExternalIps();
201         addOutboundTblTrackEntryForVxlanGre(confTx, dpnId, routerId, extNetVpnId);
202         addOutboundTblEntryForVxlanGre(confTx, dpnId, routerId, extNetVpnId, externalIps, elanId);
203         addNaptPfibFlowForVxlanGre(confTx, routers, dpnId, extNetVpnId);
204         addNaptPfibEntry(confTx, dpnId, routerId);
205
206         //Install Inbound NAT entries
207         addInboundEntryForVxlanGre(confTx, dpnId, routerId, extNetVpnId, externalIps, elanId);
208         if (externalIps.isEmpty()) {
209             LOG.error("installSnatSpecificEntriesForNaptSwitch: No externalIP present for router {}",
210                 routerName);
211             return;
212         }
213         //The logic now handle only one external IP per router, others if present will be ignored.
214         String externalIp = NatUtil.validateAndAddNetworkMask(externalIps.get(0).getIpAddress());
215         externalRouterListener.handleSnatReverseTraffic(confTx, dpnId, routers, routerId, routerName, externalIp);
216     }
217
218     @Override
219     protected void removeSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
220             Routers routers, BigInteger dpnId) throws ExecutionException, InterruptedException {
221
222         LOG.info("installSnatSpecificEntriesForNaptSwitch for router {}",
223             routers.getRouterName());
224         String routerName = routers.getRouterName();
225         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
226
227         /* Remove Outbound NAT entries */
228         removeSnatMissEntryForPrimrySwch(confTx, dpnId, routerId);
229         removeTerminatingServiceTblEntryForVxlanGre(confTx, dpnId, routerId);
230         //Long extNetVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
231         Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, routers.getNetworkId());
232         if (vpnUuid == null) {
233             LOG.error("installSnatSpecificEntriesForNaptSwitch: Unable to retrieve external vpn_id for "
234                 + "external network {} with routerId {}", routers.getNetworkId(), routerId);
235             return;
236         }
237         Long extNetVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
238         LOG.info("installSnatSpecificEntriesForNaptSwitch: external network vpn_id {} for router {}",
239             extNetVpnId, routers.getRouterName());
240         List<ExternalIps> externalIps = routers.getExternalIps();
241         removeOutboundTblTrackEntryForVxlanGre(confTx, dpnId, routerId);
242         removeOutboundTblEntryForVxlanGre(confTx, dpnId, routerId, externalIps);
243         removeNaptPfibFlowForVxlanGre(confTx, routers, dpnId, extNetVpnId);
244         removeNaptPfibEntry(confTx, dpnId, routerId);
245
246         //Install Inbound NAT entries
247         removeInboundEntryForVxlanGre(confTx, dpnId, routerId, externalIps);
248         if (externalIps.isEmpty()) {
249             LOG.error("installSnatSpecificEntriesForNaptSwitch: No externalIP present for router {}",
250                 routerName);
251             return;
252         }
253         //The logic now handle only one external IP per router, others if present will be ignored.
254         String externalIp = NatUtil.validateAndAddNetworkMask(externalIps.get(0).getIpAddress());
255         externalRouterListener.clearFibTsAndReverseTraffic(dpnId, routerId, routers.getNetworkId(),
256             Collections.singletonList(externalIp), null, routers.getExtGwMacAddress(), confTx);
257     }
258
259     protected void addOutboundTblTrackEntryForVxlanGre(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId,
260         Long routerId, Long extNetVpnId) {
261         LOG.info("createOutboundTblTrackEntryForVxlanGre: Install Outbound tracking table flow on dpId {} for "
262                 + "routerId {}", dpnId, routerId);
263         List<MatchInfoBase> matches = new ArrayList<>();
264         matches.add(MatchEthernetType.IPV4);
265         matches.add(new NxMatchCtState(SNAT_CT_STATE, SNAT_CT_STATE_MASK));
266         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
267
268         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
269         ActionSetFieldMeta actionSetFieldMeta = new ActionSetFieldMeta(MetaDataUtil.getVpnIdMetadata(extNetVpnId));
270         listActionInfo.add(actionSetFieldMeta);
271         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
272         listActionInfo.add(new ActionNxResubmit(NwConstants.NAPT_PFIB_TABLE));
273         instructionInfo.add(new InstructionApplyActions(listActionInfo));
274
275         String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId) + "trkest";
276         addFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef,
277                 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
278
279     }
280
281     protected void removeOutboundTblTrackEntryForVxlanGre(TypedReadWriteTransaction<Configuration> confTx,
282             BigInteger dpnId, Long routerId) throws ExecutionException, InterruptedException {
283         LOG.info("createOutboundTblTrackEntryForVxlanGre: Install Outbound tracking table flow on dpId {} for "
284             + "routerId {}", dpnId, routerId);
285
286         String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId) + "trkest";
287         removeFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
288
289     }
290
291     protected void addOutboundTblEntryForVxlanGre(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId,
292         long routerId, Long extNetVpnId, List<ExternalIps> externalIps, int elanId) {
293         LOG.info("createOutboundTblEntryForVxlanGre: Install Outbound table flow on dpId {} for routerId {}", dpnId,
294                 routerId);
295         List<MatchInfoBase> matches = new ArrayList<>();
296         matches.add(MatchEthernetType.IPV4);
297         matches.add(new NxMatchCtState(TRACKED_NEW_CT_STATE, TRACKED_NEW_CT_MASK));
298         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
299         if (externalIps.isEmpty()) {
300             LOG.error("createOutboundTblEntryForVxlanGre: No externalIP present for routerId {}",
301                     routerId);
302             return;
303         }
304         //The logic now handle only one external IP per router, others if present will be ignored.
305         String externalIp = externalIps.get(0).getIpAddress();
306         List<ActionInfo> actionsInfos = new ArrayList<>();
307         ActionSetFieldMeta actionSetFieldMeta = new ActionSetFieldMeta(MetaDataUtil
308                 .getVpnIdMetadata(extNetVpnId));
309         actionsInfos.add(actionSetFieldMeta);
310         List<ActionNxConntrack.NxCtAction> ctActionsListCommit = new ArrayList<>();
311         int rangePresent = NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue();
312         int flags = NxActionNatFlags.NXNATFSRC.getIntValue();
313         ActionNxConntrack.NxCtAction nxCtActionCommit = new ActionNxConntrack.NxNat(0, flags, rangePresent,
314             IpPrefixOrAddressBuilder.getDefaultInstance(externalIp).getIpAddress(), null,0, 0);
315         ctActionsListCommit.add(nxCtActionCommit);
316         int ctCommitFlag = 1;
317         ActionNxConntrack actionNxConntrackSubmit = new ActionNxConntrack(ctCommitFlag, 0, elanId,
318                 NwConstants.NAPT_PFIB_TABLE, ctActionsListCommit);
319         actionsInfos.add(actionNxConntrackSubmit);
320         List<InstructionInfo> instructions = new ArrayList<>();
321         instructions.add(new InstructionApplyActions(actionsInfos));
322         String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
323         addFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,  NatConstants.SNAT_NEW_FLOW_PRIORITY,
324                 flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
325     }
326
327     protected void removeOutboundTblEntryForVxlanGre(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
328             long routerId, List<ExternalIps> externalIps) throws ExecutionException, InterruptedException {
329         LOG.info("createOutboundTblEntryForVxlanGre: Install Outbound table flow on dpId {} for routerId {}", dpnId,
330             routerId);
331         if (externalIps.isEmpty()) {
332             LOG.error("createOutboundTblEntryForVxlanGre: No externalIP present for routerId {}",
333                 routerId);
334             return;
335         }
336         //The logic now handle only one external IP per router, others if present will be ignored.
337         String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
338         removeFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
339     }
340
341     protected void addNaptPfibFlowForVxlanGre(TypedWriteTransaction<Configuration> confTx, Routers routers,
342         BigInteger dpnId, Long extNetVpnId) {
343         LOG.info("installNaptPfibFlowForVxlanGre: Install Napt preFibFlow on dpId {} with matching extNetVpnId {} "
344                 + "for router {}", dpnId, extNetVpnId, routers.getRouterName());
345         List<MatchInfoBase> matches = new ArrayList<>();
346         matches.add(MatchEthernetType.IPV4);
347         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extNetVpnId),
348                 MetaDataUtil.METADATA_MASK_VRFID));
349         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
350         ArrayList<InstructionInfo> instructions = new ArrayList<>();
351         listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
352         listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
353         instructions.add(new InstructionApplyActions(listActionInfo));
354         String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, extNetVpnId);
355         addFlow(confTx, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY,
356                 flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
357     }
358
359     protected void removeNaptPfibFlowForVxlanGre(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
360             BigInteger dpnId, Long extNetVpnId) throws ExecutionException, InterruptedException {
361         LOG.info("installNaptPfibFlowForVxlanGre: Install Napt preFibFlow on dpId {} with matching extNetVpnId {} "
362             + "for router {}", dpnId, extNetVpnId, routers.getRouterName());
363         String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, extNetVpnId);
364         removeFlow(confTx, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
365     }
366
367     protected void addInboundEntryForVxlanGre(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId,
368         long routerId, Long extNeVpnId, List<ExternalIps> externalIps, int elanId) {
369         LOG.info("installInboundEntryForVxlanGre:  Install Inbound table entry on dpId {} for routerId {}",
370                 dpnId, routerId);
371         List<MatchInfoBase> matches = new ArrayList<>();
372         matches.add(MatchEthernetType.IPV4);
373         if (externalIps.isEmpty()) {
374             LOG.error("installInboundEntryForVxlanGre : createInboundTblEntry no externalIP present for routerId {}",
375                     routerId);
376             return;
377         }
378         String externalIp = externalIps.get(0).getIpAddress();
379         matches.add(new MatchIpv4Destination(externalIp,"32"));
380         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extNeVpnId), MetaDataUtil.METADATA_MASK_VRFID));
381         List<ActionInfo> actionsInfos = new ArrayList<>();
382         List<ActionNxConntrack.NxCtAction> ctActionsList = new ArrayList<>();
383         ActionNxConntrack.NxCtAction nxCtAction = new ActionNxConntrack.NxNat(0, 0, 0,null, null,0, 0);
384         ActionSetFieldMeta actionSetFieldMeta = new ActionSetFieldMeta(MetaDataUtil
385                 .getVpnIdMetadata(routerId));
386         actionsInfos.add(actionSetFieldMeta);
387         ctActionsList.add(nxCtAction);
388         ActionNxConntrack actionNxConntrack = new ActionNxConntrack(0, 0, elanId, NwConstants
389                 .NAPT_PFIB_TABLE,ctActionsList);
390
391         actionsInfos.add(actionNxConntrack);
392         List<InstructionInfo> instructions = new ArrayList<>();
393         instructions.add(new InstructionApplyActions(actionsInfos));
394         String flowRef = getFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId);
395         addFlow(confTx, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef,
396                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
397     }
398
399     protected void removeInboundEntryForVxlanGre(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
400             long routerId, List<ExternalIps> externalIps) throws ExecutionException, InterruptedException {
401         LOG.info("removeInboundEntryForVxlanGre: remove Inbound table entry on dpId {} for routerId {}",
402             dpnId, routerId);
403         if (externalIps.isEmpty()) {
404             LOG.error("removeInboundEntryForVxlanGre : createInboundTblEntry no externalIP present for routerId {}",
405                 routerId);
406             return;
407         }
408
409         String flowRef = getFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId);
410         removeFlow(confTx, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef);
411     }
412
413     protected void addTerminatingServiceTblEntryForVxlanGre(TypedWriteTransaction<Configuration> confTx,
414         BigInteger dpnId, String routerName, Long routerId, int elanId) {
415         LOG.info("installTerminatingServiceTblEntryForVxlanGre : creating entry for"
416                 + "Terminating Service Table for switch {}, routerId {}", dpnId, routerId);
417         List<MatchInfo> matches = new ArrayList<>();
418         matches.add(MatchEthernetType.IPV4);
419
420         BigInteger tunnelId = BigInteger.valueOf(routerId);
421         if (elanManager.isOpenStackVniSemanticsEnforced()) {
422             tunnelId = NatOverVxlanUtil.getRouterVni(idManager, routerName, routerId);
423         }
424         matches.add(new MatchTunnelId(tunnelId));
425
426         List<ActionInfo> actionsInfos = new ArrayList<>();
427         List<NxCtAction> ctActionsList = new ArrayList<>();
428         NxCtAction nxCtAction = new ActionNxConntrack.NxNat(0, 0, 0,null, null,0, 0);
429         ctActionsList.add(nxCtAction);
430         ActionNxConntrack actionNxConntrack = new ActionNxConntrack(0, 0, elanId, NwConstants
431                 .OUTBOUND_NAPT_TABLE,ctActionsList);
432         ActionSetFieldMeta actionSetFieldMeta = new ActionSetFieldMeta(MetaDataUtil
433                 .getVpnIdMetadata(routerId.longValue()));
434         actionsInfos.add(actionSetFieldMeta);
435         actionsInfos.add(actionNxConntrack);
436         List<InstructionInfo> instructions = new ArrayList<>();
437         instructions.add(new InstructionApplyActions(actionsInfos));
438         String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
439         addFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY,
440             flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
441
442     }
443
444     protected void removeTerminatingServiceTblEntryForVxlanGre(TypedReadWriteTransaction<Configuration> confTx,
445             BigInteger dpnId, Long routerId) throws ExecutionException, InterruptedException {
446         LOG.info("removeTerminatingServiceTblEntryForVxlanGre : removing entry for"
447             + "Terminating Service Table for switch {}, routerId {}", dpnId, routerId);
448
449         String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
450         removeFlow(confTx, dpnId,  NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
451
452     }
453
454     @Override
455     protected void addSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId, Long routerId,
456         String routerName, BigInteger primarySwitchId) {
457         LOG.debug("installSnatMissEntry : Installing SNAT miss entry in switch {}", dpnId);
458         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
459         String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
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         GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll,
473                 listBucketInfo);
474         LOG.debug("installSnatMissEntry : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
475         mdsalManager.addGroup(confTx, groupEntity);
476         // Install miss entry pointing to group
477         LOG.debug("installSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
478                 dpnId, routerName, groupId);
479         List<MatchInfo> matches = new ArrayList<>();
480         matches.add(new MatchEthernetType(0x0800L));
481         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
482
483         List<ActionInfo> actionsInfo = new ArrayList<>();
484
485         BigInteger tunnelId = BigInteger.valueOf(routerId);
486         if (elanManager.isOpenStackVniSemanticsEnforced()) {
487             tunnelId = NatOverVxlanUtil.getRouterVni(idManager, routerName, routerId);
488         }
489
490         actionsInfo.add(new ActionSetFieldTunnelId(tunnelId));
491         LOG.debug("AbstractSnatService : Setting the tunnel to the list of action infos {}", actionsInfo);
492         actionsInfo.add(new ActionGroup(groupId));
493         List<InstructionInfo> instructions = new ArrayList<>();
494         instructions.add(new InstructionApplyActions(actionsInfo));
495         String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
496         addFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef,  NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
497                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
498     }
499
500     @Override
501     protected void removeSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
502             Long routerId, String routerName) throws ExecutionException, InterruptedException {
503         LOG.debug("installSnatMissEntry : Removing SNAT miss entry in switch {}", dpnId);
504
505         String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
506         removeFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef);
507     }
508
509 }