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 java.math.BigInteger;
19 import java.net.Inet6Address;
20 import java.net.InetAddress;
21 import java.net.UnknownHostException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
30 import java.util.Objects;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.Future;
34 import javax.annotation.PostConstruct;
35 import javax.inject.Inject;
36 import javax.inject.Singleton;
37 import org.eclipse.jdt.annotation.NonNull;
38 import org.eclipse.jdt.annotation.Nullable;
39 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
40 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
41 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
42 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
43 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
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.actions.ActionDrop;
61 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
62 import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
63 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromField;
64 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromValue;
65 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
66 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
67 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
68 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
69 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
70 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
71 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
72 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
73 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
74 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
75 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
76 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
77 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
78 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
79 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
80 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
81 import org.opendaylight.netvirt.elanmanager.api.IElanService;
82 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
83 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
84 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
85 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
86 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
87 import org.opendaylight.serviceutils.upgrade.UpgradeState;
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.InstanceIdentifier;
152 import org.opendaylight.yangtools.yang.common.RpcResult;
153 import org.slf4j.Logger;
154 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 NatOverVxlanUtil natOverVxlanUtil;
189 private final int snatPuntTimeout;
192 public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
193 final ItmRpcService itmManager,
194 final OdlInterfaceRpcService odlInterfaceRpcService,
195 final IdManagerService idManager,
196 final NaptManager naptManager,
197 final NAPTSwitchSelector naptSwitchSelector,
198 final IBgpManager bgpManager,
199 final VpnRpcService vpnService,
200 final FibRpcService fibService,
201 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
202 final NaptEventHandler naptEventHandler,
203 final NaptPacketInHandler naptPacketInHandler,
204 final IFibManager fibManager,
205 final IVpnManager vpnManager,
206 final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer,
207 final INeutronVpnManager nvpnManager,
208 final CentralizedSwitchScheduler centralizedSwitchScheduler,
209 final NatserviceConfig config,
210 final IElanService elanManager,
211 final JobCoordinator coordinator,
212 final UpgradeState upgradeState,
213 final NatOverVxlanUtil natOverVxlanUtil,
214 final IInterfaceManager interfaceManager) {
215 super(Routers.class, ExternalRoutersListener.class);
216 this.dataBroker = dataBroker;
217 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
218 this.mdsalManager = mdsalManager;
219 this.itmManager = itmManager;
220 this.odlInterfaceRpcService = odlInterfaceRpcService;
221 this.idManager = idManager;
222 this.naptManager = naptManager;
223 this.naptSwitchSelector = naptSwitchSelector;
224 this.bgpManager = bgpManager;
225 this.vpnService = vpnService;
226 this.fibService = fibService;
227 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
228 this.naptEventHandler = naptEventHandler;
229 this.naptPacketInHandler = naptPacketInHandler;
230 this.fibManager = fibManager;
231 this.vpnManager = vpnManager;
232 this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
233 this.nvpnManager = nvpnManager;
234 this.elanManager = elanManager;
235 this.centralizedSwitchScheduler = centralizedSwitchScheduler;
236 this.coordinator = coordinator;
237 this.upgradeState = upgradeState;
238 this.interfaceManager = interfaceManager;
239 this.natOverVxlanUtil = natOverVxlanUtil;
240 if (config != null) {
241 this.natMode = config.getNatMode();
242 this.snatPuntTimeout = config.getSnatPuntTimeout().intValue();
244 this.natMode = NatMode.Controller;
245 this.snatPuntTimeout = 0;
252 LOG.info("{} init", getClass().getSimpleName());
253 // This class handles ExternalRouters for Controller SNAT mode.
254 // For Conntrack SNAT mode, its handled in SnatExternalRoutersListener.java
255 if (natMode == NatMode.Controller) {
256 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
257 NatUtil.createGroupIdPool(idManager);
262 protected InstanceIdentifier<Routers> getWildCardPath() {
263 return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
267 // TODO Clean up the exception handling
268 @SuppressWarnings("checkstyle:IllegalCatch")
269 protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
270 // Populate the router-id-name container
271 String routerName = routers.getRouterName();
272 LOG.info("add : external router event for {}", routerName);
273 long routerId = NatUtil.getVpnId(dataBroker, routerName);
274 NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
275 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
277 if (routers.isEnableSnat()) {
278 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routers.key(),
279 () -> Collections.singletonList(
280 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
281 LOG.info("add : Installing NAT default route on all dpns part of router {}", routerName);
282 long bgpVpnId = NatConstants.INVALID_ID;
283 if (bgpVpnUuid != null) {
284 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
286 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, true, confTx);
287 // Allocate Primary Napt Switch for this router
288 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName);
289 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
290 handleEnableSnat(routers, routerId, primarySwitchId, bgpVpnId, confTx);
293 )), NatConstants.NAT_DJC_MAX_RETRIES);
295 LOG.info("add : SNAT is disabled for external router {} ", routerName);
297 } catch (Exception ex) {
298 LOG.error("add : Exception while Installing NAT flows on all dpns as part of router {}",
303 public void handleEnableSnat(Routers routers, long routerId, BigInteger primarySwitchId, long bgpVpnId,
304 TypedWriteTransaction<Configuration> confTx) {
305 String routerName = routers.getRouterName();
306 LOG.info("handleEnableSnat : Handling SNAT for router {}", routerName);
308 naptManager.initialiseExternalCounter(routers, routerId);
309 subnetRegisterMapping(routers, routerId);
311 LOG.debug("handleEnableSnat:About to create and install outbound miss entry in Primary Switch {} for router {}",
312 primarySwitchId, routerName);
314 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
315 routers.getNetworkId());
316 if (extNwProvType == null) {
317 LOG.error("handleEnableSnat : External Network Provider Type missing");
321 if (bgpVpnId != NatConstants.INVALID_ID) {
322 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, false, confTx,
325 // write metadata and punt
326 installOutboundMissEntry(routerName, routerId, primarySwitchId, confTx);
327 // Now install entries in SNAT tables to point to Primary for each router
328 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
329 for (BigInteger dpnId : switches) {
330 // Handle switches and NAPT switches separately
331 if (!dpnId.equals(primarySwitchId)) {
332 LOG.debug("handleEnableSnat : Handle Ordinary switch");
333 handleSwitches(dpnId, routerName, routerId, primarySwitchId);
335 LOG.debug("handleEnableSnat : Handle NAPT switch");
336 handlePrimaryNaptSwitch(dpnId, routerName, routerId, confTx);
341 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
342 if (externalIps.isEmpty()) {
343 LOG.error("handleEnableSnat : Internal External mapping not found for router {}", routerName);
346 for (String externalIpAddrPrefix : externalIps) {
347 LOG.debug("handleEnableSnat : Calling handleSnatReverseTraffic for primarySwitchId {}, "
348 + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
349 handleSnatReverseTraffic(confTx, primarySwitchId, routers, routerId, routerName, externalIpAddrPrefix
353 LOG.debug("handleEnableSnat : Exit");
356 private BigInteger getPrimaryNaptSwitch(String routerName) {
357 // Allocate Primary Napt Switch for this router
358 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
359 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
360 LOG.debug("handleEnableSnat : Primary NAPT switch with DPN ID {} is already elected for router {}",
361 primarySwitchId, routerName);
362 return primarySwitchId;
364 // Allocated an id from VNI pool for the Router.
365 natOverVxlanUtil.getRouterVni(routerName, NatConstants.INVALID_ID);
366 primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
367 LOG.debug("handleEnableSnat : Primary NAPT switch DPN ID {}", primarySwitchId);
369 return primarySwitchId;
372 protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId,
373 TypedWriteTransaction<Configuration> confTx) {
374 Long extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
375 if (extVpnId == NatConstants.INVALID_ID) {
376 LOG.error("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
379 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
380 if (externalIps.isEmpty()) {
381 LOG.error("installNaptPfibExternalOutputFlow - empty external Ips list for dpnId {} extVpnId {}",
385 for (String ip : externalIps) {
386 Uuid subnetId = getSubnetIdForFixedIp(ip);
387 if (subnetId != null) {
388 long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
389 if (subnetVpnId != NatConstants.INVALID_ID) {
390 extVpnId = subnetVpnId;
392 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
393 dpnId, extVpnId, subnetId);
394 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
395 mdsalManager.addFlow(confTx, postNaptFlowEntity);
401 private Uuid getSubnetIdForFixedIp(String ip) {
403 IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
404 Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
405 return NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
407 LOG.error("getSubnetIdForFixedIp : ip is null");
411 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
412 LOG.debug("subnetRegisterMapping : Fetching values from extRouters model");
413 List<String> externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
415 int extIpCounter = externalIps.size();
416 LOG.debug("subnetRegisterMapping : counter values before looping counter {} and extIpCounter {}",
417 counter, extIpCounter);
418 @Nullable List<Uuid> subnetIds = routerEntry.getSubnetIds();
419 if (subnetIds == null) {
422 for (Uuid subnet : subnetIds) {
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;
430 sn = SingleTransactionDataBroker.syncReadOptional(dataBroker,
431 LogicalDatastoreType.CONFIGURATION, subnetmapId);
432 } catch (ReadFailedException e) {
433 LOG.error("Failed to read SubnetMap for subnetmap Id {}", subnetmapId, e);
434 sn = Optional.absent();
436 if (sn.isPresent()) {
438 Subnetmap subnetmapEntry = sn.get();
439 String subnetString = subnetmapEntry.getSubnetIp();
440 String[] subnetSplit = subnetString.split("/");
441 String subnetIp = subnetSplit[0];
443 InetAddress address = InetAddress.getByName(subnetIp);
444 if (address instanceof Inet6Address) {
445 LOG.debug("subnetRegisterMapping : Skipping ipv6 subnet {} for the router {} with ipv6 address "
446 + "{} ", subnet, routerEntry.getRouterName(), address);
449 } catch (UnknownHostException e) {
450 LOG.error("subnetRegisterMapping : Invalid ip address {}", subnetIp, e);
453 String subnetPrefix = "0";
454 if (subnetSplit.length == 2) {
455 subnetPrefix = subnetSplit[1];
457 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
458 LOG.debug("subnetRegisterMapping : subnetAddr is {} and subnetPrefix is {}",
459 subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
461 LOG.debug("subnetRegisterMapping : counter values counter {} and extIpCounter {}",
462 counter, extIpCounter);
463 if (extIpCounter != 0) {
464 if (counter < extIpCounter) {
465 String[] ipSplit = externalIps.get(counter).split("/");
466 String externalIp = ipSplit[0];
467 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
468 if (ipSplit.length == 2) {
469 extPrefix = ipSplit[1];
471 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
472 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
473 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
474 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
475 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
476 + "externalIp {}. prefix {}", subnetIp, subnetPrefix, externalIp, extPrefix);
478 counter = 0; //Reset the counter which runs on externalIps for round-robbin effect
479 LOG.debug("subnetRegisterMapping : Counter on externalIps got reset");
480 String[] ipSplit = externalIps.get(counter).split("/");
481 String externalIp = ipSplit[0];
482 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
483 if (ipSplit.length == 2) {
484 extPrefix = ipSplit[1];
486 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
487 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
488 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
489 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
490 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
491 + "externalIp {}. prefix {}", subnetIp, subnetPrefix,
492 externalIp, extPrefix);
496 LOG.debug("subnetRegisterMapping : Counter on externalIps incremented to {}", counter);
498 LOG.warn("subnetRegisterMapping : No internal subnets present in extRouters Model");
503 private void addOrDelDefFibRouteToSNAT(String routerName, long routerId, long bgpVpnId,
504 Uuid bgpVpnUuid, boolean create, TypedReadWriteTransaction<Configuration> confTx)
505 throws ExecutionException, InterruptedException {
506 //Check if BGP VPN exists. If exists then invoke the new method.
507 if (bgpVpnId != NatConstants.INVALID_ID) {
508 if (bgpVpnUuid != null) {
509 String bgpVpnName = bgpVpnUuid.getValue();
510 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
511 bgpVpnId, bgpVpnName);
512 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
513 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
514 confTx.put(getRoutersIdentifier(bgpVpnId), rtrs, CREATE_MISSING_PARENTS);
517 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
519 removeDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
524 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
525 addOrDelDefaultFibRouteForSNAT(routerName, routerId, create, confTx);
528 private void addOrDelDefaultFibRouteForSNAT(String routerName, long routerId, boolean create,
529 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
530 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
531 if (switches.isEmpty()) {
532 LOG.info("addOrDelDefaultFibRouteForSNAT : No switches found for router {}", routerName);
535 if (routerId == NatConstants.INVALID_ID) {
536 LOG.error("addOrDelDefaultFibRouteForSNAT : Could not retrieve router Id for {} to program "
537 + "default NAT route in FIB", routerName);
540 for (BigInteger dpnId : switches) {
542 LOG.debug("addOrDelDefaultFibRouteForSNAT : installing default NAT route for router {} in dpn {} "
543 + "for the internal vpn-id {}", routerId, dpnId, routerId);
544 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
546 LOG.debug("addOrDelDefaultFibRouteForSNAT : removing default NAT route for router {} in dpn {} "
547 + "for the internal vpn-id {}", routerId, dpnId, routerId);
548 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
553 private void addDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
554 long bgpVpnId, TypedWriteTransaction<Configuration> confTx) {
555 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
556 if (dpnIds.isEmpty()) {
557 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
558 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
561 for (BigInteger dpnId : dpnIds) {
562 if (bgpVpnId != NatConstants.INVALID_ID) {
563 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
564 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
565 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
567 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
568 + "in dpn {} for the internal vpn", routerId, dpnId);
569 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
574 private void removeDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
575 long bgpVpnId, TypedReadWriteTransaction<Configuration> confTx)
576 throws ExecutionException, InterruptedException {
577 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
578 if (dpnIds.isEmpty()) {
579 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
580 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
583 for (BigInteger dpnId : dpnIds) {
584 if (bgpVpnId != NatConstants.INVALID_ID) {
585 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
586 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
587 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
589 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
590 + "in dpn {} for the internal vpn", routerId, dpnId);
591 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
596 protected void installOutboundMissEntry(String routerName, long routerId, BigInteger primarySwitchId,
597 TypedWriteTransaction<Configuration> confTx) {
598 LOG.debug("installOutboundMissEntry : Router ID from getVpnId {}", routerId);
599 if (routerId != NatConstants.INVALID_ID) {
600 LOG.debug("installOutboundMissEntry : Creating miss entry on primary {}, for router {}",
601 primarySwitchId, routerId);
602 createOutboundTblEntry(primarySwitchId, routerId, confTx);
604 LOG.error("installOutboundMissEntry : Unable to fetch Router Id for RouterName {}, failed to "
605 + "createAndInstallMissEntry", routerName);
609 public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID, int protocol) {
610 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
611 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + protocol;
614 private String getFlowRefNaptPreFib(BigInteger dpnId, short tableId, long vpnId) {
615 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
616 .FLOWID_SEPARATOR + vpnId;
619 public BigInteger getCookieOutboundFlow(long routerId) {
620 return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
621 BigInteger.valueOf(routerId));
624 private ActionLearn getLearnActionForPunt(int protocol, int hardTimeout, BigInteger cookie) {
627 int l4portFieldLen = NxmOfFieldType.NXM_OF_TCP_SRC.getFlowModHeaderLenInt();
629 if (protocol == NwConstants.IP_PROT_TCP) {
630 l4SrcPortField = NxmOfFieldType.NXM_OF_TCP_SRC.getType();
631 l4DstPortField = NxmOfFieldType.NXM_OF_TCP_DST.getType();
633 l4SrcPortField = NxmOfFieldType.NXM_OF_UDP_SRC.getType();
634 l4DstPortField = NxmOfFieldType.NXM_OF_UDP_DST.getType();
636 List<ActionLearn.FlowMod> flowMods = Arrays.asList(
637 new MatchFromValue(NwConstants.ETHTYPE_IPV4, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
638 NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
639 new MatchFromValue(protocol, NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
640 NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
641 new MatchFromField(NxmOfFieldType.NXM_OF_IP_SRC.getType(), NxmOfFieldType.NXM_OF_IP_SRC.getType(),
642 NxmOfFieldType.NXM_OF_IP_SRC.getFlowModHeaderLenInt()),
643 new MatchFromField(NxmOfFieldType.NXM_OF_IP_DST.getType(), NxmOfFieldType.NXM_OF_IP_DST.getType(),
644 NxmOfFieldType.NXM_OF_IP_DST.getFlowModHeaderLenInt()),
645 new MatchFromField(l4SrcPortField, l4SrcPortField, l4portFieldLen),
646 new MatchFromField(l4DstPortField, l4DstPortField, l4portFieldLen),
647 new MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
648 MetaDataUtil.METADATA_VPN_ID_OFFSET,
649 NxmOfFieldType.OXM_OF_METADATA.getType(), MetaDataUtil.METADATA_VPN_ID_OFFSET,
650 MetaDataUtil.METADATA_VPN_ID_BITLEN));
652 return new ActionLearn(0, hardTimeout, 7, cookie, 0,
653 NwConstants.OUTBOUND_NAPT_TABLE, 0, 0, flowMods);
656 private FlowEntity buildIcmpDropFlow(BigInteger dpnId, long routerId, long vpnId) {
657 List<MatchInfo> matches = new ArrayList<>();
658 matches.add(MatchEthernetType.IPV4);
659 matches.add(MatchIpProtocol.ICMP);
660 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
662 List<ActionInfo> actionInfos = new ArrayList<>();
663 actionInfos.add(new ActionDrop());
665 List<InstructionInfo> instructions = new ArrayList<>();
666 instructions.add(new InstructionApplyActions(actionInfos));
668 String flowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
669 NwConstants.IP_PROT_ICMP);
670 FlowEntity flow = MDSALUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
671 NwConstants.TABLE_MISS_PRIORITY, "icmp drop flow", 0, 0,
672 NwConstants.COOKIE_OUTBOUND_NAPT_TABLE, matches, instructions);
676 protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId, int protocol) {
677 LOG.debug("buildOutboundFlowEntity : called for dpId {} and routerId{}", dpId, routerId);
678 BigInteger cookie = getCookieOutboundFlow(routerId);
679 List<MatchInfo> matches = new ArrayList<>();
680 matches.add(MatchEthernetType.IPV4);
681 matches.add(new MatchIpProtocol((short)protocol));
682 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
684 List<InstructionInfo> instructions = new ArrayList<>();
685 List<ActionInfo> actionsInfos = new ArrayList<>();
686 actionsInfos.add(new ActionPuntToController());
687 if (snatPuntTimeout != 0) {
688 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
690 instructions.add(new InstructionApplyActions(actionsInfos));
692 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
693 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
695 cookie, matches, instructions);
696 LOG.debug("installOutboundMissEntry : returning flowEntity {}", flowEntity);
700 public void createOutboundTblEntry(BigInteger dpnId, long routerId, TypedWriteTransaction<Configuration> confTx) {
701 LOG.debug("createOutboundTblEntry : called for dpId {} and routerId {}", dpnId, routerId);
702 FlowEntity tcpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_TCP);
703 LOG.debug("createOutboundTblEntry : Installing tcp flow {}", tcpflowEntity);
704 mdsalManager.addFlow(confTx, tcpflowEntity);
706 FlowEntity udpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_UDP);
707 LOG.debug("createOutboundTblEntry : Installing udp flow {}", udpflowEntity);
708 mdsalManager.addFlow(confTx, udpflowEntity);
710 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, routerId);
711 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
712 mdsalManager.addFlow(confTx, icmpDropFlow);
716 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
717 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
718 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
720 Future<RpcResult<GetTunnelInterfaceNameOutput>> result =
721 itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
722 .setSourceDpid(srcDpId)
723 .setDestinationDpid(dstDpId)
724 .setTunnelType(tunType)
726 rpcResult = result.get();
727 if (!rpcResult.isSuccessful()) {
728 tunType = TunnelTypeGre.class;
729 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
730 .setSourceDpid(srcDpId)
731 .setDestinationDpid(dstDpId)
732 .setTunnelType(tunType)
734 rpcResult = result.get();
735 if (!rpcResult.isSuccessful()) {
736 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
737 rpcResult.getErrors());
739 return rpcResult.getResult().getInterfaceName();
741 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
742 rpcResult.getErrors());
744 return rpcResult.getResult().getInterfaceName();
746 } catch (InterruptedException | ExecutionException | NullPointerException e) {
747 LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
748 + "between {} and {}", srcDpId, dstDpId, e);
754 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName, long routerId,
755 TypedWriteTransaction<Configuration> confTx) {
757 LOG.debug("installSnatMissEntry : called for for the primary NAPT switch dpnId {} ", dpnId);
758 // Install miss entry pointing to group
759 FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName, routerId);
760 mdsalManager.addFlow(confTx, flowEntity);
763 protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo,
764 String routerName, long routerId) {
765 LOG.debug("installSnatMissEntry : called for dpnId {} with primaryBucket {} ",
766 dpnId, bucketInfo.get(0));
767 // Install the select group
768 long groupId = createGroupId(getGroupIdKey(routerName));
769 GroupEntity groupEntity =
770 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
771 LOG.debug("installSnatMissEntry : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
772 mdsalManager.syncInstallGroup(groupEntity);
773 // Install miss entry pointing to group
774 FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, routerId, groupId);
775 if (flowEntity == null) {
776 LOG.error("installSnatMissEntry : Flow entity received as NULL. "
777 + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
778 + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
781 mdsalManager.installFlow(flowEntity);
784 long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo) {
785 long groupId = createGroupId(getGroupIdKey(routerName));
786 GroupEntity groupEntity =
787 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
788 LOG.debug("installGroup : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
789 mdsalManager.syncInstallGroup(groupEntity);
793 private FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long routerId, long groupId) {
794 LOG.debug("buildSnatFlowEntity : called for dpId {}, routerName {} and groupId {}",
795 dpId, routerName, groupId);
796 List<MatchInfo> matches = new ArrayList<>();
797 matches.add(MatchEthernetType.IPV4);
798 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
800 List<ActionInfo> actionsInfo = new ArrayList<>();
801 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager, idManager,
802 routerId, routerName);
803 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
804 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
805 actionsInfo.add(new ActionGroup(groupId));
806 List<InstructionInfo> instructions = new ArrayList<>();
807 instructions.add(new InstructionApplyActions(actionsInfo));
808 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
809 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
810 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
811 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
813 LOG.debug("buildSnatFlowEntity : Returning SNAT Flow Entity {}", flowEntity);
817 private FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName, long routerId) {
819 LOG.debug("buildSnatFlowEntityForPrmrySwtch : called for primary NAPT switch dpId {}, routerName {}", dpId,
821 List<MatchInfo> matches = new ArrayList<>();
822 matches.add(MatchEthernetType.IPV4);
823 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
825 List<InstructionInfo> instructions = new ArrayList<>();
826 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
828 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
829 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
830 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
831 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
833 LOG.debug("buildSnatFlowEntityForPrmrySwtch : Returning SNAT Flow Entity {}", flowEntity);
837 // TODO : Replace this with ITM Rpc once its available with full functionality
838 protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName, long routerId,
839 TypedWriteTransaction<Configuration> confTx) {
841 LOG.debug("installTerminatingServiceTblEntry : for switch {}, routerName {}",
843 FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName, routerId);
844 if (flowEntity == null) {
845 LOG.error("installTerminatingServiceTblEntry : Flow entity received as NULL. "
846 + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
847 + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
851 mdsalManager.addFlow(confTx, flowEntity);
855 private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName, long routerId) {
856 List<MatchInfo> matches = new ArrayList<>();
857 matches.add(MatchEthernetType.IPV4);
858 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
859 idManager, routerId, routerName);
860 matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
861 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
862 List<InstructionInfo> instructions = new ArrayList<>();
863 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
864 MetaDataUtil.METADATA_MASK_VRFID));
865 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
866 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
867 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
872 public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
873 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
874 .FLOWID_SEPARATOR + routerID;
877 public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
878 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
879 .FLOWID_SEPARATOR + routerID;
882 private String getGroupIdKey(String routerName) {
883 return "snatmiss." + routerName;
886 protected long createGroupId(String groupIdKey) {
887 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
888 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
891 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
892 RpcResult<AllocateIdOutput> rpcResult = result.get();
893 return rpcResult.getResult().getIdValue();
894 } catch (NullPointerException | InterruptedException | ExecutionException e) {
895 LOG.error("Exception While allocating id for group: {}", groupIdKey, e);
900 protected void handleSwitches(BigInteger dpnId, String routerName, long routerId, BigInteger primarySwitchId) {
901 LOG.debug("handleSwitches : Installing SNAT miss entry in switch {}", dpnId);
902 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
903 String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
904 List<BucketInfo> listBucketInfo = new ArrayList<>();
906 if (ifNamePrimary != null) {
907 LOG.debug("handleSwitches : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
908 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
909 interfaceManager, ifNamePrimary, routerId, true);
910 if (listActionInfoPrimary.isEmpty()) {
911 LOG.error("handleSwitches : Unable to retrieve output actions on Non-NAPT switch {} for router {}"
912 + " towards Napt-switch {} via tunnel interface {}", dpnId, routerName, primarySwitchId,
916 LOG.error("handleSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} from "
917 + "Non-Napt switch {} for router {}", primarySwitchId, dpnId, routerName);
919 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
921 listBucketInfo.add(0, bucketPrimary);
922 installSnatMissEntry(dpnId, listBucketInfo, routerName, routerId);
925 List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
926 BigInteger primarySwitchId, String routerName, long routerId) {
927 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
928 String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
929 List<BucketInfo> listBucketInfo = new ArrayList<>();
931 if (ifNamePrimary != null) {
932 LOG.debug("getBucketInfoForNonNaptSwitches : On Non- Napt switch , Primary Tunnel interface is {}",
934 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
935 interfaceManager, ifNamePrimary, routerId, true);
936 if (listActionInfoPrimary.isEmpty()) {
937 LOG.error("getBucketInfoForNonNaptSwitches : Unable to retrieve output actions on Non-NAPT switch {} "
938 + "for router {} towards Napt-switch {} via tunnel interface {}",
939 nonNaptSwitchId, routerName, primarySwitchId, ifNamePrimary);
942 LOG.error("getBucketInfoForNonNaptSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} "
943 + "from Non-Napt switch {} for router {}", primarySwitchId, nonNaptSwitchId, routerName);
945 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
947 listBucketInfo.add(0, bucketPrimary);
948 return listBucketInfo;
951 protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName, long routerId,
952 TypedWriteTransaction<Configuration> confTx) {
955 * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
958 LOG.debug("handlePrimaryNaptSwitch : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
961 List<BucketInfo> listBucketInfo = new ArrayList<>();
962 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
963 listActionInfoPrimary.add(new ActionNxResubmit(NatConstants.TERMINATING_SERVICE_TABLE));
964 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
965 listBucketInfo.add(0, bucketPrimary);
968 installSnatMissEntryForPrimrySwch(dpnId, routerName, routerId, confTx);
969 installTerminatingServiceTblEntry(dpnId, routerName, routerId, confTx);
970 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
971 installNaptPfibEntry(dpnId, routerId, confTx);
972 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
973 if (networkId != null) {
974 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
975 if (vpnUuid != null) {
976 long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
977 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
978 installNaptPfibEntriesForExternalSubnets(routerName, dpnId, null);
979 //Install the NAPT PFIB TABLE which forwards outgoing packet to FIB Table matching on the VPN ID.
980 if (vpnId != NatConstants.INVALID_ID) {
981 installNaptPfibEntry(dpnId, vpnId, null);
983 return Collections.emptyList();
986 LOG.warn("handlePrimaryNaptSwitch : External Vpn ID missing for Ext-Network : {}", networkId);
989 LOG.warn("handlePrimaryNaptSwitch : External Network not available for router : {}", routerName);
993 List<BucketInfo> getBucketInfoForPrimaryNaptSwitch() {
994 List<BucketInfo> listBucketInfo = new ArrayList<>();
995 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
996 listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
997 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
998 listBucketInfo.add(0, bucketPrimary);
999 return listBucketInfo;
1002 public void installNaptPfibEntry(BigInteger dpnId, long segmentId,
1003 @Nullable TypedWriteTransaction<Configuration> confTx) {
1004 LOG.debug("installNaptPfibEntry : called for dpnId {} and segmentId {} ", dpnId, segmentId);
1005 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
1006 if (confTx != null) {
1007 mdsalManager.addFlow(confTx, naptPfibFlowEntity);
1009 mdsalManager.installFlow(naptPfibFlowEntity);
1013 public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
1015 LOG.debug("buildNaptPfibFlowEntity : called for dpId {}, segmentId {}", dpId, segmentId);
1016 List<MatchInfo> matches = new ArrayList<>();
1017 matches.add(MatchEthernetType.IPV4);
1018 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
1020 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
1021 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
1022 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
1023 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
1024 instructionInfo.add(new InstructionApplyActions(listActionInfo));
1026 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
1027 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
1028 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
1029 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
1030 LOG.debug("buildNaptPfibFlowEntity : Returning NaptPFib Flow Entity {}", flowEntity);
1034 public void handleSnatReverseTraffic(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, Routers router,
1035 long routerId, String routerName, String externalIp) {
1036 LOG.debug("handleSnatReverseTraffic : entry for DPN ID {}, routerId {}, externalIp: {}",
1037 dpnId, routerId, externalIp);
1038 Uuid networkId = router.getNetworkId();
1039 if (networkId == null) {
1040 LOG.error("handleSnatReverseTraffic : networkId is null for the router ID {}", routerId);
1043 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1044 if (vpnName == null) {
1045 LOG.error("handleSnatReverseTraffic : No VPN associated with ext nw {} to handle add external ip "
1046 + "configuration {} in router {}", networkId, externalIp, routerId);
1049 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1050 externalIp, networkId, router, confTx);
1051 LOG.debug("handleSnatReverseTraffic : exit for DPN ID {}, routerId {}, externalIp : {}",
1052 dpnId, routerId, externalIp);
1055 public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
1056 final long routerId, final String routerName, final String externalIp,
1057 final Uuid extNetworkId, @Nullable final Routers router,
1058 final TypedWriteTransaction<Configuration> confTx) {
1059 LOG.debug("advToBgpAndInstallFibAndTsFlows : entry for DPN ID {}, tableId {}, vpnname {} "
1060 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
1061 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
1062 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1063 if (rd == null || rd.isEmpty()) {
1064 LOG.error("advToBgpAndInstallFibAndTsFlows : Unable to get RD for VPN Name {}", vpnName);
1067 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
1068 if (extNwProvType == null) {
1069 LOG.error("advToBgpAndInstallFibAndTsFlows : External Network Provider Type missing");
1072 if (extNwProvType == ProviderTypes.VXLAN) {
1073 evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
1074 nextHopIp, routerId, routerName, extNetworkId, confTx);
1077 //Generate VPN label for the external IP
1078 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
1079 .setIpPrefix(externalIp).build();
1080 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
1082 //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
1083 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
1084 if (result.isSuccessful()) {
1085 LOG.debug("advToBgpAndInstallFibAndTsFlows : inside apply with result success");
1086 GenerateVpnLabelOutput output = result.getResult();
1087 final long label = output.getLabel();
1089 int externalIpInDsFlag = 0;
1090 //Get IPMaps from the DB for the router ID
1091 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
1092 for (IpMap dbIpMap : dbIpMaps) {
1093 String dbExternalIp = dbIpMap.getExternalIp();
1094 //Select the IPMap, whose external IP is the IP for which FIB is installed
1095 if (dbExternalIp.contains(externalIp)) {
1096 String dbInternalIp = dbIpMap.getInternalIp();
1097 IpMapKey dbIpMapKey = dbIpMap.key();
1098 LOG.debug("advToBgpAndInstallFibAndTsFlows : Setting label {} for internalIp {} "
1099 + "and externalIp {}", label, dbInternalIp, externalIp);
1100 IpMap newIpm = new IpMapBuilder().withKey(dbIpMapKey).setInternalIp(dbInternalIp)
1101 .setExternalIp(dbExternalIp).setLabel(label).build();
1102 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1103 naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
1104 externalIpInDsFlag++;
1107 if (externalIpInDsFlag <= 0) {
1108 LOG.debug("advToBgpAndInstallFibAndTsFlows : External Ip {} not found in DS, "
1109 + "Failed to update label {} for routerId {} in DS",
1110 externalIp, label, routerId);
1111 String errMsg = String.format("Failed to update label %s due to external Ip %s not"
1112 + " found in DS for router %s", label, externalIp, routerId);
1113 return Futures.immediateFailedFuture(new Exception(errMsg));
1117 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1118 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni).longValue();
1120 Routers extRouter = router != null ? router :
1121 NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1122 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
1123 externalIp, nextHopIp, extRouter.getNetworkId().getValue(), null, label, l3vni,
1124 RouteOrigin.STATIC, dpnId);
1126 //Install custom FIB routes
1127 List<Instruction> tunnelTableCustomInstructions = new ArrayList<>();
1128 tunnelTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
1129 makeTunnelTableEntry(dpnId, label, l3vni, tunnelTableCustomInstructions, confTx,
1131 makeLFibTableEntry(dpnId, label, tableId, confTx);
1133 //Install custom FIB routes - FIB table.
1134 List<Instruction> fibTableCustomInstructions = createFibTableCustomInstructions(tableId,
1135 routerName, externalIp);
1136 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1137 //Install the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
1138 NatUtil.makePreDnatToSnatTableEntry(mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, confTx);
1140 String externalVpn = vpnName;
1141 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp, extRouter);
1142 if (extNwProvType == ProviderTypes.VLAN || extNwProvType == ProviderTypes.FLAT) {
1143 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
1145 if (externalSubnet.isPresent()) {
1146 externalVpn = externalSubnetId.getValue();
1149 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1150 CreateFibEntryInput input = new CreateFibEntryInputBuilder()
1151 .setVpnName(externalVpn)
1152 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
1153 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
1154 .setInstruction(fibTableCustomInstructions).build();
1155 return fibService.createFibEntry(input);
1157 LOG.error("advToBgpAndInstallFibAndTsFlows : inside apply with result failed");
1158 String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
1159 externalIp, vpnName, result.getErrors());
1160 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1162 }, MoreExecutors.directExecutor());
1164 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
1167 public void onFailure(@NonNull Throwable error) {
1168 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in generate label or fib install process", error);
1172 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
1173 if (result.isSuccessful()) {
1174 LOG.info("advToBgpAndInstallFibAndTsFlows : Successfully installed custom FIB routes for prefix {}",
1177 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in rpc call to create custom Fib entries "
1178 + "for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
1181 }, MoreExecutors.directExecutor());
1184 private List<Instruction> createFibTableCustomInstructions(short tableId, String routerName,
1185 String externalIp) {
1186 List<Instruction> fibTableCustomInstructions = new ArrayList<>();
1187 Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1188 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
1189 externalIp, router);
1190 int instructionIndex = 0;
1191 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
1192 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
1193 fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
1194 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
1198 fibTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(instructionIndex));
1199 return fibTableCustomInstructions;
1202 private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId,
1203 TypedWriteTransaction<Configuration> confTx) {
1204 List<MatchInfo> matches = new ArrayList<>();
1205 matches.add(MatchEthernetType.MPLS_UNICAST);
1206 matches.add(new MatchMplsLabel(serviceId));
1208 List<Instruction> instructions = new ArrayList<>();
1209 List<ActionInfo> actionsInfos = new ArrayList<>();
1210 //NAT is required for IPv4 only. Hence always etherType will be IPv4
1211 actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
1212 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
1213 instructions.add(writeInstruction);
1214 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
1216 // Install the flow entry in L3_LFIB_TABLE
1217 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1219 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1221 COOKIE_VM_LFIB_TABLE, matches, instructions);
1223 mdsalManager.addFlow(confTx, dpId, flowEntity);
1225 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
1228 private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, long l3Vni,
1229 List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx,
1230 ProviderTypes extNwProvType) {
1232 List<MatchInfo> mkMatches = new ArrayList<>();
1234 LOG.debug("makeTunnelTableEntry : DpnId = {} and serviceId = {} and actions = {}",
1235 dpnId, serviceId, customInstructions);
1237 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1238 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
1240 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
1243 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1244 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5,
1245 String.format("%s:%d", "TST Flow Entry ", serviceId),
1246 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1248 mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
1251 protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1252 return InstanceIdentifier.builder(RouterIdName.class).child(RouterIds.class,
1253 new RouterIdsKey(routerId)).build();
1256 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1257 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
1258 .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
1262 protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1263 String routerName = original.getRouterName();
1264 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1265 if (routerId == NatConstants.INVALID_ID) {
1266 LOG.error("update : external router event - Invalid routerId for routerName {}", routerName);
1269 // Check if its update on SNAT flag
1270 boolean originalSNATEnabled = original.isEnableSnat();
1271 boolean updatedSNATEnabled = update.isEnableSnat();
1272 LOG.debug("update :called with originalFlag and updatedFlag for SNAT enabled "
1273 + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
1274 /* Get Primary Napt Switch for existing router from "router-to-napt-switch" DS.
1275 * if dpnId value is null or zero then go for electing new Napt switch for existing router.
1277 long bgpVpnId = NatConstants.INVALID_ID;
1278 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1279 if (bgpVpnUuid != null) {
1280 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1282 BigInteger dpnId = getPrimaryNaptSwitch(routerName);
1283 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1284 // Router has no interface attached
1287 final long finalBgpVpnId = bgpVpnId;
1288 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + update.key(), () -> {
1289 List<ListenableFuture<Void>> futures = new ArrayList<>();
1290 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeFlowInvTx -> {
1291 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, removeFlowInvTx -> {
1292 Uuid networkId = original.getNetworkId();
1293 if (originalSNATEnabled != updatedSNATEnabled) {
1294 if (originalSNATEnabled) {
1295 //SNAT disabled for the router
1296 Uuid networkUuid = original.getNetworkId();
1297 LOG.info("update : SNAT disabled for Router {}", routerName);
1298 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1299 handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId, routerId,
1302 LOG.info("update : SNAT enabled for Router {}", original.getRouterName());
1303 addOrDelDefFibRouteToSNAT(routerName, routerId, finalBgpVpnId, bgpVpnUuid,
1304 true, writeFlowInvTx);
1305 handleEnableSnat(original, routerId, dpnId, finalBgpVpnId, removeFlowInvTx);
1308 if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1309 NatUtil.installRouterGwFlows(txRunner, vpnManager, original, dpnId, NwConstants.DEL_FLOW);
1310 NatUtil.installRouterGwFlows(txRunner, vpnManager, update, dpnId, NwConstants.ADD_FLOW);
1313 //Check if the Update is on External IPs
1314 LOG.debug("update : Checking if this is update on External IPs");
1315 List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
1316 List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
1318 //Check if the External IPs are added during the update.
1319 Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
1320 addedExternalIps.removeAll(originalExternalIps);
1321 if (addedExternalIps.size() != 0) {
1322 LOG.debug("update : Start processing of the External IPs addition during the update "
1324 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
1325 update.getExtGwMacAddress(), dpnId,
1326 update.getNetworkId());
1328 for (String addedExternalIp : addedExternalIps) {
1330 1) Do nothing in the IntExtIp model.
1331 2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1333 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1334 String externalIp = externalIpParts[0];
1335 String externalIpPrefix = externalIpParts[1];
1336 String externalpStr = externalIp + "/" + externalIpPrefix;
1337 LOG.debug("update : Initialise the count mapping of the external IP {} for the "
1338 + "router ID {} in the ExternalIpsCounter model.",
1339 externalpStr, routerId);
1340 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1343 "update : End processing of the External IPs addition during the update operation");
1346 //Check if the External IPs are removed during the update.
1347 Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
1348 removedExternalIps.removeAll(updatedExternalIps);
1349 if (removedExternalIps.size() > 0) {
1350 LOG.debug("update : Start processing of the External IPs removal during the update "
1352 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
1353 removedExternalIps, original.getExtGwMacAddress(),
1356 for (String removedExternalIp : removedExternalIps) {
1358 1) Remove the mappings in the IntExt IP model which has external IP.
1359 2) Remove the external IP in the ExternalCounter model.
1360 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the
1361 least loaded external IP.
1362 Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1363 4) Increase the count of the allocated external IP by one.
1364 5) Advertise to the BGP if external IP is allocated for the first time for the router
1365 i.e. the route for the external IP is absent.
1366 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for
1367 the removed external IPs and also from the model.
1368 7) Advertise to the BGP for removing the route for the removed external IPs.
1371 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1372 String externalIp = externalIpParts[0];
1373 String externalIpPrefix = externalIpParts[1];
1374 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1376 LOG.debug("update : Clear the routes from the BGP and remove the FIB and TS "
1377 + "entries for removed external IP {}", externalIpAddrStr);
1378 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1379 String vpnName = "";
1380 if (vpnUuId != null) {
1381 vpnName = vpnUuId.getValue();
1383 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName, networkId,
1384 update.getExtGwMacAddress(), removeFlowInvTx);
1386 LOG.debug("update : Remove the mappings in the IntExtIP model which has external IP.");
1387 //Get the internal IPs which are associated to the removed external IPs
1388 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1389 List<String> removedInternalIps = new ArrayList<>();
1390 for (IpMap ipMap : ipMaps) {
1391 if (ipMap.getExternalIp().equals(externalIpAddrStr)) {
1392 removedInternalIps.add(ipMap.getInternalIp());
1396 LOG.debug("update : Remove the mappings of the internal IPs from the IntExtIP model.");
1397 for (String removedInternalIp : removedInternalIps) {
1398 LOG.debug("update : Remove the IP mapping of the internal IP {} for the "
1399 + "router ID {} from the IntExtIP model",
1400 removedInternalIp, routerId);
1401 naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1404 LOG.debug("update : Remove the count mapping of the external IP {} for the "
1405 + "router ID {} from the ExternalIpsCounter model.",
1406 externalIpAddrStr, routerId);
1407 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1409 LOG.debug("update : Allocate the least loaded external IPs to the subnets "
1410 + "whose external IPs were removed.");
1411 for (String removedInternalIp : removedInternalIps) {
1412 allocateExternalIp(dpnId, update, routerId, routerName, networkId,
1413 removedInternalIp, writeFlowInvTx);
1415 LOG.debug("update : Remove the NAPT translation entries from "
1416 + "Inbound and Outbound NAPT tables for the removed external IPs.");
1417 //Get the internalIP and internal Port which were associated to the removed external IP.
1418 List<Integer> externalPorts = new ArrayList<>();
1419 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1420 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier
1421 .builder(IntextIpPortMap.class)
1422 .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1423 Optional<IpPortMapping> ipPortMapping;
1425 ipPortMapping = SingleTransactionDataBroker
1426 .syncReadOptional(dataBroker,
1427 LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1428 } catch (ReadFailedException e) {
1429 LOG.error("Failed to read ipPortMapping for router id {}", routerId, e);
1430 ipPortMapping = Optional.absent();
1433 if (ipPortMapping.isPresent()) {
1434 for (IntextIpProtocolType intextIpProtocolType :
1435 ipPortMapping.get().nonnullIntextIpProtocolType()) {
1436 ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1437 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
1438 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1439 if (ipPortExternal.getIpAddress().equals(externalIp)) {
1440 externalPorts.add(ipPortExternal.getPortNum());
1441 List<String> removedInternalIpPorts =
1442 protoTypesIntIpPortsMap.get(protoType);
1443 if (removedInternalIpPorts != null) {
1444 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1445 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1447 removedInternalIpPorts = new ArrayList<>();
1448 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1449 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1456 //Remove the IP port map from the intext-ip-port-map model, which were containing
1457 // the removed external IP.
1458 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts =
1459 protoTypesIntIpPortsMap.entrySet();
1460 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1461 for (Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts) {
1462 ProtocolTypes protocolType = (ProtocolTypes) protoTypesIntIpPort.getKey();
1463 List<String> removedInternalIpPorts = (List<String>) protoTypesIntIpPort.getValue();
1464 for (String removedInternalIpPort : removedInternalIpPorts) {
1465 // Remove the IP port map from the intext-ip-port-map model,
1466 // which were containing the removed external IP
1467 naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort,
1469 //Remove the IP port incomint packer map.
1470 naptPacketInHandler.removeIncomingPacketMap(
1471 routerId + NatConstants.COLON_SEPARATOR + removedInternalIpPort);
1472 String[] removedInternalIpPortParts = removedInternalIpPort
1473 .split(NatConstants.COLON_SEPARATOR);
1474 if (removedInternalIpPortParts.length == 2) {
1475 String removedInternalIp = removedInternalIpPortParts[0];
1476 String removedInternalPort = removedInternalIpPortParts[1];
1477 List<String> removedInternalPortsList =
1478 internalIpPortMap.get(removedInternalPort);
1479 if (removedInternalPortsList != null) {
1480 removedInternalPortsList.add(removedInternalPort);
1481 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1483 removedInternalPortsList = new ArrayList<>();
1484 removedInternalPortsList.add(removedInternalPort);
1485 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1491 // Delete the entry from SnatIntIpPortMap DS
1492 Set<String> internalIps = internalIpPortMap.keySet();
1493 for (String internalIp : internalIps) {
1494 LOG.debug("update : Removing IpPort having the internal IP {} from the "
1495 + "model SnatIntIpPortMap", internalIp);
1496 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1499 naptManager.removeNaptPortPool(externalIp);
1501 LOG.debug("update : Remove the NAPT translation entries from Inbound NAPT tables for "
1502 + "the removed external IP {}", externalIp);
1503 for (Integer externalPort : externalPorts) {
1504 //Remove the NAPT translation entries from Inbound NAPT table
1505 naptEventHandler.removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1506 routerId, externalIp, externalPort);
1509 Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
1510 for (Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
1511 String internalIp = internalIpPort.getKey();
1512 LOG.debug("update : Remove the NAPT translation entries from Outbound NAPT tables "
1513 + "for the removed internal IP {}", internalIp);
1514 List<String> internalPorts = internalIpPort.getValue();
1515 for (String internalPort : internalPorts) {
1516 //Remove the NAPT translation entries from Outbound NAPT table
1517 naptPacketInHandler.removeIncomingPacketMap(
1518 routerId + NatConstants.COLON_SEPARATOR + internalIp
1519 + NatConstants.COLON_SEPARATOR + internalPort);
1520 naptEventHandler.removeNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1521 routerId, internalIp, Integer.parseInt(internalPort));
1526 "update : End processing of the External IPs removal during the update operation");
1529 //Check if its Update on subnets
1530 LOG.debug("update : Checking if this is update on subnets");
1531 List<Uuid> originalSubnetIds = original.getSubnetIds();
1532 List<Uuid> updatedSubnetIds = update.getSubnetIds();
1533 Set<Uuid> addedSubnetIds =
1534 updatedSubnetIds != null ? new HashSet<>(updatedSubnetIds) : new HashSet<>();
1535 if (originalSubnetIds != null) {
1536 addedSubnetIds.removeAll(originalSubnetIds);
1539 //Check if the Subnet IDs are added during the update.
1540 if (addedSubnetIds.size() != 0) {
1542 "update : Start processing of the Subnet IDs addition during the update operation");
1543 for (Uuid addedSubnetId : addedSubnetIds) {
1545 1) Select the least loaded external IP for the subnet and store the mapping of the
1546 subnet IP and the external IP in the IntExtIp model.
1547 2) Increase the count of the selected external IP by one.
1548 3) Advertise to the BGP if external IP is allocated for the first time for the
1549 router i.e. the route for the external IP is absent.
1551 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1552 if (subnetIp != null) {
1553 allocateExternalIp(dpnId, update, routerId, routerName, networkId, subnetIp,
1557 LOG.debug("update : End processing of the Subnet IDs addition during the update operation");
1560 //Check if the Subnet IDs are removed during the update.
1561 Set<Uuid> removedSubnetIds = new HashSet<>(originalSubnetIds);
1562 removedSubnetIds.removeAll(updatedSubnetIds);
1563 if (removedSubnetIds.size() != 0) {
1565 "update : Start processing of the Subnet IDs removal during the update operation");
1566 for (Uuid removedSubnetId : removedSubnetIds) {
1567 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1568 if (subnetAddr != null) {
1570 1) Remove the subnet IP and the external IP in the IntExtIp map
1571 2) Decrease the count of the coresponding external IP by one.
1572 3) Advertise to the BGP for removing the routes of the corresponding external
1573 IP if its not allocated to any other internal IP.
1576 String externalIp = naptManager.getExternalIpAllocatedForSubnet(routerId,
1577 subnetAddr[0] + "/" + subnetAddr[1]);
1578 if (externalIp == null) {
1579 LOG.error("update : No mapping found for router ID {} and internal IP {}",
1580 routerId, subnetAddr[0]);
1584 naptManager.updateCounter(routerId, externalIp, false);
1585 // Traverse entire model of external-ip counter whether external ip is not
1586 // used by any other internal ip in any router
1587 if (!isExternalIpAllocated(externalIp)) {
1588 LOG.debug("update : external ip is not allocated to any other "
1589 + "internal IP so proceeding to remove routes");
1590 clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId,
1591 Collections.singleton(externalIp), null, update.getExtGwMacAddress(),
1593 LOG.debug("update : Successfully removed fib entries in switch {} for "
1594 + "router {} with networkId {} and externalIp {}",
1595 dpnId, routerId, networkId, externalIp);
1598 LOG.debug("update : Remove the IP mapping for the router ID {} and "
1599 + "internal IP {} external IP {}", routerId, subnetAddr[0], externalIp);
1600 naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1603 LOG.debug("update : End processing of the Subnet IDs removal during the update operation");
1608 }, NatConstants.NAT_DJC_MAX_RETRIES);
1611 private boolean isExternalIpAllocated(String externalIp) {
1612 InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1613 Optional<ExternalIpsCounter> externalCountersData;
1615 externalCountersData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1616 LogicalDatastoreType.OPERATIONAL, id);
1617 } catch (ReadFailedException e) {
1618 LOG.error("Failed to read external counters data for ExternalIp {}", externalIp, e);
1619 externalCountersData = Optional.absent();
1621 if (externalCountersData.isPresent()) {
1622 ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1623 for (ExternalCounters ext : externalIpsCounters.nonnullExternalCounters()) {
1624 for (ExternalIpCounter externalIpCount : ext.nonnullExternalIpCounter()) {
1625 if (externalIpCount.getExternalIp().equals(externalIp)) {
1626 if (externalIpCount.getCounter() != 0) {
1637 private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
1638 Uuid networkId, String subnetIp, TypedWriteTransaction<Configuration> writeFlowInvTx) {
1639 String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1641 InetAddress address = InetAddress.getByName(subnetIpParts[0]);
1642 if (address instanceof Inet6Address) {
1643 LOG.debug("allocateExternalIp : Skipping ipv6 address {} for the router {}.", address, routerName);
1646 } catch (UnknownHostException e) {
1647 LOG.error("allocateExternalIp : Invalid ip address {}", subnetIpParts[0], e);
1650 String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1651 if (leastLoadedExtIpAddr != null) {
1652 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1653 String leastLoadedExtIp = externalIpParts[0];
1654 String leastLoadedExtIpPrefix = externalIpParts[1];
1655 IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1656 subnetIp = subnetIpParts[0];
1657 String subnetIpPrefix = subnetIpParts[1];
1658 IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1659 LOG.debug("allocateExternalIp : Add the IP mapping for the router ID {} and internal "
1660 + "IP {} and prefix {} -> external IP {} and prefix {}",
1661 routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1662 naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1665 // Check if external IP is already assigned a route. (i.e. External IP is previously
1666 // allocated to any of the subnets)
1667 // If external IP is already assigned a route, (, do not re-advertise to the BGP
1668 String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1669 Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1670 if (label != null) {
1672 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1673 IpMapKey ipMapKey = new IpMapKey(internalIp);
1674 LOG.debug("allocateExternalIp : Setting label {} for internalIp {} and externalIp {}",
1675 label, internalIp, leastLoadedExtIpAddrStr);
1676 IpMap newIpm = new IpMapBuilder().withKey(ipMapKey).setInternalIp(internalIp)
1677 .setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1678 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1679 naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1683 // Re-advertise to the BGP for the external IP, which is allocated to the subnet
1684 // for the first time and hence not having a route.
1685 //Get the VPN Name using the network ID
1686 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1687 if (vpnName != null) {
1688 LOG.debug("allocateExternalIp : Retrieved vpnName {} for networkId {}", vpnName, networkId);
1689 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1690 LOG.debug("allocateExternalIp : Best effort for getting primary napt switch when router i/f are"
1691 + "added after gateway-set");
1692 dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1693 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1694 LOG.error("allocateExternalIp : dpnId is null or Zero for the router {}", routerName);
1698 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1699 leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, networkId, router,
1706 protected Long checkExternalIpLabel(long routerId, String externalIp) {
1707 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1708 for (IpMap ipMap : ipMaps) {
1709 if (ipMap.getExternalIp().equals(externalIp)) {
1710 if (ipMap.getLabel() != null) {
1711 return ipMap.getLabel();
1715 LOG.error("checkExternalIpLabel : no ipMaps found for routerID:{} and externalIP:{}", routerId, externalIp);
1720 protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1721 LOG.trace("remove : Router delete method");
1723 ROUTER DELETE SCENARIO
1724 1) Get the router ID from the event.
1725 2) Build the cookie information from the router ID.
1726 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1727 4) Build the flow with the cookie value.
1728 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1729 6) Remove the flows from the other switches which points to the primary and secondary
1730 switches for the flows related the router ID.
1731 7) Get the list of external IP address maintained for the router ID.
1732 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1733 9) Withdraw the corresponding routes from the BGP.
1736 if (identifier == null || router == null) {
1737 LOG.error("remove : returning without processing since routers is null");
1741 String routerName = router.getRouterName();
1742 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.key(),
1743 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
1744 LOG.info("remove : Removing default NAT route from FIB on all dpns part of router {} ",
1746 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1747 if (routerId == NatConstants.INVALID_ID) {
1748 LOG.error("remove : Remove external router event - Invalid routerId for routerName {}",
1752 long bgpVpnId = NatConstants.INVALID_ID;
1753 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1754 if (bgpVpnUuid != null) {
1755 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1757 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, false,
1759 Uuid networkUuid = router.getNetworkId();
1761 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1762 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
1763 // No NAPT switch for external router, probably because the router is not attached to
1765 // internal networks
1767 "No NAPT switch for router {}, check if router is attached to any internal "
1772 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1773 handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId,
1776 natOverVxlanUtil.releaseVNI(routerName);
1777 })), NatConstants.NAT_DJC_MAX_RETRIES);
1780 public void handleDisableSnat(Routers router, Uuid networkUuid, @NonNull Collection<String> externalIps,
1781 boolean routerFlag, @Nullable String vpnName, BigInteger naptSwitchDpnId,
1782 long routerId, TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
1783 LOG.info("handleDisableSnat : Entry");
1784 String routerName = router.getRouterName();
1787 removeNaptSwitch(routerName);
1789 updateNaptSwitch(routerName, BigInteger.ZERO);
1792 LOG.debug("handleDisableSnat : Remove the ExternalCounter model for the router ID {}", routerId);
1793 naptManager.removeExternalCounter(routerId);
1795 LOG.debug("handleDisableSnat : got primarySwitch as dpnId {}", naptSwitchDpnId);
1796 if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
1797 LOG.error("handleDisableSnat : Unable to retrieve the primary NAPT switch for the "
1798 + "router ID {} from RouterNaptSwitch model", routerId);
1801 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
1803 if (extNwProvType == null) {
1804 LOG.error("handleDisableSnat : External Network Provider Type missing");
1807 Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps());
1808 removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnName, externalIps,
1809 externalSubnetList, removeFlowInvTx, extNwProvType);
1810 removeFlowsFromNonActiveSwitches(routerId, routerName, naptSwitchDpnId, removeFlowInvTx);
1811 String externalSubnetVpn = null;
1812 for (Uuid externalSubnetId : externalSubnetList) {
1813 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, externalSubnetId);
1814 // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
1815 if (externalSubnet.isPresent()) {
1816 externalSubnetVpn = externalSubnetId.getValue();
1817 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, externalSubnetVpn,
1818 router.getExtGwMacAddress(), removeFlowInvTx);
1821 if (externalSubnetVpn == null) {
1822 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnName,
1823 router.getExtGwMacAddress(), removeFlowInvTx);
1825 // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
1826 // for the router ID.
1827 LOG.debug("handleDisableSnat : Remove the Internal to external IP address maintained for the "
1828 + "router ID {} in the DS", routerId);
1829 naptManager.removeMapping(routerId);
1830 } catch (InterruptedException | ExecutionException e) {
1831 LOG.error("handleDisableSnat : Exception while handling disableSNAT for router :{}", routerName, e);
1833 LOG.info("handleDisableSnat : Exit");
1836 // TODO Clean up the exception handling
1837 @SuppressWarnings("checkstyle:IllegalCatch")
1838 public void handleDisableSnatInternetVpn(String routerName, long routerId, Uuid networkUuid,
1839 @NonNull Collection<String> externalIps,
1840 String vpnId, TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
1841 LOG.debug("handleDisableSnatInternetVpn: Started to process handle disable snat for router {} "
1842 + "with internet vpn {}", routerName, vpnId);
1844 BigInteger naptSwitchDpnId = null;
1845 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
1846 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1847 Optional<RouterToNaptSwitch> rtrToNapt;
1849 rtrToNapt = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1850 LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1851 } catch (ReadFailedException e) {
1852 LOG.error("Failed to read NAPT switch for router {}", routerName, e);
1853 rtrToNapt = Optional.absent();
1855 if (rtrToNapt.isPresent()) {
1856 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1858 LOG.debug("handleDisableSnatInternetVpn : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1860 removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId,
1863 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1864 if (extGwMacAddress != null) {
1865 LOG.debug("handleDisableSnatInternetVpn : External Gateway MAC address {} found for "
1866 + "External Router ID {}", extGwMacAddress, routerId);
1868 LOG.error("handleDisableSnatInternetVpn : No External Gateway MAC address found for "
1869 + "External Router ID {}", routerId);
1872 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId, extGwMacAddress,
1874 } catch (Exception ex) {
1875 LOG.error("handleDisableSnatInternetVpn : Failed to remove fib entries for routerId {} "
1876 + "in naptSwitchDpnId {}", routerId, naptSwitchDpnId, ex);
1878 natOverVxlanUtil.releaseVNI(vpnId);
1879 } catch (InterruptedException | ExecutionException e) {
1880 LOG.error("handleDisableSnatInternetVpn: Exception while handling disableSNATInternetVpn for router {} "
1881 + "with internet vpn {}", routerName, vpnId, e);
1883 LOG.debug("handleDisableSnatInternetVpn: Processed handle disable snat for router {} with internet vpn {}",
1887 // TODO Clean up the exception handling
1888 @SuppressWarnings("checkstyle:IllegalCatch")
1889 public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1890 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
1891 .setPrimarySwitchId(naptSwitchId).build();
1893 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1894 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1895 } catch (Exception ex) {
1896 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
1897 naptSwitchId, routerName);
1899 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
1900 naptSwitchId, routerName);
1903 protected void removeNaptSwitch(String routerName) {
1904 // Remove router and switch from model
1905 InstanceIdentifier<RouterToNaptSwitch> id =
1906 InstanceIdentifier.builder(NaptSwitches.class)
1907 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1908 LOG.debug("removeNaptSwitch : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1909 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1910 //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
1911 NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
1914 public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
1915 BigInteger dpnId, Uuid networkId, String vpnName,
1916 @NonNull Collection<String> externalIps,
1917 Collection<Uuid> externalSubnetList,
1918 TypedReadWriteTransaction<Configuration> confTx,
1919 ProviderTypes extNwProvType)
1920 throws InterruptedException, ExecutionException {
1922 LOG.debug("removeNaptFlowsFromActiveSwitch : Remove NAPT flows from Active switch");
1923 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1925 //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1926 // traffic which comes from the VMs of the NAPT switches)
1927 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1928 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1931 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1932 + "and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
1933 mdsalManager.removeFlow(confTx, preSnatFlowEntity);
1935 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1936 // traffic which comes from the VMs of the non NAPT switches)
1937 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
1938 elanManager, idManager, routerId, routerName);
1939 String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
1940 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1942 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1943 + "and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
1944 mdsalManager.removeFlow(confTx, tsNatFlowEntity);
1946 //Remove the flow table 25->44 from NAPT Switch
1947 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1948 NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, dpnId);
1951 //Remove the Outbound flow entry which forwards the packet to FIB Table
1953 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {}"
1954 + " and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1956 String outboundTcpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1957 NwConstants.IP_PROT_TCP);
1958 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1959 outboundTcpNatFlowRef);
1960 mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
1962 String outboundUdpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1963 NwConstants.IP_PROT_UDP);
1964 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1965 outboundUdpNatFlowRef);
1966 mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
1968 String icmpDropFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1969 NwConstants.IP_PROT_ICMP);
1970 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1972 mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
1973 boolean lastRouterOnExternalNetwork =
1974 !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker, networkId, routerName, dpnId);
1975 if (lastRouterOnExternalNetwork) {
1976 removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps, confTx);
1978 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
1979 // External Subnet Vpn Id.
1980 for (Uuid externalSubnetId : externalSubnetList) {
1981 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
1982 if (subnetVpnId != -1 && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
1983 dataBroker, externalSubnetId, routerName, dpnId)) {
1984 String natPfibSubnetFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
1985 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE,
1986 natPfibSubnetFlowRef);
1987 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
1988 LOG.debug("removeNaptFlowsFromActiveSwitch : Removed the flow in table {} with external subnet "
1989 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
1990 subnetVpnId, dpnId);
1994 //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1995 String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1996 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1999 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
2000 + "and router ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
2001 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
2003 if (lastRouterOnExternalNetwork) {
2004 // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
2005 // - This does not work since ext-routers is deleted already - no network info
2006 //Get the VPN ID from the ExternalNetworks model
2008 if (vpnName == null || vpnName.isEmpty()) {
2009 // ie called from router delete cases
2010 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
2011 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnUuid is {}", vpnUuid);
2012 if (vpnUuid != null) {
2013 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2014 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId {} for external network {} router delete "
2015 + "or disableSNAT scenario", vpnId, networkId);
2018 // ie called from disassociate vpn case
2019 LOG.debug("removeNaptFlowsFromActiveSwitch : This is disassociate nw with vpn case with vpnName {}",
2021 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2022 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId for disassociate nw with vpn scenario {}",
2026 if (vpnId != NatConstants.INVALID_ID) {
2027 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2028 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2029 FlowEntity natPfibVpnFlowEntity =
2030 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2031 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in {} for the active switch with the "
2032 + "DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2033 mdsalManager.removeFlow(confTx, natPfibVpnFlowEntity);
2037 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2038 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2039 if (ipPortMapping == null) {
2040 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the IpPortMapping");
2044 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2045 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2046 String ipPortInternal = ipPortMap.getIpPortInternal();
2047 String[] ipPortParts = ipPortInternal.split(":");
2048 if (ipPortParts.length != 2) {
2049 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the Internal IP and port");
2052 String internalIp = ipPortParts[0];
2053 String internalPort = ipPortParts[1];
2055 //Build the flow for the outbound NAPT table
2056 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2057 + NatConstants.COLON_SEPARATOR + internalPort);
2058 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2059 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
2060 FlowEntity outboundNaptFlowEntity =
2061 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2063 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch "
2064 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2065 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
2067 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2068 String externalIp = ipPortExternal.getIpAddress();
2069 int externalPort = ipPortExternal.getPortNum();
2071 //Build the flow for the inbound NAPT table
2072 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2073 String.valueOf(routerId), externalIp, externalPort);
2074 FlowEntity inboundNaptFlowEntity =
2075 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2077 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active active switch "
2078 + "with the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2079 mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
2084 protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
2085 @NonNull Collection<String> externalIps,
2086 TypedReadWriteTransaction<Configuration> writeFlowInvTx)
2087 throws ExecutionException, InterruptedException {
2088 long extVpnId = NatConstants.INVALID_ID;
2089 if (networkId != null) {
2090 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
2091 if (vpnUuid != null) {
2092 extVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2094 LOG.debug("removeNaptFibExternalOutputFlows : vpnUuid is null");
2097 LOG.debug("removeNaptFibExternalOutputFlows : networkId is null");
2098 extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2100 if (extVpnId == NatConstants.INVALID_ID) {
2101 LOG.warn("removeNaptFibExternalOutputFlows : extVpnId not found for routerId {}", routerId);
2102 extVpnId = routerId;
2104 for (String ip : externalIps) {
2105 String extIp = removeMaskFromIp(ip);
2106 String naptFlowRef = getFlowRefNaptPreFib(dpnId, NwConstants.NAPT_PFIB_TABLE, extVpnId);
2107 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in table {} for the active switch"
2108 + " with the DPN ID {} and router ID {} and IP {} flowRef {}",
2109 NwConstants.NAPT_PFIB_TABLE, dpnId, routerId, extIp, naptFlowRef);
2110 FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef);
2111 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2115 private String removeMaskFromIp(String ip) {
2116 if (ip != null && !ip.trim().isEmpty()) {
2117 return ip.split("/")[0];
2122 public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
2123 BigInteger dpnId, Uuid networkId, String vpnName,
2124 TypedReadWriteTransaction<Configuration> writeFlowInvTx)
2125 throws ExecutionException, InterruptedException {
2126 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : Remove NAPT flows from Active switch Internet Vpn");
2127 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
2129 //Remove the NAPT PFIB TABLE entry
2131 if (vpnName != null) {
2132 // ie called from disassociate vpn case
2133 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : This is disassociate nw with vpn case "
2134 + "with vpnName {}", vpnName);
2135 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2136 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : vpnId for disassociate nw with vpn scenario {}",
2140 if (vpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker,
2141 networkId, routerName, dpnId)) {
2142 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2143 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2144 FlowEntity natPfibVpnFlowEntity =
2145 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2146 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the active switch "
2147 + "with the DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2148 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2150 // Remove IP-PORT active NAPT entries and release port from IdManager
2151 // For the router ID get the internal IP , internal port and the corresponding
2152 // external IP and external Port.
2153 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2154 if (ipPortMapping == null) {
2155 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the IpPortMapping");
2158 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2159 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2160 String ipPortInternal = ipPortMap.getIpPortInternal();
2161 String[] ipPortParts = ipPortInternal.split(":");
2162 if (ipPortParts.length != 2) {
2163 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the Internal IP "
2167 String internalIp = ipPortParts[0];
2168 String internalPort = ipPortParts[1];
2170 //Build the flow for the outbound NAPT table
2171 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2172 + NatConstants.COLON_SEPARATOR + internalPort);
2173 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2174 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
2175 FlowEntity outboundNaptFlowEntity =
2176 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2178 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2179 + "active switch with the DPN ID {} and router ID {}",
2180 NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2181 mdsalManager.removeFlow(writeFlowInvTx, outboundNaptFlowEntity);
2183 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2184 String externalIp = ipPortExternal.getIpAddress();
2185 int externalPort = ipPortExternal.getPortNum();
2187 //Build the flow for the inbound NAPT table
2188 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2189 String.valueOf(routerId), externalIp, externalPort);
2190 FlowEntity inboundNaptFlowEntity =
2191 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2193 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2194 + "active active switch with the DPN ID {} and router ID {}",
2195 NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2196 mdsalManager.removeFlow(writeFlowInvTx, inboundNaptFlowEntity);
2198 // Finally release port from idmanager
2199 String internalIpPort = internalIp + ":" + internalPort;
2200 naptManager.removePortFromPool(internalIpPort, externalIp);
2202 //Remove sessions from models
2203 naptManager.removeIpPortMappingForRouterID(routerId);
2204 naptManager.removeIntIpPortMappingForRouterID(routerId);
2208 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Invalid vpnId {}", vpnId);
2212 public void removeFlowsFromNonActiveSwitches(long routerId, String routerName,
2213 BigInteger naptSwitchDpnId, TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2214 throws ExecutionException, InterruptedException {
2215 LOG.debug("removeFlowsFromNonActiveSwitches : Remove NAPT related flows from non active switches");
2217 // Remove the flows from the other switches which points to the primary and secondary switches
2218 // for the flows related the router ID.
2219 List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
2220 if (allSwitchList.isEmpty()) {
2221 LOG.error("removeFlowsFromNonActiveSwitches : Unable to get the swithces for the router {}", routerName);
2224 for (BigInteger dpnId : allSwitchList) {
2225 if (!naptSwitchDpnId.equals(dpnId)) {
2226 LOG.info("removeFlowsFromNonActiveSwitches : Handle Ordinary switch");
2228 //Remove the PSNAT entry which forwards the packet to Terminating Service table
2229 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
2230 FlowEntity preSnatFlowEntity =
2231 NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
2233 LOG.info("removeFlowsFromNonActiveSwitches : Remove the flow in the {} for the non active switch "
2234 + "with the DPN ID {} and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
2235 mdsalManager.removeFlow(removeFlowInvTx, preSnatFlowEntity);
2237 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
2238 long groupId = createGroupId(getGroupIdKey(routerName));
2240 LOG.info("removeFlowsFromNonActiveSwitches : Remove the group {} for the non active switch with "
2241 + "the DPN ID {} and router ID {}", groupId, dpnId, routerId);
2242 mdsalManager.removeGroup(removeFlowInvTx, dpnId, groupId);
2247 public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, @Nullable Uuid networkUuid,
2248 @NonNull Collection<String> externalIps, @Nullable String vpnName,
2249 String extGwMacAddress, TypedReadWriteTransaction<Configuration> confTx)
2250 throws ExecutionException, InterruptedException {
2251 //Withdraw the corresponding routes from the BGP.
2252 //Get the network ID using the router ID.
2253 LOG.debug("clrRtsFromBgpAndDelFibTs : Advertise to BGP and remove routes for externalIps {} with routerId {},"
2254 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2255 if (networkUuid == null) {
2256 LOG.error("clrRtsFromBgpAndDelFibTs : networkId is null");
2260 if (externalIps.isEmpty()) {
2261 LOG.error("clrRtsFromBgpAndDelFibTs : externalIps is empty");
2265 if (vpnName == null) {
2266 //Get the VPN Name using the network ID
2267 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2268 if (vpnName == null) {
2269 LOG.error("clrRtsFromBgpAndDelFibTs : No VPN associated with ext nw {} for the router {}",
2270 networkUuid, routerId);
2274 LOG.debug("clrRtsFromBgpAndDelFibTs : Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2276 //Remove custom FIB routes
2277 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2278 for (String extIp : externalIps) {
2279 clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, confTx);
2283 protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2284 final Uuid networkUuid, String extGwMacAddress,
2285 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2286 throws ExecutionException, InterruptedException {
2287 clearBgpRoutes(extIp, vpnName);
2288 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2292 protected void delFibTsAndReverseTraffic(final BigInteger dpnId, String routerName, long routerId, String extIp,
2293 String vpnName, Uuid extNetworkId, long tempLabel,
2294 String gwMacAddress, boolean switchOver,
2295 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2296 throws ExecutionException, InterruptedException {
2297 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2298 //String routerName = NatUtil.getRouterName(dataBroker,routerId);
2299 if (routerName == null) {
2300 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2303 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
2304 if (extNwProvType == null) {
2305 LOG.error("delFibTsAndReverseTraffic : External Network Provider Type Missing");
2308 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2309 * external network provided type is VxLAN
2311 if (extNwProvType == ProviderTypes.VXLAN) {
2312 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, gwMacAddress
2316 if (tempLabel < 0) {
2317 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2321 final long label = tempLabel;
2322 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2323 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
2324 LOG.debug("delFibTsAndReverseTraffic : Using extSubnetId as vpnName for FLAT/VLAN use-cases");
2325 Routers extRouter = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
2326 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp,
2329 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
2332 if (externalSubnet.isPresent()) {
2333 vpnName = externalSubnetId.getValue();
2336 final String externalVpn = vpnName;
2337 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(externalVpn)
2338 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label)
2339 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
2340 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2342 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2343 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2344 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2345 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2346 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2349 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2350 Futures.transformAsync(future, result -> {
2352 if (result.isSuccessful()) {
2353 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2354 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2355 .setVpnName(externalVpn).setIpPrefix(externalIp).build();
2356 return vpnService.removeVpnLabel(labelInput);
2359 String.format("RPC call to remove custom FIB entries on dpn %s for "
2360 + "prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
2362 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2364 }, MoreExecutors.directExecutor());
2366 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2369 public void onFailure(@NonNull Throwable error) {
2370 LOG.error("delFibTsAndReverseTraffic : Error in removing the label:{} or custom fib entries"
2371 + "got external ip {}", label, extIp, error);
2375 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
2376 if (result.isSuccessful()) {
2377 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2378 + "from VPN {}", externalIp, externalVpn);
2380 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2381 + " from VPN {}, {}", externalIp, externalVpn, result.getErrors());
2384 }, MoreExecutors.directExecutor());
2386 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2387 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2391 private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2392 final Uuid networkUuid, String extGwMacAddress, boolean switchOver,
2393 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2394 throws ExecutionException, InterruptedException {
2395 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2396 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2397 if (routerName == null) {
2398 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2401 //Get the external network provider type from networkId
2402 ProviderTypes extNwProvType = NatUtil.getProviderTypefromNetworkId(dataBroker, networkUuid);
2403 if (extNwProvType == null) {
2404 LOG.error("delFibTsAndReverseTraffic : Could not retrieve provider type for external network {} ",
2408 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2409 * external network provided type is VxLAN
2411 if (extNwProvType == ProviderTypes.VXLAN) {
2412 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, extGwMacAddress);
2415 //Get IPMaps from the DB for the router ID
2416 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
2417 if (dbIpMaps.isEmpty()) {
2418 LOG.error("delFibTsAndReverseTraffic : IPMaps not found for router {}", routerId);
2422 long tempLabel = NatConstants.INVALID_ID;
2423 for (IpMap dbIpMap : dbIpMaps) {
2424 String dbExternalIp = dbIpMap.getExternalIp();
2425 LOG.debug("delFibTsAndReverseTraffic : Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
2426 //Select the IPMap, whose external IP is the IP for which FIB is installed
2427 if (extIp.equals(dbExternalIp)) {
2428 tempLabel = dbIpMap.getLabel();
2429 LOG.debug("delFibTsAndReverseTraffic : Retrieved label {} for dbExternalIp {} with router id {}",
2430 tempLabel, dbExternalIp, routerId);
2434 if (tempLabel == NatConstants.INVALID_ID) {
2435 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2440 final long label = tempLabel;
2441 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2442 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
2443 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp)
2444 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).setServiceId(label).build();
2445 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2447 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2448 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2449 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2450 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2451 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2454 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2455 Futures.transformAsync(future, result -> {
2457 if (result.isSuccessful()) {
2458 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2459 .setVpnName(vpnName).setIpPrefix(externalIp).build();
2460 return vpnService.removeVpnLabel(labelInput);
2463 String.format("RPC call to remove custom FIB entries on dpn %s for "
2464 + "prefix %s Failed - %s",
2465 dpnId, externalIp, result.getErrors());
2467 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2469 }, MoreExecutors.directExecutor());
2471 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2474 public void onFailure(@NonNull Throwable error) {
2475 LOG.error("delFibTsAndReverseTraffic : Error in removing the label or custom fib entries", error);
2479 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
2480 if (result.isSuccessful()) {
2481 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2482 + "from VPN {}", externalIp, vpnName);
2484 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2485 + " from VPN {}, {}", externalIp, vpnName, result.getErrors());
2488 }, MoreExecutors.directExecutor());
2490 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2491 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2495 protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2496 List<String> externalIps, @Nullable String vpnName, String extGwMacAddress,
2497 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2498 //Withdraw the corresponding routes from the BGP.
2499 //Get the network ID using the router ID.
2500 LOG.debug("clearFibTsAndReverseTraffic : for externalIps {} with routerId {},"
2501 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2502 if (networkUuid == null) {
2503 LOG.error("clearFibTsAndReverseTraffic : networkId is null");
2507 if (externalIps == null || externalIps.isEmpty()) {
2508 LOG.error("clearFibTsAndReverseTraffic : externalIps is null");
2512 if (vpnName == null) {
2513 //Get the VPN Name using the network ID
2514 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2515 if (vpnName == null) {
2516 LOG.error("clearFibTsAndReverseTraffic : No VPN associated with ext nw {} for the router {}",
2517 networkUuid, routerId);
2521 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2523 //Remove custom FIB routes
2524 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2525 for (String extIp : externalIps) {
2526 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2531 protected void clearBgpRoutes(String externalIp, final String vpnName) {
2532 //Inform BGP about the route removal
2533 LOG.info("clearBgpRoutes : Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
2534 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
2535 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
2538 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId,
2539 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2540 LOG.info("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
2541 mdsalManager.removeFlow(writeFlowInvTx, dpnId,
2542 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), NwConstants.INTERNAL_TUNNEL_TABLE);
2543 LOG.debug("removeTunnelTableEntry : dpID {} : label : {} removed successfully", dpnId, serviceId);
2546 private void removeLFibTableEntry(BigInteger dpnId, long serviceId,
2547 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2548 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2549 LOG.debug("removeLFibTableEntry : with flow ref {}", flowRef);
2550 mdsalManager.removeFlow(writeFlowInvTx, dpnId, flowRef, NwConstants.L3_LFIB_TABLE);
2551 LOG.debug("removeLFibTableEntry : dpID : {} label : {} removed successfully", dpnId, serviceId);
2555 * router association to vpn.
2557 * @param routerName - Name of router
2558 * @param routerId - router id
2559 * @param bgpVpnName BGP VPN name
2561 public void changeLocalVpnIdToBgpVpnId(String routerName, long routerId, String bgpVpnName,
2562 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2563 LOG.debug("changeLocalVpnIdToBgpVpnId : Router associated to BGP VPN");
2564 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2565 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2567 LOG.debug("changeLocalVpnIdToBgpVpnId : BGP VPN ID value {} ", bgpVpnId);
2569 if (bgpVpnId != NatConstants.INVALID_ID) {
2570 LOG.debug("changeLocalVpnIdToBgpVpnId : Populate the router-id-name container with the "
2571 + "mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
2572 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
2573 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2574 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2575 getRoutersIdentifier(bgpVpnId), rtrs);
2577 // Get the allocated Primary NAPT Switch for this router
2578 LOG.debug("changeLocalVpnIdToBgpVpnId : Router ID value {} ", routerId);
2580 LOG.debug("changeLocalVpnIdToBgpVpnId : Update the Router ID {} to the BGP VPN ID {} ",
2581 routerId, bgpVpnId);
2582 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, writeFlowInvTx);
2585 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2586 createGroupId(getGroupIdKey(routerName));
2587 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true, writeFlowInvTx,
2594 * router disassociation from vpn.
2596 * @param routerName - Name of router
2597 * @param routerId - router id
2598 * @param bgpVpnName BGP VPN name
2600 public void changeBgpVpnIdToLocalVpnId(String routerName, long routerId, String bgpVpnName,
2601 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2602 LOG.debug("changeBgpVpnIdToLocalVpnId : Router dissociated from BGP VPN");
2603 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2604 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2605 LOG.debug("changeBgpVpnIdToLocalVpnId : BGP VPN ID value {} ", bgpVpnId);
2607 // Get the allocated Primary NAPT Switch for this router
2608 LOG.debug("changeBgpVpnIdToLocalVpnId : Router ID value {} ", routerId);
2610 LOG.debug("changeBgpVpnIdToLocalVpnId : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2611 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, NatConstants.INVALID_ID, writeFlowInvTx);
2614 createGroupId(getGroupIdKey(routerName));
2615 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2616 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true,
2617 writeFlowInvTx, extNwProvType);
2621 boolean chkExtRtrAndSnatEnbl(Uuid routerUuid) {
2622 InstanceIdentifier<Routers> routerInstanceIndentifier =
2623 InstanceIdentifier.builder(ExtRouters.class)
2624 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
2626 Optional<Routers> routerData = SingleTransactionDataBroker
2627 .syncReadOptional(dataBroker,
2628 LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2629 return routerData.isPresent() && routerData.get().isEnableSnat();
2630 } catch (ReadFailedException e) {
2631 LOG.error("Failed to read data for router id {}", routerUuid, e);
2636 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2637 long routerId, boolean isSnatCfgd, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2639 long changedVpnId = bgpVpnId;
2640 String idType = "BGP VPN";
2641 if (bgpVpnId == NatConstants.INVALID_ID) {
2642 changedVpnId = routerId;
2646 List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2647 if (switches.isEmpty()) {
2648 LOG.error("installFlowsWithUpdatedVpnId : No switches found for router {}", routerName);
2651 for (BigInteger dpnId : switches) {
2652 // Update the BGP VPN ID in the SNAT miss entry to group
2653 if (!dpnId.equals(primarySwitchId)) {
2654 LOG.debug("installFlowsWithUpdatedVpnId : Install group in non NAPT switch {}", dpnId);
2655 List<BucketInfo> bucketInfoForNonNaptSwitches =
2656 getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName, routerId);
2657 long groupId = createGroupId(getGroupIdKey(routerName));
2659 groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
2663 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2664 + "{} in the non NAPT switch {}", idType, changedVpnId, groupId, dpnId);
2665 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
2666 mdsalManager.addFlow(confTx, flowEntity);
2669 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2670 + "in the primary switch {}", idType, changedVpnId, primarySwitchId);
2671 FlowEntity flowEntity =
2672 buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2673 mdsalManager.addFlow(confTx, flowEntity);
2676 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Terminating Service table (table "
2677 + "ID 36) which forwards the packet to the table 46 in the Primary switch {}",
2678 idType, changedVpnId, primarySwitchId);
2679 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, routerId,
2680 changedVpnId, confTx, extNwProvType);
2683 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Outbound NAPT table (table ID 46) "
2684 + "which punts the packet to the controller in the Primary switch {}",
2685 idType, changedVpnId, primarySwitchId);
2686 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2689 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT PFIB TABLE which forwards the"
2690 + " outgoing packet to FIB Table in the Primary switch {}",
2691 idType, changedVpnId, primarySwitchId);
2692 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2695 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT flows for the Outbound NAPT "
2696 + "table (table ID 46) and the INBOUND NAPT table (table ID 44) in the Primary switch"
2697 + " {}", idType, changedVpnId, primarySwitchId);
2698 updateNaptFlowsWithVpnId(primarySwitchId, routerName, routerId, bgpVpnId);
2700 LOG.debug("installFlowsWithUpdatedVpnId : Installing SNAT PFIB flow in the primary switch {}",
2702 Long vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2703 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2704 if (vpnId != NatConstants.INVALID_ID) {
2705 installNaptPfibEntry(primarySwitchId, vpnId, confTx);
2711 public void updateNaptFlowsWithVpnId(BigInteger dpnId, String routerName, long routerId, long bgpVpnId) {
2712 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2713 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2714 if (ipPortMapping == null) {
2715 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the IpPortMapping");
2718 // Get the External Gateway MAC Address
2719 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
2720 if (extGwMacAddress != null) {
2721 LOG.debug("updateNaptFlowsWithVpnId : External Gateway MAC address {} found for External Router ID {}",
2722 extGwMacAddress, routerId);
2724 LOG.error("updateNaptFlowsWithVpnId : No External Gateway MAC address found for External Router ID {}",
2728 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2729 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2730 String ipPortInternal = ipPortMap.getIpPortInternal();
2731 String[] ipPortParts = ipPortInternal.split(":");
2732 if (ipPortParts.length != 2) {
2733 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the Internal IP and port");
2736 String internalIp = ipPortParts[0];
2737 String internalPort = ipPortParts[1];
2738 LOG.debug("updateNaptFlowsWithVpnId : Found Internal IP {} and Internal Port {}",
2739 internalIp, internalPort);
2740 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2741 NAPTEntryEvent.Protocol protocol;
2742 switch (protocolTypes) {
2744 protocol = NAPTEntryEvent.Protocol.TCP;
2747 protocol = NAPTEntryEvent.Protocol.UDP;
2750 protocol = NAPTEntryEvent.Protocol.TCP;
2752 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.parseInt(internalPort));
2753 SessionAddress externalAddress =
2754 naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2755 long internetVpnid = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2756 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
2757 routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
2758 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
2759 routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
2764 public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
2765 long changedVpnId) {
2767 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : called for dpId {}, routerName {} groupId {} "
2768 + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
2769 List<MatchInfo> matches = new ArrayList<>();
2770 matches.add(MatchEthernetType.IPV4);
2771 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2773 List<ActionInfo> actionsInfo = new ArrayList<>();
2774 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
2775 elanManager, idManager, changedVpnId, routerName);
2776 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
2777 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Setting the tunnel to the list of action infos {}",
2779 actionsInfo.add(new ActionGroup(groupId));
2780 List<InstructionInfo> instructions = new ArrayList<>();
2781 instructions.add(new InstructionApplyActions(actionsInfo));
2782 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2783 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2784 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2785 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2787 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Returning SNAT Flow Entity {}", flowEntity);
2791 public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
2792 long changedVpnId) {
2794 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : called for dpId {}, routerName {} "
2795 + "changed VPN ID {}", dpId, routerName, changedVpnId);
2796 List<MatchInfo> matches = new ArrayList<>();
2797 matches.add(MatchEthernetType.IPV4);
2798 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2800 List<InstructionInfo> instructions = new ArrayList<>();
2801 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2803 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2804 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2805 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2806 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2808 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : Returning SNAT Flow Entity {}", flowEntity);
2812 // TODO : Replace this with ITM Rpc once its available with full functionality
2813 protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
2814 long routerId, long changedVpnId, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2816 LOG.debug("installTerminatingServiceTblEntryWithUpdatedVpnId : called for switch {}, "
2817 + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2818 FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, routerId, changedVpnId,
2820 mdsalManager.addFlow(confTx, flowEntity);
2823 private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName,
2824 long routerIdLongVal, long changedVpnId, ProviderTypes extNwProvType) {
2825 LOG.debug("buildTsFlowEntityWithUpdatedVpnId : called for switch {}, routerName {}, BGP VPN ID {}",
2826 dpId, routerName, changedVpnId);
2827 List<MatchInfo> matches = new ArrayList<>();
2828 matches.add(MatchEthernetType.IPV4);
2830 BigInteger tunnelId = BigInteger.valueOf(changedVpnId);
2831 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2832 tunnelId = natOverVxlanUtil.getRouterVni(routerName, changedVpnId);
2834 matches.add(new MatchTunnelId(tunnelId));
2836 List<InstructionInfo> instructions = new ArrayList<>();
2837 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2838 MetaDataUtil.METADATA_MASK_VRFID));
2839 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2840 BigInteger routerId = BigInteger.valueOf(routerIdLongVal);
2841 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2842 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2843 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2844 NwConstants.COOKIE_TS_TABLE, matches, instructions);
2848 public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId,
2849 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2850 LOG.debug("createOutboundTblEntryWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2851 dpnId, routerId, changedVpnId);
2852 FlowEntity tcpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2853 NwConstants.IP_PROT_TCP);
2854 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing tcp flow {}", tcpFlowEntity);
2855 mdsalManager.addFlow(writeFlowInvTx, tcpFlowEntity);
2857 FlowEntity udpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2858 NwConstants.IP_PROT_UDP);
2859 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing udp flow {}", udpFlowEntity);
2860 mdsalManager.addFlow(writeFlowInvTx, udpFlowEntity);
2862 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, changedVpnId);
2863 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
2864 mdsalManager.addFlow(writeFlowInvTx, icmpDropFlow);
2867 protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId,
2868 long changedVpnId, int protocol) {
2869 LOG.debug("buildOutboundFlowEntityWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2870 dpId, routerId, changedVpnId);
2871 BigInteger cookie = getCookieOutboundFlow(routerId);
2872 List<MatchInfo> matches = new ArrayList<>();
2873 matches.add(MatchEthernetType.IPV4);
2874 matches.add(new MatchIpProtocol((short)protocol));
2875 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2877 List<InstructionInfo> instructions = new ArrayList<>();
2878 List<ActionInfo> actionsInfos = new ArrayList<>();
2879 actionsInfos.add(new ActionPuntToController());
2880 if (snatPuntTimeout != 0) {
2881 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
2883 instructions.add(new InstructionApplyActions(actionsInfos));
2885 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
2886 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
2887 flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
2888 LOG.debug("createOutboundTblEntryWithBgpVpn : returning flowEntity {}", flowEntity);
2892 public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId,
2893 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2894 LOG.debug("installNaptPfibEntryWithBgpVpn : called for dpnId {} and segmentId {} ,BGP VPN ID {}",
2895 dpnId, segmentId, changedVpnId);
2896 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2897 mdsalManager.addFlow(writeFlowInvTx, naptPfibFlowEntity);
2900 public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2902 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : called for dpId {}, "
2903 + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2904 List<MatchInfo> matches = new ArrayList<>();
2905 matches.add(MatchEthernetType.IPV4);
2906 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2908 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2909 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2910 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
2911 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2912 instructionInfo.add(new InstructionApplyActions(listActionInfo));
2914 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2915 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2916 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2917 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2918 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : Returning NaptPFib Flow Entity {}", flowEntity);
2923 protected ExternalRoutersListener getDataTreeChangeListener() {
2924 return ExternalRoutersListener.this;
2927 protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId,
2928 @Nullable TypedWriteTransaction<Configuration> writeFlowInvTx) {
2929 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
2931 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
2932 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
2933 if (subnetVpnId != -1) {
2934 LOG.debug("installNaptPfibEntriesForExternalSubnets : called for dpnId {} "
2935 + "and vpnId {}", dpnId, subnetVpnId);
2936 installNaptPfibEntry(dpnId, subnetVpnId, writeFlowInvTx);