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.time.Duration;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.Objects;
17 import java.util.concurrent.ExecutionException;
18 import org.opendaylight.genius.datastoreutils.ExpectedDataObjectNotFoundException;
19 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
20 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
21 import org.opendaylight.genius.infra.Datastore.Configuration;
22 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
24 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
25 import org.opendaylight.genius.infra.TypedWriteTransaction;
26 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
27 import org.opendaylight.genius.mdsalutil.ActionInfo;
28 import org.opendaylight.genius.mdsalutil.BucketInfo;
29 import org.opendaylight.genius.mdsalutil.GroupEntity;
30 import org.opendaylight.genius.mdsalutil.InstructionInfo;
31 import org.opendaylight.genius.mdsalutil.MDSALUtil;
32 import org.opendaylight.genius.mdsalutil.MatchInfo;
33 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
34 import org.opendaylight.genius.mdsalutil.NWUtil;
35 import org.opendaylight.genius.mdsalutil.NwConstants;
36 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
37 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadMetadata;
38 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
39 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
40 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
41 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
42 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
43 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
44 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
45 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
46 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
47 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
48 import org.opendaylight.mdsal.binding.api.DataBroker;
49 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
50 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
51 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
52 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
53 import org.opendaylight.netvirt.natservice.api.SnatServiceListener;
54 import org.opendaylight.netvirt.natservice.ha.NatDataUtil;
55 import org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortDataBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.Adjacencies;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.AdjacenciesBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.VpnInterfaces;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.VpnInterfacesBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterface;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterfaceBuilder;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.opendaylight.yangtools.yang.common.Uint32;
76 import org.opendaylight.yangtools.yang.common.Uint64;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
80 public abstract class AbstractSnatService implements SnatServiceListener {
81 private static final Logger LOG = LoggerFactory.getLogger(AbstractSnatService.class);
83 static final int LOAD_START = mostSignificantBit(MetaDataUtil.METADATA_MASK_SH_FLAG.intValue());
84 static final int LOAD_END = mostSignificantBit(MetaDataUtil.METADATA_MASK_VRFID.intValue() | MetaDataUtil
85 .METADATA_MASK_SH_FLAG.intValue());
87 protected final DataBroker dataBroker;
88 protected final ManagedNewTransactionRunner txRunner;
89 protected final IMdsalApiManager mdsalManager;
90 protected final IdManagerService idManager;
91 private final NAPTSwitchSelector naptSwitchSelector;
92 final ItmRpcService itmManager;
93 protected final OdlInterfaceRpcService odlInterfaceRpcService;
94 protected final IInterfaceManager interfaceManager;
95 final IVpnFootprintService vpnFootprintService;
96 protected final IFibManager fibManager;
97 private final NatDataUtil natDataUtil;
98 private final DataTreeEventCallbackRegistrar eventCallbacks;
100 AbstractSnatService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
101 final ItmRpcService itmManager, final OdlInterfaceRpcService odlInterfaceRpcService,
102 final IdManagerService idManager, final NAPTSwitchSelector naptSwitchSelector,
103 final IInterfaceManager interfaceManager,
104 final IVpnFootprintService vpnFootprintService,
105 final IFibManager fibManager, final NatDataUtil natDataUtil,
106 final DataTreeEventCallbackRegistrar eventCallbacks) {
107 this.dataBroker = dataBroker;
108 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
109 this.mdsalManager = mdsalManager;
110 this.itmManager = itmManager;
111 this.interfaceManager = interfaceManager;
112 this.idManager = idManager;
113 this.naptSwitchSelector = naptSwitchSelector;
114 this.odlInterfaceRpcService = odlInterfaceRpcService;
115 this.vpnFootprintService = vpnFootprintService;
116 this.fibManager = fibManager;
117 this.natDataUtil = natDataUtil;
118 this.eventCallbacks = eventCallbacks;
121 protected DataBroker getDataBroker() {
126 public boolean addSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
127 Uint64 primarySwitchId) {
128 LOG.info("addSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
129 String routerName = routers.getRouterName();
130 List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
132 * Primary switch handled separately since the pseudo port created may
133 * not be present in the switch list on delete.
135 addSnat(confTx, routers, primarySwitchId, primarySwitchId);
136 for (Uint64 dpnId : switches) {
137 if (!Objects.equals(primarySwitchId, dpnId)) {
138 addSnat(confTx, routers, primarySwitchId, dpnId);
145 public boolean removeSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
146 Uint64 primarySwitchId) throws ExecutionException, InterruptedException {
147 LOG.info("removeSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
148 String routerName = routers.getRouterName();
149 List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
151 * Primary switch handled separately since the pseudo port created may
152 * not be present in the switch list on delete.
154 removeSnat(confTx, routers, primarySwitchId, primarySwitchId);
155 for (Uint64 dpnId : switches) {
156 if (!Objects.equals(primarySwitchId, dpnId)) {
157 removeSnat(confTx, routers, primarySwitchId, dpnId);
164 public boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers, Uint64 primarySwitchId,
167 // Handle non NAPT switches and NAPT switches separately
168 if (!dpnId.equals(primarySwitchId)) {
169 LOG.info("addSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
170 addSnatCommonEntriesForNonNaptSwitch();
171 addSnatSpecificEntriesForNonNaptSwitch();
173 LOG.info("addSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
174 addSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
175 addSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
181 public boolean removeSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
182 Uint64 primarySwitchId, Uint64 dpnId) throws ExecutionException, InterruptedException {
184 // Handle non NAPT switches and NAPT switches separately
185 if (!dpnId.equals(primarySwitchId)) {
186 LOG.info("removeSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
187 removeSnatCommonEntriesForNonNaptSwitch();
188 removeSnatSpecificEntriesForNonNaptSwitch();
190 LOG.info("removeSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
191 removeSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
192 removeSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
199 public boolean addCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
200 Uint64 primarySwitchId) {
201 LOG.info("addCentralizedRouterAllSwitch : Handle Snat in all switches for router {}",
202 routers.getRouterName());
203 String routerName = routers.getRouterName();
204 List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
205 addCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
206 for (Uint64 dpnId : switches) {
207 if (!Objects.equals(primarySwitchId, dpnId)) {
208 addCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
215 public boolean removeCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
216 Uint64 primarySwitchId) throws ExecutionException, InterruptedException {
217 LOG.info("removeCentralizedRouterAllSwitch : Handle Snat in all switches for router {}",
218 routers.getRouterName());
219 boolean isLastRouterDelete = false;
220 isLastRouterDelete = NatUtil.isLastExternalRouter(routers.getNetworkId()
221 .getValue(), routers.getRouterName(), natDataUtil);
222 LOG.info("removeCentralizedRouterAllSwitch : action is delete for router {} and isLastRouterDelete is {}",
223 routers.getRouterName(), isLastRouterDelete);
224 removeCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
225 String routerName = routers.getRouterName();
226 List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
227 for (Uint64 dpnId : switches) {
228 if (!Objects.equals(primarySwitchId, dpnId)) {
229 removeCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
232 if (isLastRouterDelete) {
233 removeLearntIpPorts(routers);
234 removeMipAdjacencies(routers);
240 public boolean addCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
241 Uint64 primarySwitchId, Uint64 dpnId) {
242 if (!dpnId.equals(primarySwitchId)) {
243 LOG.info("addCentralizedRouter : Handle non NAPT switch {} for router {}",
244 dpnId, routers.getRouterName());
245 addCommonEntriesForNonNaptSwitch(confTx, routers, primarySwitchId, dpnId);
247 LOG.info("addCentralizedRouter : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
248 addCommonEntriesForNaptSwitch(confTx, routers, dpnId);
254 public boolean removeCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
255 Uint64 primarySwitchId, Uint64 dpnId) throws ExecutionException, InterruptedException {
256 if (!dpnId.equals(primarySwitchId)) {
257 LOG.info("removeCentralizedRouter : Handle non NAPT switch {} for router {}",
258 dpnId, routers.getRouterName());
259 removeCommonEntriesForNonNaptSwitch(confTx, routers, dpnId);
261 LOG.info("removeCentralizedRouter : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
262 removeCommonEntriesForNaptSwitch(confTx, routers, dpnId);
268 public boolean handleRouterUpdate(TypedReadWriteTransaction<Configuration> confTx,
269 Routers origRouter, Routers updatedRouter) throws ExecutionException, InterruptedException {
273 private void addCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
275 String routerName = routers.getRouterName();
276 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
277 addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
278 for (ExternalIps externalIp : routers.nonnullExternalIps().values()) {
279 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
280 // In this class we handle only IPv4 use-cases.
283 //The logic now handle only one external IP per router, others if present will be ignored.
284 Uint32 extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker, externalIp.getSubnetId());
285 addInboundTerminatingServiceTblEntry(confTx, dpnId, routerId, extSubnetId);
286 addTerminatingServiceTblEntry(confTx, dpnId, routerId);
291 private void removeCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
292 Uint64 dpnId) throws ExecutionException, InterruptedException {
293 String routerName = routers.getRouterName();
294 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
295 removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
296 for (ExternalIps externalIp : routers.nonnullExternalIps().values()) {
297 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
298 // In this class we handle only IPv4 use-cases.
301 removeInboundTerminatingServiceTblEntry(confTx, dpnId, routerId);
302 removeTerminatingServiceTblEntry(confTx, dpnId, routerId);
307 private void addSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
309 String routerName = routers.getRouterName();
310 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
311 String externalGwMac = routers.getExtGwMacAddress();
312 for (ExternalIps externalIp : routers.nonnullExternalIps().values()) {
313 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
314 // In this class we handle only IPv4 use-cases.
317 //The logic now handle only one external IP per router, others if present will be ignored.
318 Uint32 extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker, externalIp.getSubnetId());
319 addInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId, extSubnetId,
320 routers.getNetworkId().getValue(), externalIp.getSubnetId().getValue(), externalGwMac);
325 private void removeSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
326 Routers routers, Uint64 dpnId) throws ExecutionException, InterruptedException {
327 String routerName = routers.getRouterName();
328 Uint32 routerId = NatUtil.getVpnId(confTx, routerName);
329 for (ExternalIps externalIp : routers.nonnullExternalIps().values()) {
330 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
331 // In this class we handle only IPv4 use-cases.
334 //The logic now handle only one external IP per router, others if present will be ignored.
335 removeInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId,
336 externalIp.getSubnetId().getValue());
342 private void addCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
343 Uint64 primarySwitchId, Uint64 dpnId) {
344 String routerName = routers.getRouterName();
345 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
346 addSnatMissEntry(confTx, dpnId, routerId, routerName, primarySwitchId);
347 addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
350 private void removeCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
351 Uint64 dpnId) throws ExecutionException, InterruptedException {
352 String routerName = routers.getRouterName();
353 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
354 removeSnatMissEntry(confTx, dpnId, routerId, routerName);
355 removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
358 private void addSnatCommonEntriesForNonNaptSwitch() {
359 /* Nothing to do here*/
362 private void removeSnatCommonEntriesForNonNaptSwitch() {
363 /* Nothing to do here*/
366 protected abstract void addSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
367 Routers routers, Uint64 dpnId);
369 protected abstract void removeSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
370 Routers routers, Uint64 dpnId) throws ExecutionException, InterruptedException;
372 protected abstract void addSnatSpecificEntriesForNonNaptSwitch();
374 protected abstract void removeSnatSpecificEntriesForNonNaptSwitch();
376 private void addInboundFibEntry(TypedWriteTransaction<Configuration> confTx, Uint64 dpnId, String externalIp,
377 Uint32 routerId, Uint32 extSubnetId, String externalNetId,
378 String subNetId, String routerMac) {
380 List<MatchInfo> matches = new ArrayList<>();
381 matches.add(MatchEthernetType.IPV4);
382 if (extSubnetId == NatConstants.INVALID_ID) {
383 LOG.error("ConntrackBasedSnatService : installInboundFibEntry : external subnet id is invalid.");
386 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extSubnetId.longValue()),
387 MetaDataUtil.METADATA_MASK_VRFID));
388 matches.add(new MatchIpv4Destination(externalIp, "32"));
390 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
391 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
392 listActionInfo.add(new ActionNxResubmit(NwConstants.INBOUND_NAPT_TABLE));
393 instructionInfo.add(new InstructionApplyActions(listActionInfo));
395 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
396 flowRef = flowRef + "inbound" + externalIp;
397 NatUtil.addFlow(confTx, mdsalManager,dpnId, NwConstants.L3_FIB_TABLE, flowRef,
398 NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
400 String rd = NatUtil.getVpnRd(dataBroker, subNetId);
401 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
402 String ipPrefix = externalIp + "/32";
403 NatUtil.addPrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, subNetId),
404 null, ipPrefix, externalNetId, dpnId, Prefixes.PrefixCue.Nat);
406 fibManager.addOrUpdateFibEntry(rd, routerMac, ipPrefix,
407 Collections.singletonList(nextHopIp), VrfEntry.EncapType.Mplsgre, extSubnetId,
408 Uint32.ZERO, null, externalNetId, RouteOrigin.STATIC, null);
411 private void removeInboundFibEntry(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
412 String externalIp, Uint32 routerId, String subNetId) throws ExecutionException, InterruptedException {
413 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
414 flowRef = flowRef + "inbound" + externalIp;
415 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
416 String rd = NatUtil.getVpnRd(dataBroker, subNetId);
417 String ipPrefix = externalIp + "/32";
418 fibManager.removeFibEntry(rd, ipPrefix, null, confTx);
419 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, subNetId), ipPrefix);
423 private void addTerminatingServiceTblEntry(TypedWriteTransaction<Configuration> confTx, Uint64 dpnId,
425 LOG.info("addTerminatingServiceTblEntry : creating entry for Terminating Service Table "
426 + "for switch {}, routerId {}", dpnId, routerId);
427 List<MatchInfo> matches = new ArrayList<>();
428 matches.add(MatchEthernetType.IPV4);
429 matches.add(new MatchTunnelId(Uint64.valueOf(routerId)));
431 List<ActionInfo> actionsInfos = new ArrayList<>();
432 ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
433 .getVpnIdMetadata(routerId.longValue()), LOAD_START, LOAD_END);
434 actionsInfos.add(actionLoadMeta);
435 actionsInfos.add(new ActionNxResubmit(NwConstants.PSNAT_TABLE));
436 List<InstructionInfo> instructions = new ArrayList<>();
437 instructions.add(new InstructionApplyActions(actionsInfos));
438 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
439 NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
440 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE,
441 matches, instructions);
444 private void removeTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
445 Uint32 routerId) throws ExecutionException, InterruptedException {
446 LOG.info("removeTerminatingServiceTblEntry : creating entry for Terminating Service Table "
447 + "for switch {}, routerId {}", dpnId, routerId);
449 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
450 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
453 protected void addSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
454 Uint32 routerId, String routerName, Uint64 primarySwitchId) {
455 LOG.debug("installSnatMissEntry : Installing SNAT miss entry in switch {}", dpnId);
456 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
457 String ifNamePrimary = NatUtil.getTunnelInterfaceName(dpnId, primarySwitchId, itmManager);
458 List<BucketInfo> listBucketInfo = new ArrayList<>();
459 if (ifNamePrimary != null) {
460 LOG.debug("installSnatMissEntry : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
461 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
462 interfaceManager, ifNamePrimary, routerId, true);
464 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
465 listBucketInfo.add(0, bucketPrimary);
466 LOG.debug("installSnatMissEntry : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId,
467 listBucketInfo.get(0));
468 // Install the select group
469 Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME, getGroupIdKey(routerName));
470 if (groupId != NatConstants.INVALID_ID) {
471 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId.longValue(), routerName,
472 GroupTypes.GroupAll, listBucketInfo);
473 LOG.debug("installing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId);
474 mdsalManager.addGroup(confTx, groupEntity);
476 // Add the flow to send the packet to the group only after group is available in Config datastore
477 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
478 NatUtil.getGroupInstanceId(dpnId, groupId), (unused, newGroupId) -> {
479 LOG.info("group {} is created in the config", groupId);
480 LoggingFutures.addErrorLogging(
481 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
482 innerConfTx -> addSnatMissFlowForGroup(innerConfTx, dpnId, routerId, groupId)),
483 LOG, "Error adding flow for the group {}",groupId);
484 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
485 }, Duration.ofSeconds(5), iid -> LOG.error("groupId {} not found in config datastore", groupId));
487 LOG.error("installSnatMissEntry: Unable to get groupId for routerName:{}", routerName);
491 private void addSnatMissFlowForGroup(TypedReadWriteTransaction<Configuration> confTx,
492 Uint64 dpnId, Uint32 routerId, Uint32 groupId) {
493 // Install miss entry pointing to group
494 LOG.debug("installSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerId {} and groupId {}",
495 dpnId, routerId, groupId);
496 List<MatchInfo> matches = new ArrayList<>();
497 matches.add(new MatchEthernetType(0x0800L));
498 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId.longValue()),
499 MetaDataUtil.METADATA_MASK_VRFID));
500 List<ActionInfo> actionsInfo = new ArrayList<>();
501 actionsInfo.add(new ActionSetFieldTunnelId(Uint64.valueOf(routerId)));
502 LOG.debug("installSnatMissEntry : Setting the tunnel to the list of action infos {}", actionsInfo);
503 actionsInfo.add(new ActionGroup(groupId.longValue()));
504 List<InstructionInfo> instructions = new ArrayList<>();
505 instructions.add(new InstructionApplyActions(actionsInfo));
506 String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
507 NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef,
508 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
512 protected void removeSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
513 Uint32 routerId, String routerName)
514 throws ExecutionException, InterruptedException {
515 LOG.debug("removeSnatMissEntry : Removing SNAT miss entry from switch {}", dpnId);
516 // Install the select group
517 Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME, getGroupIdKey(routerName));
518 if (groupId != NatConstants.INVALID_ID) {
519 LOG.debug("removeSnatMissEntry : removing the PSNAT to NAPTSwitch on DPN {} with GroupId: {}", dpnId,
521 mdsalManager.removeGroup(confTx, dpnId, groupId.longValue());
523 LOG.error("removeSnatMissEntry: Unable to get groupId for routerName:{}", routerName);
525 // Install miss entry pointing to group
526 LOG.debug("removeSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
527 dpnId, routerName, groupId);
529 String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
530 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef);
533 private void addInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
534 Uint64 dpnId, Uint32 routerId, Uint32 extSubnetId) {
536 //Install the tunnel table entry in NAPT switch for inbound traffic to SNAT IP from a non a NAPT switch.
537 LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
538 + "for switch {}, routerId {}", dpnId, routerId);
539 List<MatchInfo> matches = new ArrayList<>();
540 matches.add(MatchEthernetType.IPV4);
541 List<ActionInfo> actionsInfos = new ArrayList<>();
542 if (extSubnetId == NatConstants.INVALID_ID) {
543 LOG.error("installInboundTerminatingServiceTblEntry : external subnet id is invalid.");
546 matches.add(new MatchTunnelId(Uint64.valueOf(extSubnetId)));
547 ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
548 .getVpnIdMetadata(extSubnetId.longValue()), LOAD_START, LOAD_END);
549 actionsInfos.add(actionLoadMeta);
550 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
551 List<InstructionInfo> instructions = new ArrayList<>();
552 instructions.add(new InstructionApplyActions(actionsInfos));
553 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId) + "INBOUND";
554 NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
555 NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
558 private void removeInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
559 Uint64 dpnId, Uint32 routerId) throws ExecutionException, InterruptedException {
560 //Install the tunnel table entry in NAPT switch for inbound traffic to SNAT IP from a non a NAPT switch.
561 LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
562 + "for switch {}, routerId {}", dpnId, routerId);
563 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId) + "INBOUND";
564 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
567 private void addDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
570 List<MatchInfo> matches = new ArrayList<>();
571 matches.add(MatchEthernetType.IPV4);
572 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extNetId.longValue()),
573 MetaDataUtil.METADATA_MASK_VRFID));
575 List<InstructionInfo> instructions = new ArrayList<>();
576 instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
578 String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
579 NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef,
580 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
584 private void removeDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, Uint64 dpnId,
585 Uint32 extNetId) throws ExecutionException, InterruptedException {
586 String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
587 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
590 protected String getFlowRef(Uint64 dpnId, short tableId, Uint32 routerID) {
591 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR
592 + tableId + NatConstants.FLOWID_SEPARATOR + routerID;
595 protected String getGroupIdKey(String routerName) {
596 return "snatmiss." + routerName;
599 private void removeMipAdjacencies(Routers routers) {
600 LOG.info("removeMipAdjacencies for router {}", routers.getRouterName());
601 String externalSubNetId = null;
602 for (ExternalIps externalIp : routers.nonnullExternalIps().values()) {
603 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
604 // In this class we handle only IPv4 use-cases.
607 externalSubNetId = externalIp.getSubnetId().getValue();
610 if (externalSubNetId == null) {
611 LOG.info("removeMipAdjacencies no external Ipv4 address present on router {}",
612 routers.getRouterName());
615 InstanceIdentifier<VpnInterfaces> vpnInterfacesId =
616 InstanceIdentifier.builder(VpnInterfaces.class).build();
618 VpnInterfaces vpnInterfaces = SingleTransactionDataBroker.syncRead(dataBroker,
619 LogicalDatastoreType.CONFIGURATION, vpnInterfacesId);
620 List<VpnInterface> updatedVpnInterface = new ArrayList<>();
621 for (VpnInterface vpnInterface : vpnInterfaces.nonnullVpnInterface().values()) {
622 List<Adjacency> updatedAdjacencies = new ArrayList<>();
623 Adjacencies adjacencies = vpnInterface.augmentation(Adjacencies.class);
624 if (null != adjacencies) {
625 for (Adjacency adjacency : adjacencies.nonnullAdjacency().values()) {
626 if (!adjacency.getSubnetId().getValue().equals(externalSubNetId)) {
627 updatedAdjacencies.add(adjacency);
631 AdjacenciesBuilder adjacenciesBuilder = new AdjacenciesBuilder();
632 adjacenciesBuilder.setAdjacency(updatedAdjacencies);
633 VpnInterfaceBuilder vpnInterfaceBuilder = new VpnInterfaceBuilder(vpnInterface);
634 vpnInterfaceBuilder.addAugmentation(Adjacencies.class, adjacenciesBuilder.build());
635 updatedVpnInterface.add(vpnInterfaceBuilder.build());
637 VpnInterfacesBuilder vpnInterfacesBuilder = new VpnInterfacesBuilder();
638 vpnInterfacesBuilder.setVpnInterface(updatedVpnInterface);
640 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
641 vpnInterfacesId, vpnInterfacesBuilder.build());
642 } catch (ExpectedDataObjectNotFoundException e) {
643 LOG.warn("Failed to read removeMipAdjacencies with error {}", e.getMessage());
644 } catch (TransactionCommitFailedException e) {
645 LOG.warn("Failed to remove removeMipAdjacencies with error {}", e.getMessage());
649 private void removeLearntIpPorts(Routers routers) {
650 LOG.info("removeLearntIpPorts for router {} and network {}", routers.getRouterName(), routers.getNetworkId());
651 String networkId = routers.getNetworkId().getValue();
652 LearntVpnVipToPortData learntVpnVipToPortData = NatUtil.getLearntVpnVipToPortData(dataBroker);
653 if (learntVpnVipToPortData == null) {
654 LOG.info("removeLearntIpPorts, no learned ports present");
657 LearntVpnVipToPortDataBuilder learntVpnVipToPortDataBuilder = new LearntVpnVipToPortDataBuilder();
658 List<LearntVpnVipToPort> learntVpnVipToPortList = new ArrayList<>();
659 for (LearntVpnVipToPort learntVpnVipToPort : learntVpnVipToPortData.nonnullLearntVpnVipToPort().values()) {
660 if (!networkId.equals(learntVpnVipToPort.getVpnName())) {
661 LOG.info("The learned port belongs to Vpn {} hence not removing", learntVpnVipToPort.getVpnName());
662 learntVpnVipToPortList.add(learntVpnVipToPort);
664 String externalSubNetId = null;
665 for (ExternalIps externalIp : routers.nonnullExternalIps().values()) {
666 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
667 // In this class we handle only IPv4 use-cases.
670 externalSubNetId = externalIp.getSubnetId().getValue();
673 if (externalSubNetId == null) {
674 LOG.info("removeLearntIpPorts no external Ipv4 address present on router {}",
675 routers.getRouterName());
678 String prefix = learntVpnVipToPort.getPortFixedip() + "/32";
679 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker,
680 externalSubNetId), prefix);
685 learntVpnVipToPortDataBuilder.setLearntVpnVipToPort(learntVpnVipToPortList);
686 InstanceIdentifier<LearntVpnVipToPortData> learntVpnVipToPortDataId = NatUtil
687 .getLearntVpnVipToPortDataId();
688 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
689 learntVpnVipToPortDataId, learntVpnVipToPortDataBuilder.build());
691 } catch (TransactionCommitFailedException e) {
692 LOG.warn("Failed to remove removeLearntIpPorts with error {}", e.getMessage());
696 static int mostSignificantBit(int value) {
697 return 31 - Integer.numberOfLeadingZeros(value);