b177cd920404a9cfc96be668bbac8decc5644f0e
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / Ipv6ForwardingService.java
1 /*
2  * Copyright (c) 2018 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.netvirt.natservice.internal.AbstractSnatService.LOAD_END;
11 import static org.opendaylight.netvirt.natservice.internal.AbstractSnatService.LOAD_START;
12 import static org.opendaylight.netvirt.natservice.internal.NatUtil.getGroupIdKey;
13
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Objects;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.Future;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.genius.infra.Datastore.Configuration;
21 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
22 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
23 import org.opendaylight.genius.mdsalutil.ActionInfo;
24 import org.opendaylight.genius.mdsalutil.BucketInfo;
25 import org.opendaylight.genius.mdsalutil.GroupEntity;
26 import org.opendaylight.genius.mdsalutil.InstructionInfo;
27 import org.opendaylight.genius.mdsalutil.MDSALUtil;
28 import org.opendaylight.genius.mdsalutil.MatchInfo;
29 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
30 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
31 import org.opendaylight.genius.mdsalutil.NWUtil;
32 import org.opendaylight.genius.mdsalutil.NwConstants;
33 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
34 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
35 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadMetadata;
36 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
37 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
38 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
39 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
40 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
41 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
42 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
43 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
44 import org.opendaylight.netvirt.natservice.api.SnatServiceListener;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
54 import org.opendaylight.yangtools.yang.common.RpcResult;
55 import org.opendaylight.yangtools.yang.common.Uint32;
56 import org.opendaylight.yangtools.yang.common.Uint64;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 public class Ipv6ForwardingService implements SnatServiceListener {
61     private static final Logger LOG = LoggerFactory.getLogger(Ipv6ForwardingService.class);
62
63     protected final DataBroker dataBroker;
64     protected final IMdsalApiManager mdsalManager;
65     protected final IdManagerService idManager;
66     protected final NAPTSwitchSelector naptSwitchSelector;
67     protected final ItmRpcService itmManager;
68     protected final OdlInterfaceRpcService odlInterfaceRpcService;
69     protected final IInterfaceManager interfaceManager;
70     protected final Ipv6SubnetFlowProgrammer ipv6SubnetFlowProgrammer;
71
72     public Ipv6ForwardingService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
73                                   final ItmRpcService itmManager,
74                                   final OdlInterfaceRpcService odlInterfaceRpcService,
75                                   final IdManagerService idManager,
76                                   final NAPTSwitchSelector naptSwitchSelector,
77                                   final IInterfaceManager interfaceManager,
78                                   final Ipv6SubnetFlowProgrammer ipv6SubnetFlowProgrammer) {
79         this.dataBroker = dataBroker;
80         this.mdsalManager = mdsalManager;
81         this.itmManager = itmManager;
82         this.odlInterfaceRpcService = odlInterfaceRpcService;
83         this.idManager = idManager;
84         this.naptSwitchSelector = naptSwitchSelector;
85         this.interfaceManager = interfaceManager;
86         this.ipv6SubnetFlowProgrammer = ipv6SubnetFlowProgrammer;
87     }
88
89     @Override
90     public boolean addCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx,
91             Routers routers, Uint64 primarySwitchId) {
92         String routerName = routers.getRouterName();
93         LOG.info("handleSnatAllSwitch : invoked for router {} with NAPTSwitch {} for {} flows",
94                 routerName, primarySwitchId, "installing");
95         List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
96         /*
97          * Primary switch handled separately since the pseudo port created may
98          * not be present in the switch list on delete.
99          */
100         addCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
101         for (Uint64 dpnId : switches) {
102             if (!Objects.equals(primarySwitchId, dpnId)) {
103                 addCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
104             }
105         }
106         return true;
107     }
108
109     @Override
110     public boolean addCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx,
111             Routers routers, Uint64 primarySwitchId, Uint64 dpnId) {
112         Uint32 routerId = NatUtil.getVpnId(dataBroker, routers.getRouterName());
113         Uint64 routerMetadata = MetaDataUtil.getVpnIdMetadata(routerId.longValue());
114
115         if (!dpnId.equals(primarySwitchId)) {
116             LOG.info("handleSnat (non-NAPTSwitch) : {} flows on switch {} for router {}",
117                     "Installing", dpnId, routers.getRouterName());
118             // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction)
119             addIpv6DefaultFibRoute(confTx, dpnId, routerId, routerMetadata);
120
121             // Currently we are only programming flows when ext-net has an IPv6Subnet
122             if (routerHasIpv6ExtSubnet(routers)) {
123                 // Program flows on non-NAPTSwitch to send N/S packets to the NAPTSwitch
124                 addIpv6PsNatMissEntryNonNaptSwitch(confTx, dpnId, routerId, routers.getRouterName(),
125                         primarySwitchId);
126             }
127         } else {
128             LOG.info("handleSnat (NAPTSwitch) : {} flows on switch {} for router {}",
129                     "Installing", dpnId, routers.getRouterName());
130             // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction)
131             addIpv6DefaultFibRoute(confTx, dpnId, routerId, routerMetadata);
132
133             // Program flows from PSNAT_TABLE(26) to OUTBOUND_NAPT_TABLE(46) (egress direction)
134             addIpv6SnatMissEntryForNaptSwitch(confTx, dpnId, routerId, routerMetadata);
135
136             // Program flows in INTERNAL_TUNNEL_TABLE(36) for packets coming from non-NAPTSwitch (egress direction)
137             addIpv6TerminatingServiceTblEntry(confTx, dpnId, routerId, routerMetadata);
138
139             // Program flows from NAPT_PFIB_TABLE(47) to FIB_TABLE(21) (ingress direction)
140             addIpv6NaptPfibInboundFlow(confTx, dpnId, routerId, routerMetadata);
141
142             // Now installing flows that use SubnetInfo
143             ipv6SubnetFlowProgrammer.addSubnetSpecificFlows(confTx, dpnId, routerId, routers, routerMetadata);
144         }
145         return true;
146     }
147
148     @Override
149     public boolean removeCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx,
150             Routers routers, Uint64 primarySwitchId) throws ExecutionException, InterruptedException {
151         String routerName = routers.getRouterName();
152         LOG.info("handleSnatAllSwitch : invoked for router {} with NAPTSwitch {} for {} flows",
153                 routerName, primarySwitchId, "removing");
154         List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
155         /*
156          * Primary switch handled separately since the pseudo port created may
157          * not be present in the switch list on delete.
158          */
159         removeCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
160         for (Uint64 dpnId : switches) {
161             if (!Objects.equals(primarySwitchId, dpnId)) {
162                 removeCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
163             }
164         }
165         return true;
166     }
167
168     @Override
169     public boolean removeCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx,
170             Routers routers, Uint64 primarySwitchId, Uint64 dpnId)
171                     throws ExecutionException, InterruptedException {
172         Uint32 routerId = NatUtil.getVpnId(dataBroker, routers.getRouterName());
173         Uint64 routerMetadata = MetaDataUtil.getVpnIdMetadata(routerId.longValue());
174
175         if (!dpnId.equals(primarySwitchId)) {
176             LOG.info("handleSnat (non-NAPTSwitch) : {} flows on switch {} for router {}",
177                     "Removing", dpnId, routers.getRouterName());
178             // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction)
179             addIpv6DefaultFibRoute(confTx, dpnId, routerId, routerMetadata);
180
181             // Currently we are only programming flows when ext-net has an IPv6Subnet
182             if (routerHasIpv6ExtSubnet(routers)) {
183                 // Program flows on non-NAPTSwitch to send N/S packets to the NAPTSwitch
184                 addIpv6PsNatMissEntryNonNaptSwitch(confTx, dpnId, routerId, routers.getRouterName(),
185                         primarySwitchId);
186             }
187         } else {
188             LOG.info("handleSnat (NAPTSwitch) : {} flows on switch {} for router {}",
189                     "Removing", dpnId, routers.getRouterName());
190             // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction)
191             removeIpv6DefaultFibRoute(confTx, dpnId, routerId);
192
193             // Program flows from PSNAT_TABLE(26) to OUTBOUND_NAPT_TABLE(46) (egress direction)
194             removeIpv6SnatMissEntryForNaptSwitch(confTx, dpnId, routerId);
195
196             // Program flows in INTERNAL_TUNNEL_TABLE(36) for packets coming from non-NAPTSwitch (egress direction)
197             removeIpv6TerminatingServiceTblEntry(confTx, dpnId, routerId);
198
199             // Program flows from NAPT_PFIB_TABLE(47) to FIB_TABLE(21) (ingress direction)
200             removeIpv6NaptPfibInboundFlow(confTx, dpnId, routerId);
201
202             // Now installing flows that use SubnetInfo
203             ipv6SubnetFlowProgrammer.removeSubnetSpecificFlows(confTx, dpnId, routerId, routers);
204         }
205         return true;
206     }
207
208     @Override
209     public boolean handleRouterUpdate(TypedReadWriteTransaction<Configuration> confTx,
210             Routers origRouter, Routers updatedRouter) throws ExecutionException, InterruptedException {
211         LOG.info("handleRouterUpdate : originalRouter {}, updatedRouter {}", origRouter, updatedRouter);
212         String routerName = origRouter.getRouterName();
213         Uint64 primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
214         Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
215         Uint64 routerMetadata = MetaDataUtil.getVpnIdMetadata(routerId.longValue());
216
217         // If the external network is updated with an IPv6Subnet, program the necessary flows on non-NAPTSwitch
218         if (!routerHasIpv6ExtSubnet(origRouter) && routerHasIpv6ExtSubnet(updatedRouter)) {
219             List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
220             for (Uint64 dpnId : switches) {
221                 if (!Objects.equals(primarySwitchId, dpnId)) {
222                     LOG.info("handleRouterUpdate (non-NAPTSwitch) : Installing flows on switch {} for router {}",
223                             dpnId, routerName);
224                     addIpv6PsNatMissEntryNonNaptSwitch(confTx, dpnId, routerId, routerName,
225                             primarySwitchId);
226                 }
227             }
228         }
229
230         ipv6SubnetFlowProgrammer.removeSubnetSpecificFlows(confTx, primarySwitchId, routerId, origRouter);
231         ipv6SubnetFlowProgrammer.addSubnetSpecificFlows(confTx, primarySwitchId, routerId, updatedRouter,
232                 routerMetadata);
233         return true;
234     }
235
236     @Override
237     public boolean addSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
238             Uint64 primarySwitchId) {
239         return true;
240     }
241
242     @Override
243     public boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
244             Uint64 primarySwitchId, Uint64 dpnId) {
245         return true;
246     }
247
248     @Override
249     public boolean removeSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
250             Uint64 primarySwitchId)  throws ExecutionException, InterruptedException {
251         return true;
252     }
253
254     @Override
255     public boolean removeSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
256             Uint64 primarySwitchId, Uint64 dpnId) throws ExecutionException, InterruptedException {
257         return true;
258     }
259
260
261     protected void addIpv6DefaultFibRoute(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
262                                           Uint32 routerId, Uint64 routerMetadata) {
263         LOG.debug("installIpv6DefaultFibRoute : Installing default FIB route to PSNAT_TABLE on {}", dpnId);
264         List<MatchInfo> matches = new ArrayList<>();
265         matches.add(MatchEthernetType.IPV6);
266         matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID));
267
268         List<InstructionInfo> instructions = new ArrayList<>();
269         instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
270
271         String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
272         flowRef += ".Outbound";
273         NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef,
274                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef,
275                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
276     }
277
278     protected void removeIpv6DefaultFibRoute(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
279                                              Uint32 routerId) throws ExecutionException, InterruptedException {
280         LOG.debug("installIpv6DefaultFibRoute : Installing default FIB route to PSNAT_TABLE on {}", dpnId);
281         String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
282         flowRef += ".Outbound";
283         NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
284     }
285
286     protected void addIpv6PsNatMissEntryNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
287             Uint64 dpnId, Uint32 routerId, String routerName, Uint64 primarySwitchId) {
288         LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, installing SNAT miss entry in"
289                 + " switch {} for router {}", dpnId, routerName);
290         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
291         List<BucketInfo> listBucketInfo = new ArrayList<>();
292
293         String ifNamePrimary = NatUtil.getTunnelInterfaceName(dpnId, primarySwitchId, itmManager);
294         if (ifNamePrimary != null) {
295             LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, Primary Tunnel interface is {}",
296                     ifNamePrimary);
297             listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
298                     interfaceManager, ifNamePrimary, routerId, true);
299         } else {
300             LOG.warn("installIpv6PsNatMissEntryNonNaptSwitch: could not get tunnelInterface for {} on Switch {}",
301                     primarySwitchId, dpnId);
302         }
303
304         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
305         listBucketInfo.add(0, bucketPrimary);
306
307         LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : installSnatMissEntry called for dpnId {} with"
308                 + " primaryBucket {} ", dpnId, listBucketInfo.get(0));
309
310         long groupId = createGroupIdForIpv6Router(getGroupIdKey(routerName + "IPv6"));
311         GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll,
312                 listBucketInfo);
313         LOG.debug("installing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId);
314         mdsalManager.addGroup(confTx, groupEntity);
315         List<MatchInfo> matches = new ArrayList<>();
316         matches.add(MatchEthernetType.IPV6);
317         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId.longValue()),
318                 MetaDataUtil.METADATA_MASK_VRFID));
319
320         List<ActionInfo> actionsInfo = new ArrayList<>();
321         actionsInfo.add(new ActionSetFieldTunnelId(Uint64.valueOf(routerId)));
322         actionsInfo.add(new ActionGroup(groupId));
323         List<InstructionInfo> instructions = new ArrayList<>();
324         instructions.add(new InstructionApplyActions(actionsInfo));
325
326         String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
327         NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef,
328                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
329                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
330     }
331
332     protected void addIpv6SnatMissEntryForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
333             Uint64 dpnId, Uint32 routerId, Uint64 routerMetadata) {
334         LOG.debug("installIpv6SnatMissEntryForNaptSwitch {} called for routerId {}", dpnId, routerId);
335         List<MatchInfo> matches = new ArrayList<>();
336         matches.add(MatchEthernetType.IPV6);
337         matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID));
338
339         List<InstructionInfo> instructions = new ArrayList<>();
340         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
341
342         String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
343         flowRef += ".Outbound";
344         NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef,
345                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
346                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
347     }
348
349     protected void removeIpv6SnatMissEntryForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
350             Uint64 dpnId, Uint32 routerId)
351                     throws ExecutionException, InterruptedException {
352         LOG.debug("installIpv6SnatMissEntryForNaptSwitch {} called for routerId {}", dpnId, routerId);
353         String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
354         flowRef += ".Outbound";
355         NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef);
356     }
357
358     protected void addIpv6TerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
359             Uint64 dpnId, Uint32  routerId, Uint64 routerMetadata) {
360         LOG.debug("installIpv6TerminatingServiceTblEntry : creating entry for Terminating Service Table "
361                 + "for switch {}, routerId {}", dpnId, routerId);
362         List<MatchInfo> matches = new ArrayList<>();
363         matches.add(MatchEthernetType.IPV6);
364         matches.add(new MatchTunnelId(Uint64.valueOf(routerId)));
365
366         List<ActionInfo> actionsInfos = new ArrayList<>();
367         ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(routerMetadata, LOAD_START, LOAD_END);
368         actionsInfos.add(actionLoadMeta);
369         actionsInfos.add(new ActionNxResubmit(NwConstants.OUTBOUND_NAPT_TABLE));
370         List<InstructionInfo> instructions = new ArrayList<>();
371         instructions.add(new InstructionApplyActions(actionsInfos));
372
373         String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
374         flowRef += ".Outbound";
375         NatUtil.addFlow(confTx, mdsalManager, dpnId,  NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
376                 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef,
377                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
378
379     }
380
381     protected void removeIpv6TerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
382             Uint64 dpnId, Uint32 routerId) throws ExecutionException, InterruptedException {
383         LOG.debug("installIpv6TerminatingServiceTblEntry : creating entry for Terminating Service Table "
384                 + "for switch {}, routerId {}", dpnId, routerId);
385         String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
386         flowRef += ".Outbound";
387         NatUtil.removeFlow(confTx, mdsalManager, dpnId,  NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
388
389     }
390
391     protected void addIpv6NaptPfibInboundFlow(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
392                                               Uint32 routerId, Uint64 routerMetadata) {
393         LOG.debug("installIpv6NaptPfibInboundFlow : called for dpnId {} and routerId {} ", dpnId, routerId);
394         List<MatchInfoBase> matches = new ArrayList<>();
395         matches.add(MatchEthernetType.IPV6);
396         matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID));
397
398         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
399         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
400         listActionInfo.add(new ActionNxLoadInPort(Uint64.ZERO));
401         listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
402         instructionInfo.add(new InstructionApplyActions(listActionInfo));
403
404         String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
405         flowRef += ".Inbound";
406         NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef,
407                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY,
408                 flowRef, NwConstants.COOKIE_SNAT_TABLE,
409                 matches, instructionInfo);
410     }
411
412     protected void removeIpv6NaptPfibInboundFlow(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
413                                                  Uint32 routerId)
414                     throws ExecutionException, InterruptedException {
415         LOG.debug("installIpv6NaptPfibInboundFlow : called for dpnId {} and routerId {} ", dpnId, routerId);
416         String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
417         flowRef += ".Inbound";
418         NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
419     }
420
421     protected long createGroupIdForIpv6Router(String groupIdKey) {
422         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
423                 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
424                 .build();
425         try {
426             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
427             RpcResult<AllocateIdOutput> rpcResult = result.get();
428             return rpcResult.getResult().getIdValue().toJava();
429         } catch (NullPointerException | InterruptedException | ExecutionException e) {
430             LOG.error("createGroupIdForIPv6Router: Exception while creating group with key : {}", groupIdKey, e);
431         }
432         return 0;
433     }
434
435     protected boolean routerHasIpv6ExtSubnet(Routers routers) {
436         for (ExternalIps externalIp : routers.getExternalIps()) {
437             if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
438                 LOG.debug("router {}, has an external IPv6 subnet {}",
439                         routers.getRouterName(), externalIp.getIpAddress());
440                 return true;
441             }
442         }
443         LOG.debug("router {}, does not have an external IPv6 subnet", routers.getRouterName());
444         return false;
445     }
446 }