2 * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. 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.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import com.google.common.base.Optional;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import java.math.BigInteger;
20 import java.net.Inet6Address;
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
31 import java.util.Objects;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.Future;
35 import javax.annotation.Nonnull;
36 import javax.annotation.Nullable;
37 import javax.annotation.PostConstruct;
38 import javax.inject.Inject;
39 import javax.inject.Singleton;
40 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
41 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
42 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
43 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
44 import org.opendaylight.genius.infra.Datastore.Configuration;
45 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
46 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
47 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
48 import org.opendaylight.genius.infra.TypedWriteTransaction;
49 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
50 import org.opendaylight.genius.mdsalutil.ActionInfo;
51 import org.opendaylight.genius.mdsalutil.BucketInfo;
52 import org.opendaylight.genius.mdsalutil.FlowEntity;
53 import org.opendaylight.genius.mdsalutil.GroupEntity;
54 import org.opendaylight.genius.mdsalutil.InstructionInfo;
55 import org.opendaylight.genius.mdsalutil.MDSALUtil;
56 import org.opendaylight.genius.mdsalutil.MatchInfo;
57 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
58 import org.opendaylight.genius.mdsalutil.NwConstants;
59 import org.opendaylight.genius.mdsalutil.NwConstants.NxmOfFieldType;
60 import org.opendaylight.genius.mdsalutil.UpgradeState;
61 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
62 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
63 import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
64 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromField;
65 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromValue;
66 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
67 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
68 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
69 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
70 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
71 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
72 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
73 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
74 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
75 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
76 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
77 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
78 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
79 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
80 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
81 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
82 import org.opendaylight.netvirt.elanmanager.api.IElanService;
83 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
84 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
85 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
86 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
87 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
88 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
89 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
90 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIds;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsBuilder;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsKey;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
143 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
144 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
145 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
146 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
147 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
148 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelOutput;
149 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
150 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
151 import org.opendaylight.yangtools.yang.binding.DataObject;
152 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
153 import org.opendaylight.yangtools.yang.common.RpcResult;
154 import org.slf4j.Logger;
155 import org.slf4j.LoggerFactory;
158 public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener> {
159 private static final Logger LOG = LoggerFactory.getLogger(ExternalRoutersListener.class);
161 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
162 private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
164 private final DataBroker dataBroker;
165 private final ManagedNewTransactionRunner txRunner;
166 private final IMdsalApiManager mdsalManager;
167 private final ItmRpcService itmManager;
168 private final OdlInterfaceRpcService odlInterfaceRpcService;
169 private final IdManagerService idManager;
170 private final NaptManager naptManager;
171 private final NAPTSwitchSelector naptSwitchSelector;
172 private final IBgpManager bgpManager;
173 private final VpnRpcService vpnService;
174 private final FibRpcService fibService;
175 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
176 private final NaptEventHandler naptEventHandler;
177 private final NaptPacketInHandler naptPacketInHandler;
178 private final IFibManager fibManager;
179 private final IVpnManager vpnManager;
180 private final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer;
181 private final CentralizedSwitchScheduler centralizedSwitchScheduler;
182 private final NatMode natMode;
183 private final INeutronVpnManager nvpnManager;
184 private final IElanService elanManager;
185 private final JobCoordinator coordinator;
186 private final UpgradeState upgradeState;
187 private final IInterfaceManager interfaceManager;
188 private final int snatPuntTimeout;
191 public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
192 final ItmRpcService itmManager,
193 final OdlInterfaceRpcService odlInterfaceRpcService,
194 final IdManagerService idManager,
195 final NaptManager naptManager,
196 final NAPTSwitchSelector naptSwitchSelector,
197 final IBgpManager bgpManager,
198 final VpnRpcService vpnService,
199 final FibRpcService fibService,
200 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
201 final NaptEventHandler naptEventHandler,
202 final NaptPacketInHandler naptPacketInHandler,
203 final IFibManager fibManager,
204 final IVpnManager vpnManager,
205 final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer,
206 final INeutronVpnManager nvpnManager,
207 final CentralizedSwitchScheduler centralizedSwitchScheduler,
208 final NatserviceConfig config,
209 final IElanService elanManager,
210 final JobCoordinator coordinator,
211 final UpgradeState upgradeState,
212 final IInterfaceManager interfaceManager) {
213 super(Routers.class, ExternalRoutersListener.class);
214 this.dataBroker = dataBroker;
215 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
216 this.mdsalManager = mdsalManager;
217 this.itmManager = itmManager;
218 this.odlInterfaceRpcService = odlInterfaceRpcService;
219 this.idManager = idManager;
220 this.naptManager = naptManager;
221 this.naptSwitchSelector = naptSwitchSelector;
222 this.bgpManager = bgpManager;
223 this.vpnService = vpnService;
224 this.fibService = fibService;
225 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
226 this.naptEventHandler = naptEventHandler;
227 this.naptPacketInHandler = naptPacketInHandler;
228 this.fibManager = fibManager;
229 this.vpnManager = vpnManager;
230 this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
231 this.nvpnManager = nvpnManager;
232 this.elanManager = elanManager;
233 this.centralizedSwitchScheduler = centralizedSwitchScheduler;
234 this.coordinator = coordinator;
235 this.upgradeState = upgradeState;
236 this.interfaceManager = interfaceManager;
237 if (config != null) {
238 this.natMode = config.getNatMode();
239 this.snatPuntTimeout = config.getSnatPuntTimeout().intValue();
241 this.natMode = NatMode.Controller;
242 this.snatPuntTimeout = 0;
249 LOG.info("{} init", getClass().getSimpleName());
250 // This class handles ExternalRouters for Controller SNAT mode.
251 // For Conntrack SNAT mode, its handled in SnatExternalRoutersListener.java
252 if (natMode == NatMode.Controller) {
253 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
254 NatUtil.createGroupIdPool(idManager);
259 protected InstanceIdentifier<Routers> getWildCardPath() {
260 return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
264 // TODO Clean up the exception handling
265 @SuppressWarnings("checkstyle:IllegalCatch")
266 protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
267 // Populate the router-id-name container
268 String routerName = routers.getRouterName();
269 LOG.info("add : external router event for {}", routerName);
270 long routerId = NatUtil.getVpnId(dataBroker, routerName);
271 NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
272 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
274 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routers.key(),
275 () -> Collections.singletonList(
276 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
277 LOG.info("add : Installing NAT default route on all dpns part of router {}", routerName);
278 long bgpVpnId = NatConstants.INVALID_ID;
279 if (bgpVpnUuid != null) {
280 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
282 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, true, confTx);
283 // Allocate Primary Napt Switch for this router
284 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName);
285 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
286 if (!routers.isEnableSnat()) {
287 LOG.info("add : SNAT is disabled for external router {} ", routerName);
288 /* If SNAT is disabled on ext-router though L3_FIB_TABLE(21) -> PSNAT_TABLE(26) flow
289 * is required for DNAT. Hence writeFlowInvTx object submit is required.
293 handleEnableSnat(routers, routerId, primarySwitchId, bgpVpnId, confTx);
295 })), NatConstants.NAT_DJC_MAX_RETRIES);
296 } catch (Exception ex) {
297 LOG.error("add : Exception while Installing NAT flows on all dpns as part of router {}",
302 public void handleEnableSnat(Routers routers, long routerId, BigInteger primarySwitchId, long bgpVpnId,
303 TypedWriteTransaction<Configuration> confTx) {
304 String routerName = routers.getRouterName();
305 LOG.info("handleEnableSnat : Handling SNAT for router {}", routerName);
307 naptManager.initialiseExternalCounter(routers, routerId);
308 subnetRegisterMapping(routers, routerId);
310 LOG.debug("handleEnableSnat:About to create and install outbound miss entry in Primary Switch {} for router {}",
311 primarySwitchId, routerName);
313 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
314 routers.getNetworkId());
315 if (extNwProvType == null) {
316 LOG.error("handleEnableSnat : External Network Provider Type missing");
320 if (bgpVpnId != NatConstants.INVALID_ID) {
321 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, false, confTx,
324 // write metadata and punt
325 installOutboundMissEntry(routerName, routerId, primarySwitchId, confTx);
326 // Now install entries in SNAT tables to point to Primary for each router
327 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
328 for (BigInteger dpnId : switches) {
329 // Handle switches and NAPT switches separately
330 if (!dpnId.equals(primarySwitchId)) {
331 LOG.debug("handleEnableSnat : Handle Ordinary switch");
332 handleSwitches(dpnId, routerName, routerId, primarySwitchId);
334 LOG.debug("handleEnableSnat : Handle NAPT switch");
335 handlePrimaryNaptSwitch(dpnId, routerName, routerId, confTx);
340 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
341 if (externalIps.isEmpty()) {
342 LOG.error("handleEnableSnat : Internal External mapping not found for router {}", routerName);
345 for (String externalIpAddrPrefix : externalIps) {
346 LOG.debug("handleEnableSnat : Calling handleSnatReverseTraffic for primarySwitchId {}, "
347 + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
348 handleSnatReverseTraffic(confTx, primarySwitchId, routers, routerId, routerName, externalIpAddrPrefix
352 LOG.debug("handleEnableSnat : Exit");
355 private BigInteger getPrimaryNaptSwitch(String routerName) {
356 // Allocate Primary Napt Switch for this router
357 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
358 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
359 LOG.debug("handleEnableSnat : Primary NAPT switch with DPN ID {} is already elected for router {}",
360 primarySwitchId, routerName);
361 return primarySwitchId;
363 // Validating and creating VNI pool during when NAPT switch is selected.
364 // With Assumption this might be the first NAT service comes up.
365 NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager, idManager,
366 NatConstants.ODL_VNI_POOL_NAME);
367 // Allocated an id from VNI pool for the Router.
368 NatOverVxlanUtil.getRouterVni(idManager, routerName, NatConstants.INVALID_ID);
369 primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
370 LOG.debug("handleEnableSnat : Primary NAPT switch DPN ID {}", primarySwitchId);
372 return primarySwitchId;
375 protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId,
376 TypedWriteTransaction<Configuration> confTx) {
377 Long extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
378 if (extVpnId == NatConstants.INVALID_ID) {
379 LOG.error("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
382 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
383 if (externalIps.isEmpty()) {
384 LOG.error("installNaptPfibExternalOutputFlow - empty external Ips list for dpnId {} extVpnId {}",
388 for (String ip : externalIps) {
389 Uuid subnetId = getSubnetIdForFixedIp(ip);
390 if (subnetId != null) {
391 long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
392 if (subnetVpnId != NatConstants.INVALID_ID) {
393 extVpnId = subnetVpnId;
395 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
396 dpnId, extVpnId, subnetId);
397 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
398 mdsalManager.addFlow(confTx, postNaptFlowEntity);
404 private Uuid getSubnetIdForFixedIp(String ip) {
406 IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
407 Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
408 return NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
410 LOG.error("getSubnetIdForFixedIp : ip is null");
414 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
415 LOG.debug("subnetRegisterMapping : Fetching values from extRouters model");
416 List<Uuid> subnetList = routerEntry.getSubnetIds();
417 List<String> externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
419 int extIpCounter = externalIps.size();
420 LOG.debug("subnetRegisterMapping : counter values before looping counter {} and extIpCounter {}",
421 counter, extIpCounter);
422 for (Uuid subnet : subnetList) {
423 LOG.debug("subnetRegisterMapping : Looping internal subnets for subnet {}", subnet);
424 InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
425 .builder(Subnetmaps.class)
426 .child(Subnetmap.class, new SubnetmapKey(subnet))
428 Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
429 if (sn.isPresent()) {
431 Subnetmap subnetmapEntry = sn.get();
432 String subnetString = subnetmapEntry.getSubnetIp();
433 String[] subnetSplit = subnetString.split("/");
434 String subnetIp = subnetSplit[0];
436 InetAddress address = InetAddress.getByName(subnetIp);
437 if (address instanceof Inet6Address) {
438 LOG.debug("subnetRegisterMapping : Skipping ipv6 subnet {} for the router {} with ipv6 address "
439 + "{} ", subnet, routerEntry.getRouterName(), address);
442 } catch (UnknownHostException e) {
443 LOG.error("subnetRegisterMapping : Invalid ip address {}", subnetIp, e);
446 String subnetPrefix = "0";
447 if (subnetSplit.length == 2) {
448 subnetPrefix = subnetSplit[1];
450 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
451 LOG.debug("subnetRegisterMapping : subnetAddr is {} and subnetPrefix is {}",
452 subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
454 LOG.debug("subnetRegisterMapping : counter values counter {} and extIpCounter {}",
455 counter, extIpCounter);
456 if (extIpCounter != 0) {
457 if (counter < extIpCounter) {
458 String[] ipSplit = externalIps.get(counter).split("/");
459 String externalIp = ipSplit[0];
460 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
461 if (ipSplit.length == 2) {
462 extPrefix = ipSplit[1];
464 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
465 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
466 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
467 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
468 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
469 + "externalIp {}. prefix {}", subnetIp, subnetPrefix, externalIp, extPrefix);
471 counter = 0; //Reset the counter which runs on externalIps for round-robbin effect
472 LOG.debug("subnetRegisterMapping : Counter on externalIps got reset");
473 String[] ipSplit = externalIps.get(counter).split("/");
474 String externalIp = ipSplit[0];
475 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
476 if (ipSplit.length == 2) {
477 extPrefix = ipSplit[1];
479 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
480 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
481 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
482 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
483 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
484 + "externalIp {}. prefix {}", subnetIp, subnetPrefix,
485 externalIp, extPrefix);
489 LOG.debug("subnetRegisterMapping : Counter on externalIps incremented to {}", counter);
491 LOG.warn("subnetRegisterMapping : No internal subnets present in extRouters Model");
496 private void addOrDelDefFibRouteToSNAT(String routerName, long routerId, long bgpVpnId,
497 Uuid bgpVpnUuid, boolean create, TypedReadWriteTransaction<Configuration> confTx) {
498 //Check if BGP VPN exists. If exists then invoke the new method.
499 if (bgpVpnId != NatConstants.INVALID_ID) {
500 if (bgpVpnUuid != null) {
501 String bgpVpnName = bgpVpnUuid.getValue();
502 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
503 bgpVpnId, bgpVpnName);
504 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
505 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
506 confTx.put(getRoutersIdentifier(bgpVpnId), rtrs, CREATE_MISSING_PARENTS);
509 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
511 removeDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
516 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
517 addOrDelDefaultFibRouteForSNAT(routerName, routerId, create, confTx);
520 private void addOrDelDefaultFibRouteForSNAT(String routerName, long routerId, boolean create,
521 TypedReadWriteTransaction<Configuration> confTx) {
522 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
523 if (switches.isEmpty()) {
524 LOG.info("addOrDelDefaultFibRouteForSNAT : No switches found for router {}", routerName);
527 if (routerId == NatConstants.INVALID_ID) {
528 LOG.error("addOrDelDefaultFibRouteForSNAT : Could not retrieve router Id for {} to program "
529 + "default NAT route in FIB", routerName);
532 for (BigInteger dpnId : switches) {
534 LOG.debug("addOrDelDefaultFibRouteForSNAT : installing default NAT route for router {} in dpn {} "
535 + "for the internal vpn-id {}", routerId, dpnId, routerId);
536 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
538 LOG.debug("addOrDelDefaultFibRouteForSNAT : removing default NAT route for router {} in dpn {} "
539 + "for the internal vpn-id {}", routerId, dpnId, routerId);
540 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
545 private void addDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
546 long bgpVpnId, TypedWriteTransaction<Configuration> confTx) {
547 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
548 if (dpnIds.isEmpty()) {
549 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
550 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
553 for (BigInteger dpnId : dpnIds) {
554 if (bgpVpnId != NatConstants.INVALID_ID) {
555 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
556 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
557 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
559 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
560 + "in dpn {} for the internal vpn", routerId, dpnId);
561 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
566 private void removeDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
567 long bgpVpnId, TypedReadWriteTransaction<Configuration> confTx) {
568 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
569 if (dpnIds.isEmpty()) {
570 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
571 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
574 for (BigInteger dpnId : dpnIds) {
575 if (bgpVpnId != NatConstants.INVALID_ID) {
576 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
577 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
578 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
580 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
581 + "in dpn {} for the internal vpn", routerId, dpnId);
582 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
587 // TODO Clean up the exception handling
588 @SuppressWarnings("checkstyle:IllegalCatch")
589 public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
590 InstanceIdentifier<T> path) {
591 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
594 return tx.read(datastoreType, path).get();
595 } catch (Exception e) {
596 throw new RuntimeException(e);
600 protected void installOutboundMissEntry(String routerName, long routerId, BigInteger primarySwitchId,
601 TypedWriteTransaction<Configuration> confTx) {
602 LOG.debug("installOutboundMissEntry : Router ID from getVpnId {}", routerId);
603 if (routerId != NatConstants.INVALID_ID) {
604 LOG.debug("installOutboundMissEntry : Creating miss entry on primary {}, for router {}",
605 primarySwitchId, routerId);
606 createOutboundTblEntry(primarySwitchId, routerId, confTx);
608 LOG.error("installOutboundMissEntry : Unable to fetch Router Id for RouterName {}, failed to "
609 + "createAndInstallMissEntry", routerName);
613 public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID, int protocol) {
614 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
615 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + protocol;
618 private String getFlowRefNaptPreFib(BigInteger dpnId, short tableId, long vpnId) {
619 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
620 .FLOWID_SEPARATOR + vpnId;
623 public BigInteger getCookieOutboundFlow(long routerId) {
624 return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
625 BigInteger.valueOf(routerId));
628 private ActionLearn getLearnActionForPunt(int protocol, int hardTimeout, BigInteger cookie) {
631 int l4portFieldLen = NxmOfFieldType.NXM_OF_TCP_SRC.getFlowModHeaderLenInt();
633 if (protocol == NwConstants.IP_PROT_TCP) {
634 l4SrcPortField = NxmOfFieldType.NXM_OF_TCP_SRC.getType();
635 l4DstPortField = NxmOfFieldType.NXM_OF_TCP_DST.getType();
637 l4SrcPortField = NxmOfFieldType.NXM_OF_UDP_SRC.getType();
638 l4DstPortField = NxmOfFieldType.NXM_OF_UDP_DST.getType();
640 List<ActionLearn.FlowMod> flowMods = Arrays.asList(
641 new MatchFromValue(NwConstants.ETHTYPE_IPV4, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
642 NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
643 new MatchFromValue(protocol, NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
644 NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
645 new MatchFromField(NxmOfFieldType.NXM_OF_IP_SRC.getType(), NxmOfFieldType.NXM_OF_IP_SRC.getType(),
646 NxmOfFieldType.NXM_OF_IP_SRC.getFlowModHeaderLenInt()),
647 new MatchFromField(NxmOfFieldType.NXM_OF_IP_DST.getType(), NxmOfFieldType.NXM_OF_IP_DST.getType(),
648 NxmOfFieldType.NXM_OF_IP_DST.getFlowModHeaderLenInt()),
649 new MatchFromField(l4SrcPortField, l4SrcPortField, l4portFieldLen),
650 new MatchFromField(l4DstPortField, l4DstPortField, l4portFieldLen),
651 new MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
652 MetaDataUtil.METADATA_VPN_ID_OFFSET,
653 NxmOfFieldType.OXM_OF_METADATA.getType(), MetaDataUtil.METADATA_VPN_ID_OFFSET,
654 MetaDataUtil.METADATA_VPN_ID_BITLEN));
656 return new ActionLearn(0, hardTimeout, 7, cookie, 0,
657 NwConstants.OUTBOUND_NAPT_TABLE, 0, 0, flowMods);
660 private FlowEntity buildIcmpDropFlow(BigInteger dpnId, long routerId, long vpnId) {
661 List<MatchInfo> matches = new ArrayList<>();
662 matches.add(MatchEthernetType.IPV4);
663 matches.add(MatchIpProtocol.ICMP);
664 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
666 List<ActionInfo> actionInfos = new ArrayList<>();
667 actionInfos.add(new ActionDrop());
669 List<InstructionInfo> instructions = new ArrayList<>();
670 instructions.add(new InstructionApplyActions(actionInfos));
672 String flowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
673 NwConstants.IP_PROT_ICMP);
674 FlowEntity flow = MDSALUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
675 NwConstants.TABLE_MISS_PRIORITY, "icmp drop flow", 0, 0,
676 NwConstants.COOKIE_OUTBOUND_NAPT_TABLE, matches, instructions);
680 protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId, int protocol) {
681 LOG.debug("buildOutboundFlowEntity : called for dpId {} and routerId{}", dpId, routerId);
682 BigInteger cookie = getCookieOutboundFlow(routerId);
683 List<MatchInfo> matches = new ArrayList<>();
684 matches.add(MatchEthernetType.IPV4);
685 matches.add(new MatchIpProtocol((short)protocol));
686 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
688 List<InstructionInfo> instructions = new ArrayList<>();
689 List<ActionInfo> actionsInfos = new ArrayList<>();
690 actionsInfos.add(new ActionPuntToController());
691 if (snatPuntTimeout != 0) {
692 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
694 instructions.add(new InstructionApplyActions(actionsInfos));
696 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
697 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
699 cookie, matches, instructions);
700 LOG.debug("installOutboundMissEntry : returning flowEntity {}", flowEntity);
704 public void createOutboundTblEntry(BigInteger dpnId, long routerId, TypedWriteTransaction<Configuration> confTx) {
705 LOG.debug("createOutboundTblEntry : called for dpId {} and routerId {}", dpnId, routerId);
706 FlowEntity tcpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_TCP);
707 LOG.debug("createOutboundTblEntry : Installing tcp flow {}", tcpflowEntity);
708 mdsalManager.addFlow(confTx, tcpflowEntity);
710 FlowEntity udpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_UDP);
711 LOG.debug("createOutboundTblEntry : Installing udp flow {}", udpflowEntity);
712 mdsalManager.addFlow(confTx, udpflowEntity);
714 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, routerId);
715 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
716 mdsalManager.addFlow(confTx, icmpDropFlow);
719 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
720 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
721 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
723 Future<RpcResult<GetTunnelInterfaceNameOutput>> result =
724 itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
725 .setSourceDpid(srcDpId)
726 .setDestinationDpid(dstDpId)
727 .setTunnelType(tunType)
729 rpcResult = result.get();
730 if (!rpcResult.isSuccessful()) {
731 tunType = TunnelTypeGre.class;
732 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
733 .setSourceDpid(srcDpId)
734 .setDestinationDpid(dstDpId)
735 .setTunnelType(tunType)
737 rpcResult = result.get();
738 if (!rpcResult.isSuccessful()) {
739 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
740 rpcResult.getErrors());
742 return rpcResult.getResult().getInterfaceName();
744 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
745 rpcResult.getErrors());
747 return rpcResult.getResult().getInterfaceName();
749 } catch (InterruptedException | ExecutionException | NullPointerException e) {
750 LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
751 + "between {} and {}", srcDpId, dstDpId, e);
757 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName, long routerId,
758 TypedWriteTransaction<Configuration> confTx) {
760 LOG.debug("installSnatMissEntry : called for for the primary NAPT switch dpnId {} ", dpnId);
761 // Install miss entry pointing to group
762 FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName, routerId);
763 mdsalManager.addFlow(confTx, flowEntity);
766 protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo,
767 String routerName, long routerId) {
768 LOG.debug("installSnatMissEntry : called for dpnId {} with primaryBucket {} ",
769 dpnId, bucketInfo.get(0));
770 // Install the select group
771 long groupId = createGroupId(getGroupIdKey(routerName));
772 GroupEntity groupEntity =
773 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
774 LOG.debug("installSnatMissEntry : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
775 mdsalManager.syncInstallGroup(groupEntity);
776 // Install miss entry pointing to group
777 FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, routerId, groupId);
778 if (flowEntity == null) {
779 LOG.error("installSnatMissEntry : Flow entity received as NULL. "
780 + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
781 + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
784 mdsalManager.installFlow(flowEntity);
787 long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo) {
788 long groupId = createGroupId(getGroupIdKey(routerName));
789 GroupEntity groupEntity =
790 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
791 LOG.debug("installGroup : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
792 mdsalManager.syncInstallGroup(groupEntity);
796 private FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long routerId, long groupId) {
797 LOG.debug("buildSnatFlowEntity : called for dpId {}, routerName {} and groupId {}",
798 dpId, routerName, groupId);
799 List<MatchInfo> matches = new ArrayList<>();
800 matches.add(MatchEthernetType.IPV4);
801 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
803 List<ActionInfo> actionsInfo = new ArrayList<>();
804 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
806 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
807 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
808 actionsInfo.add(new ActionGroup(groupId));
809 List<InstructionInfo> instructions = new ArrayList<>();
810 instructions.add(new InstructionApplyActions(actionsInfo));
811 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
812 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
813 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
814 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
816 LOG.debug("buildSnatFlowEntity : Returning SNAT Flow Entity {}", flowEntity);
820 private FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName, long routerId) {
822 LOG.debug("buildSnatFlowEntityForPrmrySwtch : called for primary NAPT switch dpId {}, routerName {}", dpId,
824 List<MatchInfo> matches = new ArrayList<>();
825 matches.add(MatchEthernetType.IPV4);
826 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
828 List<InstructionInfo> instructions = new ArrayList<>();
829 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
831 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
832 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
833 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
834 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
836 LOG.debug("buildSnatFlowEntityForPrmrySwtch : Returning SNAT Flow Entity {}", flowEntity);
840 // TODO : Replace this with ITM Rpc once its available with full functionality
841 protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName, long routerId,
842 TypedWriteTransaction<Configuration> confTx) {
844 LOG.debug("installTerminatingServiceTblEntry : for switch {}, routerName {}",
846 FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName, routerId);
847 if (flowEntity == null) {
848 LOG.error("installTerminatingServiceTblEntry : Flow entity received as NULL. "
849 + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
850 + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
854 mdsalManager.addFlow(confTx, flowEntity);
858 private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName, long routerId) {
859 List<MatchInfo> matches = new ArrayList<>();
860 matches.add(MatchEthernetType.IPV4);
861 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
863 matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
864 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
865 List<InstructionInfo> instructions = new ArrayList<>();
866 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
867 MetaDataUtil.METADATA_MASK_VRFID));
868 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
869 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
870 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
875 public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
876 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
877 .FLOWID_SEPARATOR + routerID;
880 public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
881 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
882 .FLOWID_SEPARATOR + routerID;
885 private String getGroupIdKey(String routerName) {
886 return "snatmiss." + routerName;
889 protected long createGroupId(String groupIdKey) {
890 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
891 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
894 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
895 RpcResult<AllocateIdOutput> rpcResult = result.get();
896 return rpcResult.getResult().getIdValue();
897 } catch (NullPointerException | InterruptedException | ExecutionException e) {
898 LOG.error("Exception While allocating id for group: {}", groupIdKey, e);
903 protected void handleSwitches(BigInteger dpnId, String routerName, long routerId, BigInteger primarySwitchId) {
904 LOG.debug("handleSwitches : Installing SNAT miss entry in switch {}", dpnId);
905 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
906 String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
907 List<BucketInfo> listBucketInfo = new ArrayList<>();
909 if (ifNamePrimary != null) {
910 LOG.debug("handleSwitches : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
911 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
912 interfaceManager, ifNamePrimary, routerId, true);
913 if (listActionInfoPrimary.isEmpty()) {
914 LOG.error("handleSwitches : Unable to retrieve output actions on Non-NAPT switch {} for router {}"
915 + " towards Napt-switch {} via tunnel interface {}", dpnId, routerName, primarySwitchId,
919 LOG.error("handleSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} from "
920 + "Non-Napt switch {} for router {}", primarySwitchId, dpnId, routerName);
922 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
924 listBucketInfo.add(0, bucketPrimary);
925 installSnatMissEntry(dpnId, listBucketInfo, routerName, routerId);
928 List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
929 BigInteger primarySwitchId, String routerName, long routerId) {
930 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
931 String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
932 List<BucketInfo> listBucketInfo = new ArrayList<>();
934 if (ifNamePrimary != null) {
935 LOG.debug("getBucketInfoForNonNaptSwitches : On Non- Napt switch , Primary Tunnel interface is {}",
937 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
938 interfaceManager, ifNamePrimary, routerId, true);
939 if (listActionInfoPrimary.isEmpty()) {
940 LOG.error("getBucketInfoForNonNaptSwitches : Unable to retrieve output actions on Non-NAPT switch {} "
941 + "for router {} towards Napt-switch {} via tunnel interface {}",
942 nonNaptSwitchId, routerName, primarySwitchId, ifNamePrimary);
945 LOG.error("getBucketInfoForNonNaptSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} "
946 + "from Non-Napt switch {} for router {}", primarySwitchId, nonNaptSwitchId, routerName);
948 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
950 listBucketInfo.add(0, bucketPrimary);
951 return listBucketInfo;
954 protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName, long routerId,
955 TypedWriteTransaction<Configuration> confTx) {
958 * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
961 LOG.debug("handlePrimaryNaptSwitch : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
964 List<BucketInfo> listBucketInfo = new ArrayList<>();
965 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
966 listActionInfoPrimary.add(new ActionNxResubmit(NatConstants.TERMINATING_SERVICE_TABLE));
967 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
968 listBucketInfo.add(0, bucketPrimary);
971 installSnatMissEntryForPrimrySwch(dpnId, routerName, routerId, confTx);
972 installTerminatingServiceTblEntry(dpnId, routerName, routerId, confTx);
973 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
974 installNaptPfibEntry(dpnId, routerId, confTx);
975 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
976 if (networkId != null) {
977 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
978 if (vpnUuid != null) {
979 Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
980 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
981 installNaptPfibEntriesForExternalSubnets(routerName, dpnId, null);
982 //Install the NAPT PFIB TABLE which forwards outgoing packet to FIB Table matching on the VPN ID.
983 if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
984 installNaptPfibEntry(dpnId, vpnId, null);
986 return Collections.emptyList();
989 LOG.warn("handlePrimaryNaptSwitch : External Vpn ID missing for Ext-Network : {}", networkId);
992 LOG.warn("handlePrimaryNaptSwitch : External Network not available for router : {}", routerName);
996 List<BucketInfo> getBucketInfoForPrimaryNaptSwitch() {
997 List<BucketInfo> listBucketInfo = new ArrayList<>();
998 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
999 listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
1000 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
1001 listBucketInfo.add(0, bucketPrimary);
1002 return listBucketInfo;
1005 public void installNaptPfibEntry(BigInteger dpnId, long segmentId, TypedWriteTransaction<Configuration> confTx) {
1006 LOG.debug("installNaptPfibEntry : called for dpnId {} and segmentId {} ", dpnId, segmentId);
1007 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
1008 if (confTx != null) {
1009 mdsalManager.addFlow(confTx, naptPfibFlowEntity);
1011 mdsalManager.installFlow(naptPfibFlowEntity);
1015 public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
1017 LOG.debug("buildNaptPfibFlowEntity : called for dpId {}, segmentId {}", dpId, segmentId);
1018 List<MatchInfo> matches = new ArrayList<>();
1019 matches.add(MatchEthernetType.IPV4);
1020 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
1022 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
1023 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
1024 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
1025 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
1026 instructionInfo.add(new InstructionApplyActions(listActionInfo));
1028 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
1029 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
1030 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
1031 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
1032 LOG.debug("buildNaptPfibFlowEntity : Returning NaptPFib Flow Entity {}", flowEntity);
1036 public void handleSnatReverseTraffic(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, Routers router,
1037 long routerId, String routerName, String externalIp) {
1038 LOG.debug("handleSnatReverseTraffic : entry for DPN ID {}, routerId {}, externalIp: {}",
1039 dpnId, routerId, externalIp);
1040 Uuid networkId = router.getNetworkId();
1041 if (networkId == null) {
1042 LOG.error("handleSnatReverseTraffic : networkId is null for the router ID {}", routerId);
1045 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1046 if (vpnName == null) {
1047 LOG.error("handleSnatReverseTraffic : No VPN associated with ext nw {} to handle add external ip "
1048 + "configuration {} in router {}", networkId, externalIp, routerId);
1051 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1052 externalIp, networkId, router, confTx);
1053 LOG.debug("handleSnatReverseTraffic : exit for DPN ID {}, routerId {}, externalIp : {}",
1054 dpnId, routerId, externalIp);
1057 public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
1058 final long routerId, final String routerName, final String externalIp,
1059 final Uuid extNetworkId, final Routers router,
1060 final TypedWriteTransaction<Configuration> confTx) {
1061 LOG.debug("advToBgpAndInstallFibAndTsFlows : entry for DPN ID {}, tableId {}, vpnname {} "
1062 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
1063 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
1064 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1065 if (rd == null || rd.isEmpty()) {
1066 LOG.error("advToBgpAndInstallFibAndTsFlows : Unable to get RD for VPN Name {}", vpnName);
1069 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
1070 if (extNwProvType == null) {
1071 LOG.error("advToBgpAndInstallFibAndTsFlows : External Network Provider Type missing");
1074 if (extNwProvType == ProviderTypes.VXLAN) {
1075 evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
1076 nextHopIp, routerId, routerName, confTx);
1079 //Generate VPN label for the external IP
1080 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
1081 .setIpPrefix(externalIp).build();
1082 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
1084 //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
1085 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
1086 if (result.isSuccessful()) {
1087 LOG.debug("advToBgpAndInstallFibAndTsFlows : inside apply with result success");
1088 GenerateVpnLabelOutput output = result.getResult();
1089 final long label = output.getLabel();
1091 int externalIpInDsFlag = 0;
1092 //Get IPMaps from the DB for the router ID
1093 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
1094 if (dbIpMaps != null) {
1095 for (IpMap dbIpMap : dbIpMaps) {
1096 String dbExternalIp = dbIpMap.getExternalIp();
1097 //Select the IPMap, whose external IP is the IP for which FIB is installed
1098 if (dbExternalIp.contains(externalIp)) {
1099 String dbInternalIp = dbIpMap.getInternalIp();
1100 IpMapKey dbIpMapKey = dbIpMap.key();
1101 LOG.debug("advToBgpAndInstallFibAndTsFlows : Setting label {} for internalIp {} "
1102 + "and externalIp {}", label, dbInternalIp, externalIp);
1103 IpMap newIpm = new IpMapBuilder().withKey(dbIpMapKey).setInternalIp(dbInternalIp)
1104 .setExternalIp(dbExternalIp).setLabel(label).build();
1105 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1106 naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
1107 externalIpInDsFlag++;
1110 if (externalIpInDsFlag <= 0) {
1111 LOG.debug("advToBgpAndInstallFibAndTsFlows : External Ip {} not found in DS, "
1112 + "Failed to update label {} for routerId {} in DS",
1113 externalIp, label, routerId);
1114 String errMsg = String.format("Failed to update label %s due to external Ip %s not"
1115 + " found in DS for router %s", label, externalIp, routerId);
1116 return Futures.immediateFailedFuture(new Exception(errMsg));
1119 LOG.error("advToBgpAndInstallFibAndTsFlows : Failed to write label {} for externalIp {} for"
1120 + " routerId {} in DS", label, externalIp, routerId);
1124 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1125 l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
1127 Routers extRouter = router != null ? router :
1128 NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1129 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp,
1131 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, externalSubnetId,
1132 externalIp, nextHopIp, extRouter.getNetworkId().getValue(), null, label, l3vni,
1133 RouteOrigin.STATIC, dpnId);
1135 //Install custom FIB routes
1136 List<Instruction> tunnelTableCustomInstructions = new ArrayList<>();
1137 tunnelTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
1138 makeTunnelTableEntry(dpnId, label, l3vni, tunnelTableCustomInstructions, confTx,
1140 makeLFibTableEntry(dpnId, label, tableId, confTx);
1142 //Install custom FIB routes - FIB table.
1143 List<Instruction> fibTableCustomInstructions = createFibTableCustomInstructions(tableId,
1144 routerName, externalIp);
1145 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1146 //Install the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
1147 NatUtil.makePreDnatToSnatTableEntry(mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, confTx);
1149 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1150 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
1152 String externalVpn = vpnName;
1153 if (externalSubnet.isPresent()) {
1154 externalVpn = externalSubnetId.getValue();
1156 CreateFibEntryInput input = new CreateFibEntryInputBuilder()
1157 .setVpnName(externalVpn)
1158 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
1159 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
1160 .setInstruction(fibTableCustomInstructions).build();
1161 return fibService.createFibEntry(input);
1163 LOG.error("advToBgpAndInstallFibAndTsFlows : inside apply with result failed");
1164 String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
1165 externalIp, vpnName, result.getErrors());
1166 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1168 }, MoreExecutors.directExecutor());
1170 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
1173 public void onFailure(@Nonnull Throwable error) {
1174 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in generate label or fib install process", error);
1178 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
1179 if (result.isSuccessful()) {
1180 LOG.info("advToBgpAndInstallFibAndTsFlows : Successfully installed custom FIB routes for prefix {}",
1183 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in rpc call to create custom Fib entries "
1184 + "for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
1187 }, MoreExecutors.directExecutor());
1190 private List<Instruction> createFibTableCustomInstructions(short tableId, String routerName,
1191 String externalIp) {
1192 List<Instruction> fibTableCustomInstructions = new ArrayList<>();
1193 Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1194 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
1195 externalIp, router);
1196 int instructionIndex = 0;
1197 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
1198 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
1199 fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
1200 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
1204 fibTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(instructionIndex));
1205 return fibTableCustomInstructions;
1208 private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId,
1209 TypedWriteTransaction<Configuration> confTx) {
1210 List<MatchInfo> matches = new ArrayList<>();
1211 matches.add(MatchEthernetType.MPLS_UNICAST);
1212 matches.add(new MatchMplsLabel(serviceId));
1214 List<Instruction> instructions = new ArrayList<>();
1215 List<ActionInfo> actionsInfos = new ArrayList<>();
1216 //NAT is required for IPv4 only. Hence always etherType will be IPv4
1217 actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
1218 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
1219 instructions.add(writeInstruction);
1220 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
1222 // Install the flow entry in L3_LFIB_TABLE
1223 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1225 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1227 COOKIE_VM_LFIB_TABLE, matches, instructions);
1229 mdsalManager.addFlow(confTx, dpId, flowEntity);
1231 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
1234 private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, long l3Vni,
1235 List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx,
1236 ProviderTypes extNwProvType) {
1238 List<MatchInfo> mkMatches = new ArrayList<>();
1240 LOG.debug("makeTunnelTableEntry : DpnId = {} and serviceId = {} and actions = {}",
1241 dpnId, serviceId, customInstructions);
1243 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1244 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
1246 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
1249 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1250 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5,
1251 String.format("%s:%d", "TST Flow Entry ", serviceId),
1252 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1254 mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
1257 protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1258 return InstanceIdentifier.builder(RouterIdName.class).child(RouterIds.class,
1259 new RouterIdsKey(routerId)).build();
1262 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1263 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
1264 .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
1268 protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1269 String routerName = original.getRouterName();
1270 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1271 if (routerId == NatConstants.INVALID_ID) {
1272 LOG.error("update : external router event - Invalid routerId for routerName {}", routerName);
1275 // Check if its update on SNAT flag
1276 boolean originalSNATEnabled = original.isEnableSnat();
1277 boolean updatedSNATEnabled = update.isEnableSnat();
1278 LOG.debug("update :called with originalFlag and updatedFlag for SNAT enabled "
1279 + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
1280 /* Get Primary Napt Switch for existing router from "router-to-napt-switch" DS.
1281 * if dpnId value is null or zero then go for electing new Napt switch for existing router.
1283 long bgpVpnId = NatConstants.INVALID_ID;
1284 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1285 if (bgpVpnUuid != null) {
1286 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1288 BigInteger dpnId = getPrimaryNaptSwitch(routerName);
1289 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1290 // Router has no interface attached
1293 final long finalBgpVpnId = bgpVpnId;
1294 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + update.key(), () -> {
1295 List<ListenableFuture<Void>> futures = new ArrayList<>();
1296 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, writeFlowInvTx -> {
1297 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, removeFlowInvTx -> {
1298 Uuid networkId = original.getNetworkId();
1299 if (originalSNATEnabled != updatedSNATEnabled) {
1300 if (originalSNATEnabled) {
1301 //SNAT disabled for the router
1302 Uuid networkUuid = original.getNetworkId();
1303 LOG.info("update : SNAT disabled for Router {}", routerName);
1304 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1305 handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId, routerId,
1308 LOG.info("update : SNAT enabled for Router {}", original.getRouterName());
1309 handleEnableSnat(original, routerId, dpnId, finalBgpVpnId, removeFlowInvTx);
1312 if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1313 NatUtil.installRouterGwFlows(txRunner, vpnManager, original, dpnId, NwConstants.DEL_FLOW);
1314 NatUtil.installRouterGwFlows(txRunner, vpnManager, update, dpnId, NwConstants.ADD_FLOW);
1317 //Check if the Update is on External IPs
1318 LOG.debug("update : Checking if this is update on External IPs");
1319 List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
1320 List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
1322 //Check if the External IPs are added during the update.
1323 Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
1324 addedExternalIps.removeAll(originalExternalIps);
1325 if (addedExternalIps.size() != 0) {
1326 LOG.debug("update : Start processing of the External IPs addition during the update "
1328 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
1329 update.getExtGwMacAddress(), dpnId,
1330 update.getNetworkId());
1332 for (String addedExternalIp : addedExternalIps) {
1334 1) Do nothing in the IntExtIp model.
1335 2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1337 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1338 String externalIp = externalIpParts[0];
1339 String externalIpPrefix = externalIpParts[1];
1340 String externalpStr = externalIp + "/" + externalIpPrefix;
1341 LOG.debug("update : Initialise the count mapping of the external IP {} for the "
1342 + "router ID {} in the ExternalIpsCounter model.",
1343 externalpStr, routerId);
1344 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1347 "update : End processing of the External IPs addition during the update operation");
1350 //Check if the External IPs are removed during the update.
1351 Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
1352 removedExternalIps.removeAll(updatedExternalIps);
1353 if (removedExternalIps.size() > 0) {
1354 LOG.debug("update : Start processing of the External IPs removal during the update "
1356 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
1357 removedExternalIps, original.getExtGwMacAddress(),
1360 for (String removedExternalIp : removedExternalIps) {
1362 1) Remove the mappings in the IntExt IP model which has external IP.
1363 2) Remove the external IP in the ExternalCounter model.
1364 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the
1365 least loaded external IP.
1366 Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1367 4) Increase the count of the allocated external IP by one.
1368 5) Advertise to the BGP if external IP is allocated for the first time for the router
1369 i.e. the route for the external IP is absent.
1370 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for
1371 the removed external IPs and also from the model.
1372 7) Advertise to the BGP for removing the route for the removed external IPs.
1375 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1376 String externalIp = externalIpParts[0];
1377 String externalIpPrefix = externalIpParts[1];
1378 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1380 LOG.debug("update : Clear the routes from the BGP and remove the FIB and TS "
1381 + "entries for removed external IP {}", externalIpAddrStr);
1382 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1383 String vpnName = "";
1384 if (vpnUuId != null) {
1385 vpnName = vpnUuId.getValue();
1387 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName, networkId,
1388 update.getExtGwMacAddress(), removeFlowInvTx);
1390 LOG.debug("update : Remove the mappings in the IntExtIP model which has external IP.");
1391 //Get the internal IPs which are associated to the removed external IPs
1392 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1393 List<String> removedInternalIps = new ArrayList<>();
1394 for (IpMap ipMap : ipMaps) {
1395 if (ipMap.getExternalIp().equals(externalIpAddrStr)) {
1396 removedInternalIps.add(ipMap.getInternalIp());
1400 LOG.debug("update : Remove the mappings of the internal IPs from the IntExtIP model.");
1401 for (String removedInternalIp : removedInternalIps) {
1402 LOG.debug("update : Remove the IP mapping of the internal IP {} for the "
1403 + "router ID {} from the IntExtIP model",
1404 removedInternalIp, routerId);
1405 naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1408 LOG.debug("update : Remove the count mapping of the external IP {} for the "
1409 + "router ID {} from the ExternalIpsCounter model.",
1410 externalIpAddrStr, routerId);
1411 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1413 LOG.debug("update : Allocate the least loaded external IPs to the subnets "
1414 + "whose external IPs were removed.");
1415 for (String removedInternalIp : removedInternalIps) {
1416 allocateExternalIp(dpnId, update, routerId, routerName, networkId,
1417 removedInternalIp, writeFlowInvTx);
1420 LOG.debug("update : Remove the NAPT translation entries from "
1421 + "Inbound and Outbound NAPT tables for the removed external IPs.");
1422 //Get the internalIP and internal Port which were associated to the removed external IP.
1423 List<Integer> externalPorts = new ArrayList<>();
1424 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1425 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier
1426 .builder(IntextIpPortMap.class)
1427 .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1428 Optional<IpPortMapping> ipPortMapping =
1429 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1430 if (ipPortMapping.isPresent()) {
1431 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get()
1432 .getIntextIpProtocolType();
1433 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1434 ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1435 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1436 for (IpPortMap ipPortMap : ipPortMaps) {
1437 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1438 if (ipPortExternal.getIpAddress().equals(externalIp)) {
1439 externalPorts.add(ipPortExternal.getPortNum());
1440 List<String> removedInternalIpPorts =
1441 protoTypesIntIpPortsMap.get(protoType);
1442 if (removedInternalIpPorts != null) {
1443 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1444 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1446 removedInternalIpPorts = new ArrayList<>();
1447 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1448 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1455 //Remove the IP port map from the intext-ip-port-map model, which were containing
1456 // the removed external IP.
1457 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts =
1458 protoTypesIntIpPortsMap.entrySet();
1459 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1460 for (Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts) {
1461 ProtocolTypes protocolType = (ProtocolTypes) protoTypesIntIpPort.getKey();
1462 List<String> removedInternalIpPorts = (List<String>) protoTypesIntIpPort.getValue();
1463 for (String removedInternalIpPort : removedInternalIpPorts) {
1464 // Remove the IP port map from the intext-ip-port-map model,
1465 // which were containing the removed external IP
1466 naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort,
1468 //Remove the IP port incomint packer map.
1469 naptPacketInHandler.removeIncomingPacketMap(
1470 routerId + NatConstants.COLON_SEPARATOR + removedInternalIpPort);
1471 String[] removedInternalIpPortParts = removedInternalIpPort
1472 .split(NatConstants.COLON_SEPARATOR);
1473 if (removedInternalIpPortParts.length == 2) {
1474 String removedInternalIp = removedInternalIpPortParts[0];
1475 String removedInternalPort = removedInternalIpPortParts[1];
1476 List<String> removedInternalPortsList =
1477 internalIpPortMap.get(removedInternalPort);
1478 if (removedInternalPortsList != null) {
1479 removedInternalPortsList.add(removedInternalPort);
1480 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1482 removedInternalPortsList = new ArrayList<>();
1483 removedInternalPortsList.add(removedInternalPort);
1484 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1490 // Delete the entry from SnatIntIpPortMap DS
1491 Set<String> internalIps = internalIpPortMap.keySet();
1492 for (String internalIp : internalIps) {
1493 LOG.debug("update : Removing IpPort having the internal IP {} from the "
1494 + "model SnatIntIpPortMap", internalIp);
1495 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1498 naptManager.removeNaptPortPool(externalIp);
1500 LOG.debug("update : Remove the NAPT translation entries from Inbound NAPT tables for "
1501 + "the removed external IP {}", externalIp);
1502 for (Integer externalPort : externalPorts) {
1503 //Remove the NAPT translation entries from Inbound NAPT table
1504 naptEventHandler.removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1505 routerId, externalIp, externalPort);
1508 Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
1509 for (Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
1510 String internalIp = internalIpPort.getKey();
1511 LOG.debug("update : Remove the NAPT translation entries from Outbound NAPT tables "
1512 + "for the removed internal IP {}", internalIp);
1513 List<String> internalPorts = internalIpPort.getValue();
1514 for (String internalPort : internalPorts) {
1515 //Remove the NAPT translation entries from Outbound NAPT table
1516 naptPacketInHandler.removeIncomingPacketMap(
1517 routerId + NatConstants.COLON_SEPARATOR + internalIp
1518 + NatConstants.COLON_SEPARATOR + internalPort);
1519 naptEventHandler.removeNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1520 routerId, internalIp, Integer.parseInt(internalPort));
1525 "update : End processing of the External IPs removal during the update operation");
1528 //Check if its Update on subnets
1529 LOG.debug("update : Checking if this is update on subnets");
1530 List<Uuid> originalSubnetIds = original.getSubnetIds();
1531 List<Uuid> updatedSubnetIds = update.getSubnetIds();
1532 Set<Uuid> addedSubnetIds = new HashSet<>(updatedSubnetIds);
1533 addedSubnetIds.removeAll(originalSubnetIds);
1535 //Check if the Subnet IDs are added during the update.
1536 if (addedSubnetIds.size() != 0) {
1538 "update : Start processing of the Subnet IDs addition during the update operation");
1539 for (Uuid addedSubnetId : addedSubnetIds) {
1541 1) Select the least loaded external IP for the subnet and store the mapping of the
1542 subnet IP and the external IP in the IntExtIp model.
1543 2) Increase the count of the selected external IP by one.
1544 3) Advertise to the BGP if external IP is allocated for the first time for the
1545 router i.e. the route for the external IP is absent.
1547 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1548 if (subnetIp != null) {
1549 allocateExternalIp(dpnId, update, routerId, routerName, networkId, subnetIp,
1553 LOG.debug("update : End processing of the Subnet IDs addition during the update operation");
1556 //Check if the Subnet IDs are removed during the update.
1557 Set<Uuid> removedSubnetIds = new HashSet<>(originalSubnetIds);
1558 removedSubnetIds.removeAll(updatedSubnetIds);
1559 if (removedSubnetIds.size() != 0) {
1561 "update : Start processing of the Subnet IDs removal during the update operation");
1562 for (Uuid removedSubnetId : removedSubnetIds) {
1563 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1564 if (subnetAddr != null) {
1566 1) Remove the subnet IP and the external IP in the IntExtIp map
1567 2) Decrease the count of the coresponding external IP by one.
1568 3) Advertise to the BGP for removing the routes of the corresponding external
1569 IP if its not allocated to any other internal IP.
1572 String externalIp = naptManager.getExternalIpAllocatedForSubnet(routerId,
1573 subnetAddr[0] + "/" + subnetAddr[1]);
1574 if (externalIp == null) {
1575 LOG.error("update : No mapping found for router ID {} and internal IP {}",
1576 routerId, subnetAddr[0]);
1580 naptManager.updateCounter(routerId, externalIp, false);
1581 // Traverse entire model of external-ip counter whether external ip is not
1582 // used by any other internal ip in any router
1583 if (!isExternalIpAllocated(externalIp)) {
1584 LOG.debug("update : external ip is not allocated to any other "
1585 + "internal IP so proceeding to remove routes");
1586 clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId,
1587 Collections.singleton(externalIp), null, update.getExtGwMacAddress(),
1589 LOG.debug("update : Successfully removed fib entries in switch {} for "
1590 + "router {} with networkId {} and externalIp {}",
1591 dpnId, routerId, networkId, externalIp);
1594 LOG.debug("update : Remove the IP mapping for the router ID {} and "
1595 + "internal IP {} external IP {}", routerId, subnetAddr[0], externalIp);
1596 naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1599 LOG.debug("update : End processing of the Subnet IDs removal during the update operation");
1604 }, NatConstants.NAT_DJC_MAX_RETRIES);
1607 private boolean isExternalIpAllocated(String externalIp) {
1608 InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1609 Optional<ExternalIpsCounter> externalCountersData =
1610 MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1611 if (externalCountersData.isPresent()) {
1612 ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1613 List<ExternalCounters> externalCounters = externalIpsCounters.getExternalCounters();
1614 for (ExternalCounters ext : externalCounters) {
1615 for (ExternalIpCounter externalIpCount : ext.getExternalIpCounter()) {
1616 if (externalIpCount.getExternalIp().equals(externalIp)) {
1617 if (externalIpCount.getCounter() != 0) {
1628 private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
1629 Uuid networkId, String subnetIp, TypedWriteTransaction<Configuration> writeFlowInvTx) {
1630 String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1632 InetAddress address = InetAddress.getByName(subnetIpParts[0]);
1633 if (address instanceof Inet6Address) {
1634 LOG.debug("allocateExternalIp : Skipping ipv6 address {} for the router {}.", address, routerName);
1637 } catch (UnknownHostException e) {
1638 LOG.error("allocateExternalIp : Invalid ip address {}", subnetIpParts[0], e);
1641 String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1642 if (leastLoadedExtIpAddr != null) {
1643 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1644 String leastLoadedExtIp = externalIpParts[0];
1645 String leastLoadedExtIpPrefix = externalIpParts[1];
1646 IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1647 subnetIp = subnetIpParts[0];
1648 String subnetIpPrefix = subnetIpParts[1];
1649 IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1650 LOG.debug("allocateExternalIp : Add the IP mapping for the router ID {} and internal "
1651 + "IP {} and prefix {} -> external IP {} and prefix {}",
1652 routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1653 naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1656 // Check if external IP is already assigned a route. (i.e. External IP is previously
1657 // allocated to any of the subnets)
1658 // If external IP is already assigned a route, (, do not re-advertise to the BGP
1659 String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1660 Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1661 if (label != null) {
1663 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1664 IpMapKey ipMapKey = new IpMapKey(internalIp);
1665 LOG.debug("allocateExternalIp : Setting label {} for internalIp {} and externalIp {}",
1666 label, internalIp, leastLoadedExtIpAddrStr);
1667 IpMap newIpm = new IpMapBuilder().withKey(ipMapKey).setInternalIp(internalIp)
1668 .setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1669 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1670 naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1674 // Re-advertise to the BGP for the external IP, which is allocated to the subnet
1675 // for the first time and hence not having a route.
1676 //Get the VPN Name using the network ID
1677 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1678 if (vpnName != null) {
1679 LOG.debug("allocateExternalIp : Retrieved vpnName {} for networkId {}", vpnName, networkId);
1680 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1681 LOG.debug("allocateExternalIp : Best effort for getting primary napt switch when router i/f are"
1682 + "added after gateway-set");
1683 dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1684 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1685 LOG.error("allocateExternalIp : dpnId is null or Zero for the router {}", routerName);
1689 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1690 leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, networkId, router,
1696 protected Long checkExternalIpLabel(long routerId, String externalIp) {
1697 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1698 for (IpMap ipMap : ipMaps) {
1699 if (ipMap.getExternalIp().equals(externalIp)) {
1700 if (ipMap.getLabel() != null) {
1701 return ipMap.getLabel();
1705 LOG.error("checkExternalIpLabel : no ipMaps found for routerID:{} and externalIP:{}", routerId, externalIp);
1710 protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1711 LOG.trace("remove : Router delete method");
1713 ROUTER DELETE SCENARIO
1714 1) Get the router ID from the event.
1715 2) Build the cookie information from the router ID.
1716 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1717 4) Build the flow with the cookie value.
1718 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1719 6) Remove the flows from the other switches which points to the primary and secondary
1720 switches for the flows related the router ID.
1721 7) Get the list of external IP address maintained for the router ID.
1722 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1723 9) Withdraw the corresponding routes from the BGP.
1726 if (identifier == null || router == null) {
1727 LOG.error("remove : returning without processing since routers is null");
1731 String routerName = router.getRouterName();
1732 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.key(),
1733 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
1734 LOG.info("remove : Removing default NAT route from FIB on all dpns part of router {} ",
1736 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1737 if (routerId == NatConstants.INVALID_ID) {
1738 LOG.error("remove : Remove external router event - Invalid routerId for routerName {}",
1742 long bgpVpnId = NatConstants.INVALID_ID;
1743 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1744 if (bgpVpnUuid != null) {
1745 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1747 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, false,
1749 Uuid networkUuid = router.getNetworkId();
1751 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1752 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
1753 // No NAPT switch for external router, probably because the router is not attached to
1755 // internal networks
1757 "No NAPT switch for router {}, check if router is attached to any internal "
1762 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1763 handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId,
1766 NatOverVxlanUtil.releaseVNI(routerName, idManager);
1767 })), NatConstants.NAT_DJC_MAX_RETRIES);
1770 // TODO Clean up the exception handling
1771 @SuppressWarnings("checkstyle:IllegalCatch")
1772 public void handleDisableSnat(Routers router, Uuid networkUuid, @Nonnull Collection<String> externalIps,
1773 boolean routerFlag, String vpnName, BigInteger naptSwitchDpnId,
1774 long routerId, TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
1775 LOG.info("handleDisableSnat : Entry");
1776 String routerName = router.getRouterName();
1779 removeNaptSwitch(routerName);
1781 updateNaptSwitch(routerName, BigInteger.ZERO);
1784 LOG.debug("handleDisableSnat : Remove the ExternalCounter model for the router ID {}", routerId);
1785 naptManager.removeExternalCounter(routerId);
1787 LOG.debug("handleDisableSnat : got primarySwitch as dpnId {}", naptSwitchDpnId);
1788 if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
1789 LOG.error("handleDisableSnat : Unable to retrieve the primary NAPT switch for the "
1790 + "router ID {} from RouterNaptSwitch model", routerId);
1793 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
1795 if (extNwProvType == null) {
1796 LOG.error("handleDisableSnat : External Network Provider Type missing");
1799 Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps());
1800 removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnName, externalIps,
1801 externalSubnetList, removeFlowInvTx, extNwProvType);
1802 removeFlowsFromNonActiveSwitches(routerId, routerName, naptSwitchDpnId, removeFlowInvTx);
1804 String externalSubnetVpn = null;
1805 for (Uuid externalSubnetId : externalSubnetList) {
1806 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, externalSubnetId);
1807 // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
1808 if (externalSubnet.isPresent()) {
1809 externalSubnetVpn = externalSubnetId.getValue();
1810 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, externalSubnetVpn,
1811 router.getExtGwMacAddress(), removeFlowInvTx);
1814 if (externalSubnetVpn == null) {
1815 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnName,
1816 router.getExtGwMacAddress(), removeFlowInvTx);
1818 } catch (Exception ex) {
1819 LOG.error("handleDisableSnat : Failed to remove fib entries for routerId {} in naptSwitchDpnId {}",
1820 routerId, naptSwitchDpnId, ex);
1822 // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
1823 // for the router ID.
1824 LOG.debug("handleDisableSnat : Remove the Internal to external IP address maintained for the "
1825 + "router ID {} in the DS", routerId);
1826 naptManager.removeMapping(routerId);
1827 } catch (Exception ex) {
1828 LOG.error("handleDisableSnat : Exception while handling disableSNAT for router :{}", routerName, ex);
1830 LOG.info("handleDisableSnat : Exit");
1833 // TODO Clean up the exception handling
1834 @SuppressWarnings("checkstyle:IllegalCatch")
1835 public void handleDisableSnatInternetVpn(String routerName, long routerId, Uuid networkUuid,
1836 @Nonnull Collection<String> externalIps,
1837 String vpnId, TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
1838 LOG.debug("handleDisableSnatInternetVpn: Started to process handle disable snat for router {} "
1839 + "with internet vpn {}", routerName, vpnId);
1841 BigInteger naptSwitchDpnId = null;
1842 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
1843 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1844 Optional<RouterToNaptSwitch> rtrToNapt =
1845 read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1846 if (rtrToNapt.isPresent()) {
1847 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1849 LOG.debug("handleDisableSnatInternetVpn : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1851 removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId,
1854 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1855 if (extGwMacAddress != null) {
1856 LOG.debug("handleDisableSnatInternetVpn : External Gateway MAC address {} found for "
1857 + "External Router ID {}", extGwMacAddress, routerId);
1859 LOG.error("handleDisableSnatInternetVpn : No External Gateway MAC address found for "
1860 + "External Router ID {}", routerId);
1863 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId, extGwMacAddress,
1865 } catch (Exception ex) {
1866 LOG.error("handleDisableSnatInternetVpn : Failed to remove fib entries for routerId {} "
1867 + "in naptSwitchDpnId {}", routerId, naptSwitchDpnId, ex);
1869 NatOverVxlanUtil.releaseVNI(vpnId, idManager);
1870 } catch (Exception ex) {
1871 LOG.error("handleDisableSnatInternetVpn: Exception while handling disableSNATInternetVpn for router {} "
1872 + "with internet vpn {}", routerName, vpnId, ex);
1874 LOG.debug("handleDisableSnatInternetVpn: Processed handle disable snat for router {} with internet vpn {}",
1878 // TODO Clean up the exception handling
1879 @SuppressWarnings("checkstyle:IllegalCatch")
1880 public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1881 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
1882 .setPrimarySwitchId(naptSwitchId).build();
1884 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1885 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1886 } catch (Exception ex) {
1887 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
1888 naptSwitchId, routerName);
1890 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
1891 naptSwitchId, routerName);
1894 protected void removeNaptSwitch(String routerName) {
1895 // Remove router and switch from model
1896 InstanceIdentifier<RouterToNaptSwitch> id =
1897 InstanceIdentifier.builder(NaptSwitches.class)
1898 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1899 LOG.debug("removeNaptSwitch : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1900 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1901 //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
1902 NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
1905 // TODO skitt Fix the exception handling here
1906 @SuppressWarnings("checkstyle:IllegalCatch")
1907 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
1908 public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
1909 BigInteger dpnId, Uuid networkId, String vpnName,
1910 @Nonnull Collection<String> externalIps,
1911 Collection<Uuid> externalSubnetList,
1912 TypedReadWriteTransaction<Configuration> confTx,
1913 ProviderTypes extNwProvType) {
1915 LOG.debug("removeNaptFlowsFromActiveSwitch : Remove NAPT flows from Active switch");
1916 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1918 //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1919 // traffic which comes from the VMs of the NAPT switches)
1920 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1921 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1924 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1925 + "and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
1926 mdsalManager.removeFlow(confTx, preSnatFlowEntity);
1928 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1929 // traffic which comes from the VMs of the non NAPT switches)
1930 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
1932 String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
1933 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1935 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1936 + "and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
1937 mdsalManager.removeFlow(confTx, tsNatFlowEntity);
1939 //Remove the flow table 25->44 from NAPT Switch
1940 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1941 NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, dpnId);
1944 //Remove the Outbound flow entry which forwards the packet to FIB Table
1946 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {}"
1947 + " and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1949 String outboundTcpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1950 NwConstants.IP_PROT_TCP);
1951 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1952 outboundTcpNatFlowRef);
1953 mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
1955 String outboundUdpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1956 NwConstants.IP_PROT_UDP);
1957 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1958 outboundUdpNatFlowRef);
1959 mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
1961 String icmpDropFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1962 NwConstants.IP_PROT_ICMP);
1963 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1965 mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
1966 boolean lastRouterOnExternalNetwork =
1967 !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker, networkId, routerName, dpnId);
1968 if (lastRouterOnExternalNetwork) {
1969 removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps, confTx);
1971 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
1972 // External Subnet Vpn Id.
1973 for (Uuid externalSubnetId : externalSubnetList) {
1974 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
1975 if (subnetVpnId != -1 && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
1976 dataBroker, externalSubnetId, routerName, dpnId)) {
1977 String natPfibSubnetFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
1978 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE,
1979 natPfibSubnetFlowRef);
1980 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
1981 LOG.debug("removeNaptFlowsFromActiveSwitch : Removed the flow in table {} with external subnet "
1982 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
1983 subnetVpnId, dpnId);
1987 //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1988 String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1989 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1992 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1993 + "and router ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
1994 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
1996 if (lastRouterOnExternalNetwork) {
1997 // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
1998 // - This does not work since ext-routers is deleted already - no network info
1999 //Get the VPN ID from the ExternalNetworks model
2001 if (vpnName == null || vpnName.isEmpty()) {
2002 // ie called from router delete cases
2003 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
2004 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnUuid is {}", vpnUuid);
2005 if (vpnUuid != null) {
2006 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2007 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId {} for external network {} router delete "
2008 + "or disableSNAT scenario", vpnId, networkId);
2011 // ie called from disassociate vpn case
2012 LOG.debug("removeNaptFlowsFromActiveSwitch : This is disassociate nw with vpn case with vpnName {}",
2014 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2015 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId for disassociate nw with vpn scenario {}",
2019 if (vpnId != NatConstants.INVALID_ID) {
2020 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2021 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2022 FlowEntity natPfibVpnFlowEntity =
2023 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2024 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in {} for the active switch with the "
2025 + "DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2026 mdsalManager.removeFlow(confTx, natPfibVpnFlowEntity);
2030 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2031 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2032 if (ipPortMapping == null) {
2033 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the IpPortMapping");
2037 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2038 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
2039 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2040 for (IpPortMap ipPortMap : ipPortMaps) {
2041 String ipPortInternal = ipPortMap.getIpPortInternal();
2042 String[] ipPortParts = ipPortInternal.split(":");
2043 if (ipPortParts.length != 2) {
2044 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the Internal IP and port");
2047 String internalIp = ipPortParts[0];
2048 String internalPort = ipPortParts[1];
2050 //Build the flow for the outbound NAPT table
2051 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2052 + NatConstants.COLON_SEPARATOR + internalPort);
2053 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2054 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
2055 FlowEntity outboundNaptFlowEntity =
2056 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2058 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch "
2059 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2060 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
2062 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2063 String externalIp = ipPortExternal.getIpAddress();
2064 int externalPort = ipPortExternal.getPortNum();
2066 //Build the flow for the inbound NAPT table
2067 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2068 String.valueOf(routerId), externalIp, externalPort);
2069 FlowEntity inboundNaptFlowEntity =
2070 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2072 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active active switch "
2073 + "with the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2074 mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
2077 } catch (Exception e) {
2078 LOG.error("Error removing flow", e);
2079 throw new RuntimeException("Error removing flow", e);
2083 // TODO skitt Fix the exception handling here
2084 @SuppressWarnings("checkstyle:IllegalCatch")
2085 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
2086 protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
2087 @Nonnull Collection<String> externalIps,
2088 TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
2089 long extVpnId = NatConstants.INVALID_ID;
2090 if (networkId != null) {
2091 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
2092 if (vpnUuid != null) {
2093 extVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2095 LOG.debug("removeNaptFibExternalOutputFlows : vpnUuid is null");
2098 LOG.debug("removeNaptFibExternalOutputFlows : networkId is null");
2099 extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2101 if (extVpnId == NatConstants.INVALID_ID) {
2102 LOG.warn("removeNaptFibExternalOutputFlows : extVpnId not found for routerId {}", routerId);
2103 extVpnId = routerId;
2105 for (String ip : externalIps) {
2106 String extIp = removeMaskFromIp(ip);
2107 String naptFlowRef = getFlowRefNaptPreFib(dpnId, NwConstants.NAPT_PFIB_TABLE, extVpnId);
2108 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in table {} for the active switch"
2109 + " with the DPN ID {} and router ID {} and IP {} flowRef {}",
2110 NwConstants.NAPT_PFIB_TABLE, dpnId, routerId, extIp, naptFlowRef);
2111 FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef);
2113 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2114 } catch (Exception e) {
2115 LOG.error("Error removing flow", e);
2116 throw new RuntimeException("Error removing flow", e);
2121 private String removeMaskFromIp(String ip) {
2122 if (ip != null && !ip.trim().isEmpty()) {
2123 return ip.split("/")[0];
2128 // TODO skitt Fix the exception handling here
2129 @SuppressWarnings("checkstyle:IllegalCatch")
2130 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
2131 public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
2132 BigInteger dpnId, Uuid networkId, String vpnName,
2133 TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
2134 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : Remove NAPT flows from Active switch Internet Vpn");
2135 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
2137 //Remove the NAPT PFIB TABLE entry
2139 if (vpnName != null) {
2140 // ie called from disassociate vpn case
2141 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : This is disassociate nw with vpn case "
2142 + "with vpnName {}", vpnName);
2143 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2144 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : vpnId for disassociate nw with vpn scenario {}",
2148 if (vpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker,
2149 networkId, routerName, dpnId)) {
2150 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2151 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2152 FlowEntity natPfibVpnFlowEntity =
2153 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2154 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the active switch "
2155 + "with the DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2157 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2158 } catch (Exception e) {
2159 LOG.error("Error removing flow", e);
2160 throw new RuntimeException("Error removing flow", e);
2163 // Remove IP-PORT active NAPT entries and release port from IdManager
2164 // For the router ID get the internal IP , internal port and the corresponding
2165 // external IP and external Port.
2166 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2167 if (ipPortMapping == null) {
2168 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the IpPortMapping");
2171 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2172 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
2173 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2174 for (IpPortMap ipPortMap : ipPortMaps) {
2175 String ipPortInternal = ipPortMap.getIpPortInternal();
2176 String[] ipPortParts = ipPortInternal.split(":");
2177 if (ipPortParts.length != 2) {
2178 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the Internal IP "
2182 String internalIp = ipPortParts[0];
2183 String internalPort = ipPortParts[1];
2185 //Build the flow for the outbound NAPT table
2186 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2187 + NatConstants.COLON_SEPARATOR + internalPort);
2188 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2189 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
2190 FlowEntity outboundNaptFlowEntity =
2191 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2193 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2194 + "active switch with the DPN ID {} and router ID {}",
2195 NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2197 mdsalManager.removeFlow(writeFlowInvTx, outboundNaptFlowEntity);
2198 } catch (Exception e) {
2199 LOG.error("Error removing flow", e);
2200 throw new RuntimeException("Error removing flow", e);
2203 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2204 String externalIp = ipPortExternal.getIpAddress();
2205 int externalPort = ipPortExternal.getPortNum();
2207 //Build the flow for the inbound NAPT table
2208 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2209 String.valueOf(routerId), externalIp, externalPort);
2210 FlowEntity inboundNaptFlowEntity =
2211 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2213 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2214 + "active active switch with the DPN ID {} and router ID {}",
2215 NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2217 mdsalManager.removeFlow(writeFlowInvTx, inboundNaptFlowEntity);
2218 } catch (Exception e) {
2219 LOG.error("Error removing flow", e);
2220 throw new RuntimeException("Error removing flow", e);
2223 // Finally release port from idmanager
2224 String internalIpPort = internalIp + ":" + internalPort;
2225 naptManager.removePortFromPool(internalIpPort, externalIp);
2227 //Remove sessions from models
2228 naptManager.removeIpPortMappingForRouterID(routerId);
2229 naptManager.removeIntIpPortMappingForRouterID(routerId);
2233 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Invalid vpnId {}", vpnId);
2237 // TODO skitt Fix the exception handling here
2238 @SuppressWarnings("checkstyle:IllegalCatch")
2239 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
2240 public void removeFlowsFromNonActiveSwitches(long routerId, String routerName,
2241 BigInteger naptSwitchDpnId, TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
2242 LOG.debug("removeFlowsFromNonActiveSwitches : Remove NAPT related flows from non active switches");
2244 // Remove the flows from the other switches which points to the primary and secondary switches
2245 // for the flows related the router ID.
2246 List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
2247 if (allSwitchList.isEmpty()) {
2248 LOG.error("removeFlowsFromNonActiveSwitches : Unable to get the swithces for the router {}", routerName);
2252 for (BigInteger dpnId : allSwitchList) {
2253 if (!naptSwitchDpnId.equals(dpnId)) {
2254 LOG.info("removeFlowsFromNonActiveSwitches : Handle Ordinary switch");
2256 //Remove the PSNAT entry which forwards the packet to Terminating Service table
2257 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
2258 FlowEntity preSnatFlowEntity =
2259 NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
2261 LOG.info("removeFlowsFromNonActiveSwitches : Remove the flow in the {} for the non active switch "
2262 + "with the DPN ID {} and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
2263 mdsalManager.removeFlow(removeFlowInvTx, preSnatFlowEntity);
2265 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
2266 long groupId = createGroupId(getGroupIdKey(routerName));
2267 List<BucketInfo> listBucketInfo = new ArrayList<>();
2268 GroupEntity preSnatGroupEntity =
2269 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
2271 LOG.info("removeFlowsFromNonActiveSwitches : Remove the group {} for the non active switch with "
2272 + "the DPN ID {} and router ID {}", groupId, dpnId, routerId);
2273 mdsalManager.removeGroup(removeFlowInvTx, preSnatGroupEntity);
2277 } catch (Exception e) {
2278 LOG.error("Error removing flow", e);
2279 throw new RuntimeException("Error removing flow", e);
2283 public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2284 @Nonnull Collection<String> externalIps, String vpnName,
2285 String extGwMacAddress, TypedReadWriteTransaction<Configuration> confTx) {
2286 //Withdraw the corresponding routes from the BGP.
2287 //Get the network ID using the router ID.
2288 LOG.debug("clrRtsFromBgpAndDelFibTs : Advertise to BGP and remove routes for externalIps {} with routerId {},"
2289 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2290 if (networkUuid == null) {
2291 LOG.error("clrRtsFromBgpAndDelFibTs : networkId is null");
2295 if (externalIps.isEmpty()) {
2296 LOG.error("clrRtsFromBgpAndDelFibTs : externalIps is empty");
2300 if (vpnName == null) {
2301 //Get the VPN Name using the network ID
2302 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2303 if (vpnName == null) {
2304 LOG.error("clrRtsFromBgpAndDelFibTs : No VPN associated with ext nw {} for the router {}",
2305 networkUuid, routerId);
2309 LOG.debug("clrRtsFromBgpAndDelFibTs : Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2311 //Remove custom FIB routes
2312 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2313 for (String extIp : externalIps) {
2314 clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, confTx);
2318 protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2319 final Uuid networkUuid, String extGwMacAddress,
2320 TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
2321 clearBgpRoutes(extIp, vpnName);
2322 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2326 protected void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp,
2327 final String vpnName, Uuid extNetworkId, long tempLabel,
2328 String gwMacAddress, boolean switchOver,
2329 TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
2330 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2331 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2332 if (routerName == null) {
2333 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2336 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
2337 if (extNwProvType == null) {
2338 LOG.error("delFibTsAndReverseTraffic : External Network Provider Type Missing");
2341 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2342 * external network provided type is VxLAN
2344 if (extNwProvType == ProviderTypes.VXLAN) {
2345 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, gwMacAddress
2349 if (tempLabel < 0) {
2350 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2355 final long label = tempLabel;
2356 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2357 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
2358 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label)
2359 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
2360 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2362 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2363 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2364 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2365 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2366 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2369 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2370 Futures.transformAsync(future, result -> {
2372 if (result.isSuccessful()) {
2373 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2374 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2375 .setVpnName(vpnName).setIpPrefix(externalIp).build();
2376 return vpnService.removeVpnLabel(labelInput);
2379 String.format("RPC call to remove custom FIB entries on dpn %s for "
2380 + "prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
2382 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2384 }, MoreExecutors.directExecutor());
2386 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2389 public void onFailure(@Nonnull Throwable error) {
2390 LOG.error("delFibTsAndReverseTraffic : Error in removing the label:{} or custom fib entries"
2391 + "got external ip {}", label, extIp, error);
2395 public void onSuccess(@Nonnull RpcResult<RemoveVpnLabelOutput> result) {
2396 if (result.isSuccessful()) {
2397 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2398 + "from VPN {}", externalIp, vpnName);
2400 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2401 + " from VPN {}, {}", externalIp, vpnName, result.getErrors());
2404 }, MoreExecutors.directExecutor());
2406 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2407 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2411 private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2412 final Uuid networkUuid, String extGwMacAddress, boolean switchOver,
2413 TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
2414 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2415 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2416 if (routerName == null) {
2417 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2420 //Get the external network provider type from networkId
2421 ProviderTypes extNwProvType = NatUtil.getProviderTypefromNetworkId(dataBroker, networkUuid);
2422 if (extNwProvType == null) {
2423 LOG.error("delFibTsAndReverseTraffic : Could not retrieve provider type for external network {} ",
2427 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2428 * external network provided type is VxLAN
2430 if (extNwProvType == ProviderTypes.VXLAN) {
2431 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, extGwMacAddress);
2434 //Get IPMaps from the DB for the router ID
2435 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
2436 if (dbIpMaps.isEmpty()) {
2437 LOG.error("delFibTsAndReverseTraffic : IPMaps not found for router {}", routerId);
2441 long tempLabel = NatConstants.INVALID_ID;
2442 for (IpMap dbIpMap : dbIpMaps) {
2443 String dbExternalIp = dbIpMap.getExternalIp();
2444 LOG.debug("delFibTsAndReverseTraffic : Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
2445 //Select the IPMap, whose external IP is the IP for which FIB is installed
2446 if (extIp.equals(dbExternalIp)) {
2447 tempLabel = dbIpMap.getLabel();
2448 LOG.debug("delFibTsAndReverseTraffic : Retrieved label {} for dbExternalIp {} with router id {}",
2449 tempLabel, dbExternalIp, routerId);
2453 if (tempLabel == NatConstants.INVALID_ID) {
2454 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2459 final long label = tempLabel;
2460 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2461 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
2462 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp)
2463 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).setServiceId(label).build();
2464 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2466 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2467 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2468 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2469 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2470 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2473 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2474 Futures.transformAsync(future, result -> {
2476 if (result.isSuccessful()) {
2477 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2478 .setVpnName(vpnName).setIpPrefix(externalIp).build();
2479 return vpnService.removeVpnLabel(labelInput);
2482 String.format("RPC call to remove custom FIB entries on dpn %s for "
2483 + "prefix %s Failed - %s",
2484 dpnId, externalIp, result.getErrors());
2486 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2488 }, MoreExecutors.directExecutor());
2490 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2493 public void onFailure(@Nonnull Throwable error) {
2494 LOG.error("delFibTsAndReverseTraffic : Error in removing the label or custom fib entries", error);
2498 public void onSuccess(@Nonnull RpcResult<RemoveVpnLabelOutput> result) {
2499 if (result.isSuccessful()) {
2500 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2501 + "from VPN {}", externalIp, vpnName);
2503 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2504 + " from VPN {}, {}", externalIp, vpnName, result.getErrors());
2507 }, MoreExecutors.directExecutor());
2509 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2510 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2514 protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2515 List<String> externalIps, String vpnName, String extGwMacAddress,
2516 TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
2517 //Withdraw the corresponding routes from the BGP.
2518 //Get the network ID using the router ID.
2519 LOG.debug("clearFibTsAndReverseTraffic : for externalIps {} with routerId {},"
2520 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2521 if (networkUuid == null) {
2522 LOG.error("clearFibTsAndReverseTraffic : networkId is null");
2526 if (externalIps == null || externalIps.isEmpty()) {
2527 LOG.error("clearFibTsAndReverseTraffic : externalIps is null");
2531 if (vpnName == null) {
2532 //Get the VPN Name using the network ID
2533 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2534 if (vpnName == null) {
2535 LOG.error("clearFibTsAndReverseTraffic : No VPN associated with ext nw {} for the router {}",
2536 networkUuid, routerId);
2540 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2542 //Remove custom FIB routes
2543 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2544 for (String extIp : externalIps) {
2545 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2550 protected void clearBgpRoutes(String externalIp, final String vpnName) {
2551 //Inform BGP about the route removal
2552 LOG.info("clearBgpRoutes : Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
2553 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
2554 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
2557 // TODO skitt Fix the exception handling here
2558 @SuppressWarnings("checkstyle:IllegalCatch")
2559 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
2560 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId,
2561 TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
2562 LOG.info("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
2563 List<MatchInfo> mkMatches = new ArrayList<>();
2564 // Matching metadata
2565 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
2566 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
2567 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
2568 5, String.format("%s:%d", "TST Flow Entry ", serviceId), 0, 0,
2569 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
2571 mdsalManager.removeFlow(writeFlowInvTx, dpnId, flowEntity);
2572 } catch (Exception e) {
2573 LOG.error("Error removing flow", e);
2574 throw new RuntimeException("Error removing flow", e);
2576 LOG.debug("removeTunnelTableEntry : dpID {} : label : {} removed successfully", dpnId, serviceId);
2579 // TODO skitt Fix the exception handling here
2580 @SuppressWarnings("checkstyle:IllegalCatch")
2581 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
2582 private void removeLFibTableEntry(BigInteger dpnId, long serviceId,
2583 TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
2584 List<MatchInfo> matches = new ArrayList<>();
2585 matches.add(MatchEthernetType.MPLS_UNICAST);
2586 matches.add(new MatchMplsLabel(serviceId));
2588 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2590 LOG.debug("removeLFibTableEntry : with flow ref {}", flowRef);
2592 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
2594 COOKIE_VM_LFIB_TABLE, matches, null);
2597 mdsalManager.removeFlow(writeFlowInvTx, dpnId, flowEntity);
2598 } catch (Exception e) {
2599 LOG.error("Error removing flow", e);
2600 throw new RuntimeException("Error removing flow", e);
2603 LOG.debug("removeLFibTableEntry : dpID : {} label : {} removed successfully", dpnId, serviceId);
2607 * router association to vpn.
2609 * @param routerName - Name of router
2610 * @param routerId - router id
2611 * @param bgpVpnName BGP VPN name
2613 public void changeLocalVpnIdToBgpVpnId(String routerName, long routerId, String bgpVpnName,
2614 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2615 LOG.debug("changeLocalVpnIdToBgpVpnId : Router associated to BGP VPN");
2616 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2617 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2619 LOG.debug("changeLocalVpnIdToBgpVpnId : BGP VPN ID value {} ", bgpVpnId);
2621 if (bgpVpnId != NatConstants.INVALID_ID) {
2622 LOG.debug("changeLocalVpnIdToBgpVpnId : Populate the router-id-name container with the "
2623 + "mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
2624 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
2625 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2626 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2627 getRoutersIdentifier(bgpVpnId), rtrs);
2629 // Get the allocated Primary NAPT Switch for this router
2630 LOG.debug("changeLocalVpnIdToBgpVpnId : Router ID value {} ", routerId);
2632 LOG.debug("changeLocalVpnIdToBgpVpnId : Update the Router ID {} to the BGP VPN ID {} ",
2633 routerId, bgpVpnId);
2634 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, writeFlowInvTx);
2637 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2638 createGroupId(getGroupIdKey(routerName));
2639 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true, writeFlowInvTx,
2646 * router disassociation from vpn.
2648 * @param routerName - Name of router
2649 * @param routerId - router id
2650 * @param bgpVpnName BGP VPN name
2652 public void changeBgpVpnIdToLocalVpnId(String routerName, long routerId, String bgpVpnName,
2653 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2654 LOG.debug("changeBgpVpnIdToLocalVpnId : Router dissociated from BGP VPN");
2655 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2656 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2657 LOG.debug("changeBgpVpnIdToLocalVpnId : BGP VPN ID value {} ", bgpVpnId);
2659 // Get the allocated Primary NAPT Switch for this router
2660 LOG.debug("changeBgpVpnIdToLocalVpnId : Router ID value {} ", routerId);
2662 LOG.debug("changeBgpVpnIdToLocalVpnId : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2663 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, NatConstants.INVALID_ID, writeFlowInvTx);
2666 createGroupId(getGroupIdKey(routerName));
2667 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2668 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true,
2669 writeFlowInvTx, extNwProvType);
2673 boolean chkExtRtrAndSnatEnbl(Uuid routerUuid) {
2674 InstanceIdentifier<Routers> routerInstanceIndentifier =
2675 InstanceIdentifier.builder(ExtRouters.class)
2676 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
2677 Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2678 return routerData.isPresent() && routerData.get().isEnableSnat();
2681 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2682 long routerId, boolean isSnatCfgd, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2684 long changedVpnId = bgpVpnId;
2685 String idType = "BGP VPN";
2686 if (bgpVpnId == NatConstants.INVALID_ID) {
2687 changedVpnId = routerId;
2691 List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2692 if (switches.isEmpty()) {
2693 LOG.error("installFlowsWithUpdatedVpnId : No switches found for router {}", routerName);
2696 for (BigInteger dpnId : switches) {
2697 // Update the BGP VPN ID in the SNAT miss entry to group
2698 if (!dpnId.equals(primarySwitchId)) {
2699 LOG.debug("installFlowsWithUpdatedVpnId : Install group in non NAPT switch {}", dpnId);
2700 List<BucketInfo> bucketInfoForNonNaptSwitches =
2701 getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName, routerId);
2702 long groupId = createGroupId(getGroupIdKey(routerName));
2704 groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
2708 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2709 + "{} in the non NAPT switch {}", idType, changedVpnId, groupId, dpnId);
2710 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
2711 mdsalManager.addFlow(confTx, flowEntity);
2714 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2715 + "in the primary switch {}", idType, changedVpnId, primarySwitchId);
2716 FlowEntity flowEntity =
2717 buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2718 mdsalManager.addFlow(confTx, flowEntity);
2721 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Terminating Service table (table "
2722 + "ID 36) which forwards the packet to the table 46 in the Primary switch {}",
2723 idType, changedVpnId, primarySwitchId);
2724 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, routerId,
2725 changedVpnId, confTx, extNwProvType);
2728 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Outbound NAPT table (table ID 46) "
2729 + "which punts the packet to the controller in the Primary switch {}",
2730 idType, changedVpnId, primarySwitchId);
2731 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2734 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT PFIB TABLE which forwards the"
2735 + " outgoing packet to FIB Table in the Primary switch {}",
2736 idType, changedVpnId, primarySwitchId);
2737 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2740 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT flows for the Outbound NAPT "
2741 + "table (table ID 46) and the INBOUND NAPT table (table ID 44) in the Primary switch"
2742 + " {}", idType, changedVpnId, primarySwitchId);
2743 updateNaptFlowsWithVpnId(primarySwitchId, routerName, routerId, bgpVpnId);
2745 LOG.debug("installFlowsWithUpdatedVpnId : Installing SNAT PFIB flow in the primary switch {}",
2747 Long vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2748 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2749 if (vpnId != NatConstants.INVALID_ID) {
2750 installNaptPfibEntry(primarySwitchId, vpnId, confTx);
2756 public void updateNaptFlowsWithVpnId(BigInteger dpnId, String routerName, long routerId, long bgpVpnId) {
2757 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2758 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2759 if (ipPortMapping == null) {
2760 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the IpPortMapping");
2763 // Get the External Gateway MAC Address
2764 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
2765 if (extGwMacAddress != null) {
2766 LOG.debug("updateNaptFlowsWithVpnId : External Gateway MAC address {} found for External Router ID {}",
2767 extGwMacAddress, routerId);
2769 LOG.error("updateNaptFlowsWithVpnId : No External Gateway MAC address found for External Router ID {}",
2773 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2774 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
2775 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2776 for (IpPortMap ipPortMap : ipPortMaps) {
2777 String ipPortInternal = ipPortMap.getIpPortInternal();
2778 String[] ipPortParts = ipPortInternal.split(":");
2779 if (ipPortParts.length != 2) {
2780 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the Internal IP and port");
2783 String internalIp = ipPortParts[0];
2784 String internalPort = ipPortParts[1];
2785 LOG.debug("updateNaptFlowsWithVpnId : Found Internal IP {} and Internal Port {}",
2786 internalIp, internalPort);
2787 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2788 NAPTEntryEvent.Protocol protocol;
2789 switch (protocolTypes) {
2791 protocol = NAPTEntryEvent.Protocol.TCP;
2794 protocol = NAPTEntryEvent.Protocol.UDP;
2797 protocol = NAPTEntryEvent.Protocol.TCP;
2799 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.parseInt(internalPort));
2800 SessionAddress externalAddress =
2801 naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2802 long internetVpnid = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2803 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
2804 routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
2805 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
2806 routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
2811 public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
2812 long changedVpnId) {
2814 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : called for dpId {}, routerName {} groupId {} "
2815 + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
2816 List<MatchInfo> matches = new ArrayList<>();
2817 matches.add(MatchEthernetType.IPV4);
2818 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2820 List<ActionInfo> actionsInfo = new ArrayList<>();
2821 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, changedVpnId,
2823 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
2824 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Setting the tunnel to the list of action infos {}",
2826 actionsInfo.add(new ActionGroup(groupId));
2827 List<InstructionInfo> instructions = new ArrayList<>();
2828 instructions.add(new InstructionApplyActions(actionsInfo));
2829 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2830 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2831 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2832 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2834 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Returning SNAT Flow Entity {}", flowEntity);
2838 public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
2839 long changedVpnId) {
2841 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : called for dpId {}, routerName {} "
2842 + "changed VPN ID {}", dpId, routerName, changedVpnId);
2843 List<MatchInfo> matches = new ArrayList<>();
2844 matches.add(MatchEthernetType.IPV4);
2845 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2847 List<InstructionInfo> instructions = new ArrayList<>();
2848 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2850 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2851 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2852 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2853 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2855 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : Returning SNAT Flow Entity {}", flowEntity);
2859 // TODO : Replace this with ITM Rpc once its available with full functionality
2860 protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
2861 long routerId, long changedVpnId, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2863 LOG.debug("installTerminatingServiceTblEntryWithUpdatedVpnId : called for switch {}, "
2864 + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2865 FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, routerId, changedVpnId,
2867 mdsalManager.addFlow(confTx, flowEntity);
2870 private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName,
2871 long routerIdLongVal, long changedVpnId, ProviderTypes extNwProvType) {
2872 LOG.debug("buildTsFlowEntityWithUpdatedVpnId : called for switch {}, routerName {}, BGP VPN ID {}",
2873 dpId, routerName, changedVpnId);
2874 List<MatchInfo> matches = new ArrayList<>();
2875 matches.add(MatchEthernetType.IPV4);
2877 BigInteger tunnelId = BigInteger.valueOf(changedVpnId);
2878 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2879 tunnelId = NatOverVxlanUtil.getRouterVni(idManager, routerName, changedVpnId);
2881 matches.add(new MatchTunnelId(tunnelId));
2883 List<InstructionInfo> instructions = new ArrayList<>();
2884 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2885 MetaDataUtil.METADATA_MASK_VRFID));
2886 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2887 BigInteger routerId = BigInteger.valueOf(routerIdLongVal);
2888 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2889 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2890 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2891 NwConstants.COOKIE_TS_TABLE, matches, instructions);
2895 public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId,
2896 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2897 LOG.debug("createOutboundTblEntryWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2898 dpnId, routerId, changedVpnId);
2899 FlowEntity tcpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2900 NwConstants.IP_PROT_TCP);
2901 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing tcp flow {}", tcpFlowEntity);
2902 mdsalManager.addFlow(writeFlowInvTx, tcpFlowEntity);
2904 FlowEntity udpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2905 NwConstants.IP_PROT_UDP);
2906 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing udp flow {}", udpFlowEntity);
2907 mdsalManager.addFlow(writeFlowInvTx, udpFlowEntity);
2909 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, changedVpnId);
2910 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
2911 mdsalManager.addFlow(writeFlowInvTx, icmpDropFlow);
2914 protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId,
2915 long changedVpnId, int protocol) {
2916 LOG.debug("buildOutboundFlowEntityWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2917 dpId, routerId, changedVpnId);
2918 BigInteger cookie = getCookieOutboundFlow(routerId);
2919 List<MatchInfo> matches = new ArrayList<>();
2920 matches.add(MatchEthernetType.IPV4);
2921 matches.add(new MatchIpProtocol((short)protocol));
2922 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2924 List<InstructionInfo> instructions = new ArrayList<>();
2925 List<ActionInfo> actionsInfos = new ArrayList<>();
2926 actionsInfos.add(new ActionPuntToController());
2927 if (snatPuntTimeout != 0) {
2928 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
2930 instructions.add(new InstructionApplyActions(actionsInfos));
2932 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
2933 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
2934 flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
2935 LOG.debug("createOutboundTblEntryWithBgpVpn : returning flowEntity {}", flowEntity);
2939 public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId,
2940 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2941 LOG.debug("installNaptPfibEntryWithBgpVpn : called for dpnId {} and segmentId {} ,BGP VPN ID {}",
2942 dpnId, segmentId, changedVpnId);
2943 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2944 mdsalManager.addFlow(writeFlowInvTx, naptPfibFlowEntity);
2947 public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2949 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : called for dpId {}, "
2950 + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2951 List<MatchInfo> matches = new ArrayList<>();
2952 matches.add(MatchEthernetType.IPV4);
2953 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2955 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2956 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2957 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
2958 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2959 instructionInfo.add(new InstructionApplyActions(listActionInfo));
2961 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2962 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2963 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2964 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2965 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : Returning NaptPFib Flow Entity {}", flowEntity);
2970 protected ExternalRoutersListener getDataTreeChangeListener() {
2971 return ExternalRoutersListener.this;
2974 protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId,
2975 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2976 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
2978 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
2979 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
2980 if (subnetVpnId != -1) {
2981 LOG.debug("installNaptPfibEntriesForExternalSubnets : called for dpnId {} "
2982 + "and vpnId {}", dpnId, subnetVpnId);
2983 installNaptPfibEntry(dpnId, subnetVpnId, writeFlowInvTx);