2 * Copyright (c) 2017 Red Hat, Inc. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.natservice.internal;
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
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;
84 public abstract class AbstractSnatService implements SnatServiceListener {
85 private static final Logger LOG = LoggerFactory.getLogger(AbstractSnatService.class);
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());
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;
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;
125 protected DataBroker getDataBroker() {
130 LOG.info("{} init", getClass().getSimpleName());
133 public void close() {
134 LOG.debug("AbstractSnatService Closed");
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);
144 * Primary switch handled separately since the pseudo port created may
145 * not be present in the switch list on delete.
147 addSnat(confTx, routers, primarySwitchId, primarySwitchId);
148 for (BigInteger dpnId : switches) {
149 if (!Objects.equals(primarySwitchId, dpnId)) {
150 addSnat(confTx, routers, primarySwitchId, dpnId);
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);
163 * Primary switch handled separately since the pseudo port created may
164 * not be present in the switch list on delete.
166 removeSnat(confTx, routers, primarySwitchId, primarySwitchId);
167 for (BigInteger dpnId : switches) {
168 if (!Objects.equals(primarySwitchId, dpnId)) {
169 removeSnat(confTx, routers, primarySwitchId, dpnId);
176 public boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers, BigInteger primarySwitchId,
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);
185 LOG.info("addSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
186 addSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
187 addSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
193 public boolean removeSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
194 BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException {
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);
202 LOG.info("removeSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
203 removeSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
204 removeSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
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);
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);
244 if (isLastRouterDelete) {
245 removeLearntIpPorts(routers);
246 removeMipAdjacencies(routers);
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);
259 LOG.info("addCentralizedRouter : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
260 addCommonEntriesForNaptSwitch(confTx, routers, dpnId);
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);
273 LOG.info("removeCentralizedRouter : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
274 removeCommonEntriesForNaptSwitch(confTx, routers, dpnId);
280 public boolean handleRouterUpdate(TypedReadWriteTransaction<Configuration> confTx,
281 Routers origRouter, Routers updatedRouter) throws ExecutionException, InterruptedException {
285 protected void addCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
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.
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);
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.
315 removeInboundTerminatingServiceTblEntry(confTx, dpnId, routerId);
316 removeTerminatingServiceTblEntry(confTx, dpnId, routerId);
321 protected void addSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
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.
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);
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.
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());
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);
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);
372 protected void addSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
373 Routers routers, BigInteger primarySwitchId, BigInteger dpnId) {
374 /* Nothing to do here*/
377 protected void removeSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
378 Routers routers, BigInteger dpnId) throws ExecutionException, InterruptedException {
379 /* Nothing to do here*/
382 protected abstract void addSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
383 Routers routers, BigInteger dpnId);
385 protected abstract void removeSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
386 Routers routers, BigInteger dpnId) throws ExecutionException, InterruptedException;
388 protected abstract void addSnatSpecificEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
389 Routers routers, BigInteger dpnId);
391 protected abstract void removeSnatSpecificEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
392 Routers routers, BigInteger dpnId);
394 protected void addInboundFibEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, String externalIp,
395 Long routerId, long extSubnetId, String externalNetId, String subNetId, String routerMac) {
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.");
403 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extSubnetId),
404 MetaDataUtil.METADATA_MASK_VRFID));
405 matches.add(new MatchIpv4Destination(externalIp, "32"));
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));
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,
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);
423 fibManager.addOrUpdateFibEntry(rd, routerMac, ipPrefix,
424 Collections.singletonList(nextHopIp), VrfEntry.EncapType.Mplsgre, extSubnetId,
425 0, null, externalNetId, RouteOrigin.STATIC, null);
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);
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)));
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);
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);
465 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
466 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
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);
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));
487 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll,
489 LOG.debug("installing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId);
490 mdsalManager.addGroup(confTx, groupEntity);
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));
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));
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,
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));
532 LOG.debug("removing the PSNAT to NAPTSwitch on DPN {} with GroupId: {}", dpnId, groupId);
533 mdsalManager.removeGroup(confTx, dpnId, groupId);
535 // Install miss entry pointing to group
536 LOG.debug("installSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
537 dpnId, routerName, groupId);
539 String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
540 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef);
543 protected void addInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
544 BigInteger dpnId, Long routerId, long extSubnetId) {
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.");
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);
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);
577 protected void addDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
580 List<MatchInfo> matches = new ArrayList<>();
581 matches.add(MatchEthernetType.IPV4);
582 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extNetId),
583 MetaDataUtil.METADATA_MASK_VRFID));
585 List<InstructionInfo> instructions = new ArrayList<>();
586 instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
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,
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);
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;
605 protected long createGroupId(String groupIdKey) {
606 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
607 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
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);
619 protected String getGroupIdKey(String routerName) {
620 return "snatmiss." + routerName;
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.
631 externalSubNetId = externalIp.getSubnetId().getValue();
634 if (externalSubNetId == null) {
635 LOG.info("removeMipAdjacencies no external Ipv4 address present on router {}",
636 routers.getRouterName());
639 InstanceIdentifier<VpnInterfaces> vpnInterfacesId =
640 InstanceIdentifier.builder(VpnInterfaces.class).build();
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);
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());
661 VpnInterfacesBuilder vpnInterfacesBuilder = new VpnInterfacesBuilder();
662 vpnInterfacesBuilder.setVpnInterface(updatedVpnInterface);
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());
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");
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);
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.
694 externalSubNetId = externalIp.getSubnetId().getValue();
697 if (externalSubNetId == null) {
698 LOG.info("removeLearntIpPorts no external Ipv4 address present on router {}",
699 routers.getRouterName());
702 String prefix = learntVpnVipToPort.getPortFixedip() + "/32";
703 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker,
704 externalSubNetId), prefix);
709 learntVpnVipToPortDataBuilder.setLearntVpnVipToPort(learntVpnVipToPortList);
710 InstanceIdentifier<LearntVpnVipToPortData> learntVpnVipToPortDataId = NatUtil
711 .getLearntVpnVipToPortDataId();
712 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
713 learntVpnVipToPortDataId, learntVpnVipToPortDataBuilder.build());
715 } catch (TransactionCommitFailedException e) {
716 LOG.warn("Failed to remove removeLearntIpPorts with error {}", e.getMessage());
720 static int mostSignificantBit(int value) {
721 return 31 - Integer.numberOfLeadingZeros(value);