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 com.google.common.base.Optional;
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import java.math.BigInteger;
16 import java.net.Inet6Address;
17 import java.net.InetAddress;
18 import java.net.UnknownHostException;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
27 import java.util.Objects;
29 import java.util.concurrent.ExecutionException;
30 import java.util.concurrent.Future;
31 import javax.annotation.Nonnull;
32 import javax.annotation.PostConstruct;
33 import javax.inject.Inject;
34 import javax.inject.Singleton;
35 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
36 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
37 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
38 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
39 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
40 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
41 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
42 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
43 import org.opendaylight.genius.mdsalutil.ActionInfo;
44 import org.opendaylight.genius.mdsalutil.BucketInfo;
45 import org.opendaylight.genius.mdsalutil.FlowEntity;
46 import org.opendaylight.genius.mdsalutil.GroupEntity;
47 import org.opendaylight.genius.mdsalutil.InstructionInfo;
48 import org.opendaylight.genius.mdsalutil.MDSALUtil;
49 import org.opendaylight.genius.mdsalutil.MatchInfo;
50 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
51 import org.opendaylight.genius.mdsalutil.NwConstants;
52 import org.opendaylight.genius.mdsalutil.NwConstants.NxmOfFieldType;
53 import org.opendaylight.genius.mdsalutil.UpgradeState;
54 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
55 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
56 import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
57 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromField;
58 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromValue;
59 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
60 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
61 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
62 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
63 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
64 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
65 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
66 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
67 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
68 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
69 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
70 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
71 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
72 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
73 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
74 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
75 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
76 import org.opendaylight.netvirt.elanmanager.api.IElanService;
77 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
78 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
79 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
80 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
81 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
82 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
83 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
84 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
127 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;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIds;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsBuilder;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsKey;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelOutput;
143 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
144 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
145 import org.opendaylight.yangtools.yang.binding.DataObject;
146 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
147 import org.opendaylight.yangtools.yang.common.RpcResult;
148 import org.slf4j.Logger;
149 import org.slf4j.LoggerFactory;
152 public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener> {
153 private static final Logger LOG = LoggerFactory.getLogger(ExternalRoutersListener.class);
155 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
156 private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
158 private final DataBroker dataBroker;
159 private final ManagedNewTransactionRunner txRunner;
160 private final IMdsalApiManager mdsalManager;
161 private final ItmRpcService itmManager;
162 private final OdlInterfaceRpcService odlInterfaceRpcService;
163 private final IdManagerService idManager;
164 private final NaptManager naptManager;
165 private final NAPTSwitchSelector naptSwitchSelector;
166 private final IBgpManager bgpManager;
167 private final VpnRpcService vpnService;
168 private final FibRpcService fibService;
169 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
170 private final NaptEventHandler naptEventHandler;
171 private final NaptPacketInHandler naptPacketInHandler;
172 private final IFibManager fibManager;
173 private final IVpnManager vpnManager;
174 private final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer;
175 private final CentralizedSwitchScheduler centralizedSwitchScheduler;
176 private final NatMode natMode;
177 private final INeutronVpnManager nvpnManager;
178 private final IElanService elanManager;
179 private final JobCoordinator coordinator;
180 private final UpgradeState upgradeState;
181 private final IInterfaceManager interfaceManager;
182 private final int snatPuntTimeout;
185 public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
186 final ItmRpcService itmManager,
187 final OdlInterfaceRpcService odlInterfaceRpcService,
188 final IdManagerService idManager,
189 final NaptManager naptManager,
190 final NAPTSwitchSelector naptSwitchSelector,
191 final IBgpManager bgpManager,
192 final VpnRpcService vpnService,
193 final FibRpcService fibService,
194 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
195 final NaptEventHandler naptEventHandler,
196 final NaptPacketInHandler naptPacketInHandler,
197 final IFibManager fibManager,
198 final IVpnManager vpnManager,
199 final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer,
200 final INeutronVpnManager nvpnManager,
201 final CentralizedSwitchScheduler centralizedSwitchScheduler,
202 final NatserviceConfig config,
203 final IElanService elanManager,
204 final JobCoordinator coordinator,
205 final UpgradeState upgradeState,
206 final IInterfaceManager interfaceManager) {
207 super(Routers.class, ExternalRoutersListener.class);
208 this.dataBroker = dataBroker;
209 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
210 this.mdsalManager = mdsalManager;
211 this.itmManager = itmManager;
212 this.odlInterfaceRpcService = odlInterfaceRpcService;
213 this.idManager = idManager;
214 this.naptManager = naptManager;
215 this.naptSwitchSelector = naptSwitchSelector;
216 this.bgpManager = bgpManager;
217 this.vpnService = vpnService;
218 this.fibService = fibService;
219 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
220 this.naptEventHandler = naptEventHandler;
221 this.naptPacketInHandler = naptPacketInHandler;
222 this.fibManager = fibManager;
223 this.vpnManager = vpnManager;
224 this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
225 this.nvpnManager = nvpnManager;
226 this.elanManager = elanManager;
227 this.centralizedSwitchScheduler = centralizedSwitchScheduler;
228 this.coordinator = coordinator;
229 this.upgradeState = upgradeState;
230 this.interfaceManager = interfaceManager;
231 if (config != null) {
232 this.natMode = config.getNatMode();
233 this.snatPuntTimeout = config.getSnatPuntTimeout().intValue();
235 this.natMode = NatMode.Controller;
236 this.snatPuntTimeout = 0;
243 LOG.info("{} init", getClass().getSimpleName());
244 // This class handles ExternalRouters for Controller SNAT mode.
245 // For Conntrack SNAT mode, its handled in SnatExternalRoutersListener.java
246 if (natMode == NatMode.Controller) {
247 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
248 NatUtil.createGroupIdPool(idManager);
253 protected InstanceIdentifier<Routers> getWildCardPath() {
254 return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
258 // TODO Clean up the exception handling
259 @SuppressWarnings("checkstyle:IllegalCatch")
260 protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
261 // Populate the router-id-name container
262 String routerName = routers.getRouterName();
263 LOG.info("add : external router event for {}", routerName);
264 long routerId = NatUtil.getVpnId(dataBroker, routerName);
265 NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
266 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
268 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routers.key(),
269 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
270 LOG.info("add : Installing NAT default route on all dpns part of router {}", routerName);
271 long bgpVpnId = NatConstants.INVALID_ID;
272 if (bgpVpnUuid != null) {
273 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
275 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, true, tx);
276 // Allocate Primary Napt Switch for this router
277 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName);
278 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
279 if (!routers.isEnableSnat()) {
280 LOG.info("add : SNAT is disabled for external router {} ", routerName);
281 /* If SNAT is disabled on ext-router though L3_FIB_TABLE(21) -> PSNAT_TABLE(26) flow
282 * is required for DNAT. Hence writeFlowInvTx object submit is required.
286 handleEnableSnat(routers, routerId, primarySwitchId, bgpVpnId, tx);
288 })), NatConstants.NAT_DJC_MAX_RETRIES);
289 } catch (Exception ex) {
290 LOG.error("add : Exception while Installing NAT flows on all dpns as part of router {}",
295 public void handleEnableSnat(Routers routers, long routerId, BigInteger primarySwitchId, long bgpVpnId,
296 WriteTransaction writeFlowInvTx) {
297 String routerName = routers.getRouterName();
298 LOG.info("handleEnableSnat : Handling SNAT for router {}", routerName);
300 naptManager.initialiseExternalCounter(routers, routerId);
301 subnetRegisterMapping(routers, routerId);
303 LOG.debug("handleEnableSnat:About to create and install outbound miss entry in Primary Switch {} for router {}",
304 primarySwitchId, routerName);
306 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
307 routers.getNetworkId());
308 if (extNwProvType == null) {
309 LOG.error("handleEnableSnat : External Network Provider Type missing");
313 if (bgpVpnId != NatConstants.INVALID_ID) {
314 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, false, writeFlowInvTx,
317 // write metadata and punt
318 installOutboundMissEntry(routerName, routerId, primarySwitchId, writeFlowInvTx);
319 // Now install entries in SNAT tables to point to Primary for each router
320 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
321 for (BigInteger dpnId : switches) {
322 // Handle switches and NAPT switches separately
323 if (!dpnId.equals(primarySwitchId)) {
324 LOG.debug("handleEnableSnat : Handle Ordinary switch");
325 handleSwitches(dpnId, routerName, routerId, primarySwitchId);
327 LOG.debug("handleEnableSnat : Handle NAPT switch");
328 handlePrimaryNaptSwitch(dpnId, routerName, routerId, writeFlowInvTx);
333 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
334 if (externalIps.isEmpty()) {
335 LOG.error("handleEnableSnat : Internal External mapping not found for router {}", routerName);
338 for (String externalIpAddrPrefix : externalIps) {
339 LOG.debug("handleEnableSnat : Calling handleSnatReverseTraffic for primarySwitchId {}, "
340 + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
341 handleSnatReverseTraffic(primarySwitchId, routers, routerId, routerName, externalIpAddrPrefix,
345 LOG.debug("handleEnableSnat : Exit");
348 private BigInteger getPrimaryNaptSwitch(String routerName) {
349 // Allocate Primary Napt Switch for this router
350 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
351 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
352 LOG.debug("handleEnableSnat : Primary NAPT switch with DPN ID {} is already elected for router {}",
353 primarySwitchId, routerName);
354 return primarySwitchId;
356 // Validating and creating VNI pool during when NAPT switch is selected.
357 // With Assumption this might be the first NAT service comes up.
358 NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager, idManager,
359 NatConstants.ODL_VNI_POOL_NAME);
360 // Allocated an id from VNI pool for the Router.
361 NatOverVxlanUtil.getRouterVni(idManager, routerName, NatConstants.INVALID_ID);
362 primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
363 LOG.debug("handleEnableSnat : Primary NAPT switch DPN ID {}", primarySwitchId);
365 return primarySwitchId;
368 protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId,
369 WriteTransaction writeFlowInvTx) {
370 Long extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
371 if (extVpnId == NatConstants.INVALID_ID) {
372 LOG.error("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
375 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
376 if (externalIps.isEmpty()) {
377 LOG.error("installNaptPfibExternalOutputFlow - empty external Ips list for dpnId {} extVpnId {}",
381 for (String ip : externalIps) {
382 Uuid subnetId = getSubnetIdForFixedIp(ip);
383 if (subnetId != null) {
384 long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
385 if (subnetVpnId != NatConstants.INVALID_ID) {
386 extVpnId = subnetVpnId;
388 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
389 dpnId, extVpnId, subnetId);
390 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
391 mdsalManager.addFlowToTx(postNaptFlowEntity, writeFlowInvTx);
396 private Uuid getSubnetIdForFixedIp(String ip) {
398 IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
399 Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
400 Uuid subnetId = NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
403 LOG.error("getSubnetIdForFixedIp : ip is null");
407 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
408 List<Uuid> subnetList = null;
409 List<String> externalIps = null;
410 LOG.debug("subnetRegisterMapping : Fetching values from extRouters model");
411 subnetList = routerEntry.getSubnetIds();
412 externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
414 int extIpCounter = externalIps.size();
415 LOG.debug("subnetRegisterMapping : counter values before looping counter {} and extIpCounter {}",
416 counter, extIpCounter);
417 for (Uuid subnet : subnetList) {
418 LOG.debug("subnetRegisterMapping : Looping internal subnets for subnet {}", subnet);
419 InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
420 .builder(Subnetmaps.class)
421 .child(Subnetmap.class, new SubnetmapKey(subnet))
423 Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
424 if (sn.isPresent()) {
426 Subnetmap subnetmapEntry = sn.get();
427 String subnetString = subnetmapEntry.getSubnetIp();
428 String[] subnetSplit = subnetString.split("/");
429 String subnetIp = subnetSplit[0];
431 InetAddress address = InetAddress.getByName(subnetIp);
432 if (address instanceof Inet6Address) {
433 LOG.debug("subnetRegisterMapping : Skipping ipv6 subnet {} for the router {} with ipv6 address "
434 + "{} ", subnet, routerEntry.getRouterName(), address);
437 } catch (UnknownHostException e) {
438 LOG.error("subnetRegisterMapping : Invalid ip address {}", subnetIp, e);
441 String subnetPrefix = "0";
442 if (subnetSplit.length == 2) {
443 subnetPrefix = subnetSplit[1];
445 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
446 LOG.debug("subnetRegisterMapping : subnetAddr is {} and subnetPrefix is {}",
447 subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
449 LOG.debug("subnetRegisterMapping : counter values counter {} and extIpCounter {}",
450 counter, extIpCounter);
451 if (extIpCounter != 0) {
452 if (counter < extIpCounter) {
453 String[] ipSplit = externalIps.get(counter).split("/");
454 String externalIp = ipSplit[0];
455 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
456 if (ipSplit.length == 2) {
457 extPrefix = ipSplit[1];
459 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
460 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
461 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
462 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
463 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
464 + "externalIp {}. prefix {}", subnetIp, subnetPrefix, externalIp, extPrefix);
466 counter = 0; //Reset the counter which runs on externalIps for round-robbin effect
467 LOG.debug("subnetRegisterMapping : Counter on externalIps got reset");
468 String[] ipSplit = externalIps.get(counter).split("/");
469 String externalIp = ipSplit[0];
470 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
471 if (ipSplit.length == 2) {
472 extPrefix = ipSplit[1];
474 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
475 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
476 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
477 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
478 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
479 + "externalIp {}. prefix {}", subnetIp, subnetPrefix,
480 externalIp, extPrefix);
484 LOG.debug("subnetRegisterMapping : Counter on externalIps incremented to {}", counter);
486 LOG.warn("subnetRegisterMapping : No internal subnets present in extRouters Model");
491 private void addOrDelDefFibRouteToSNAT(String routerName, long routerId, long bgpVpnId,
492 Uuid bgpVpnUuid, boolean create, WriteTransaction writeFlowInvTx) {
493 //Check if BGP VPN exists. If exists then invoke the new method.
494 if (bgpVpnId != NatConstants.INVALID_ID) {
495 if (bgpVpnUuid != null) {
496 String bgpVpnName = bgpVpnUuid.getValue();
497 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
498 bgpVpnId, bgpVpnName);
499 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
500 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
501 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
502 getRoutersIdentifier(bgpVpnId), rtrs);
504 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, create, writeFlowInvTx);
508 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
509 addOrDelDefaultFibRouteForSNAT(routerName, routerId, create, writeFlowInvTx);
512 private void addOrDelDefaultFibRouteForSNAT(String routerName, long routerId, boolean create,
513 WriteTransaction writeFlowInvTx) {
514 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
515 if (switches.isEmpty()) {
516 LOG.info("addOrDelDefaultFibRouteForSNAT : No switches found for router {}", routerName);
519 if (routerId == NatConstants.INVALID_ID) {
520 LOG.error("addOrDelDefaultFibRouteForSNAT : Could not retrieve router Id for {} to program "
521 + "default NAT route in FIB", routerName);
524 for (BigInteger dpnId : switches) {
526 LOG.debug("addOrDelDefaultFibRouteForSNAT : installing default NAT route for router {} in dpn {} "
527 + "for the internal vpn-id {}", routerId, dpnId, routerId);
528 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, writeFlowInvTx);
530 LOG.debug("addOrDelDefaultFibRouteForSNAT : removing default NAT route for router {} in dpn {} "
531 + "for the internal vpn-id {}", routerId, dpnId, routerId);
532 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, writeFlowInvTx);
537 private void addOrDelDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
538 long bgpVpnId, boolean create,WriteTransaction writeFlowInvTx) {
539 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
540 if (dpnIds.isEmpty()) {
541 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
542 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
545 for (BigInteger dpnId : dpnIds) {
547 if (bgpVpnId != NatConstants.INVALID_ID) {
548 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
549 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
550 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, writeFlowInvTx);
552 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
553 + "in dpn {} for the internal vpn", routerId, dpnId);
554 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId,writeFlowInvTx);
557 if (bgpVpnId != NatConstants.INVALID_ID) {
558 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
559 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
560 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId, writeFlowInvTx);
562 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
563 + "in dpn {} for the internal vpn", routerId, dpnId);
564 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, writeFlowInvTx);
570 // TODO Clean up the exception handling
571 @SuppressWarnings("checkstyle:IllegalCatch")
572 public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
573 InstanceIdentifier<T> path) {
574 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
577 return tx.read(datastoreType, path).get();
578 } catch (Exception e) {
579 throw new RuntimeException(e);
583 protected void installOutboundMissEntry(String routerName, long routerId, BigInteger primarySwitchId,
584 WriteTransaction writeFlowInvTx) {
585 LOG.debug("installOutboundMissEntry : Router ID from getVpnId {}", routerId);
586 if (routerId != NatConstants.INVALID_ID) {
587 LOG.debug("installOutboundMissEntry : Creating miss entry on primary {}, for router {}",
588 primarySwitchId, routerId);
589 createOutboundTblEntry(primarySwitchId, routerId, writeFlowInvTx);
591 LOG.error("installOutboundMissEntry : Unable to fetch Router Id for RouterName {}, failed to "
592 + "createAndInstallMissEntry", routerName);
596 public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID, int protocol) {
597 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
598 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + protocol;
601 private String getFlowRefNaptPreFib(BigInteger dpnId, short tableId, long vpnId) {
602 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
603 .FLOWID_SEPARATOR + vpnId;
606 public BigInteger getCookieOutboundFlow(long routerId) {
607 return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
608 BigInteger.valueOf(routerId));
611 private ActionLearn getLearnActionForPunt(int protocol, int hardTimeout, BigInteger cookie) {
614 int l4portFieldLen = NxmOfFieldType.NXM_OF_TCP_SRC.getFlowModHeaderLenInt();
616 if (protocol == NwConstants.IP_PROT_TCP) {
617 l4SrcPortField = NxmOfFieldType.NXM_OF_TCP_SRC.getType();
618 l4DstPortField = NxmOfFieldType.NXM_OF_TCP_DST.getType();
620 l4SrcPortField = NxmOfFieldType.NXM_OF_UDP_SRC.getType();
621 l4DstPortField = NxmOfFieldType.NXM_OF_UDP_DST.getType();
623 List<ActionLearn.FlowMod> flowMods = Arrays.asList(
624 new MatchFromValue(NwConstants.ETHTYPE_IPV4, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
625 NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
626 new MatchFromValue(protocol, NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
627 NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
628 new MatchFromField(NxmOfFieldType.NXM_OF_IP_SRC.getType(), NxmOfFieldType.NXM_OF_IP_SRC.getType(),
629 NxmOfFieldType.NXM_OF_IP_SRC.getFlowModHeaderLenInt()),
630 new MatchFromField(NxmOfFieldType.NXM_OF_IP_DST.getType(), NxmOfFieldType.NXM_OF_IP_DST.getType(),
631 NxmOfFieldType.NXM_OF_IP_DST.getFlowModHeaderLenInt()),
632 new MatchFromField(l4SrcPortField, l4SrcPortField, l4portFieldLen),
633 new MatchFromField(l4DstPortField, l4DstPortField, l4portFieldLen),
634 new MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
635 MetaDataUtil.METADATA_VPN_ID_OFFSET,
636 NxmOfFieldType.OXM_OF_METADATA.getType(), MetaDataUtil.METADATA_VPN_ID_OFFSET,
637 MetaDataUtil.METADATA_VPN_ID_BITLEN));
639 return new ActionLearn(0, hardTimeout, 7, cookie, 0,
640 NwConstants.OUTBOUND_NAPT_TABLE, 0, 0, flowMods);
643 private FlowEntity buildIcmpDropFlow(BigInteger dpnId, long routerId, long vpnId) {
644 List<MatchInfo> matches = new ArrayList<>();
645 matches.add(MatchEthernetType.IPV4);
646 matches.add(MatchIpProtocol.ICMP);
647 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
649 List<ActionInfo> actionInfos = new ArrayList<>();
650 actionInfos.add(new ActionDrop());
652 List<InstructionInfo> instructions = new ArrayList<>();
653 instructions.add(new InstructionApplyActions(actionInfos));
655 String flowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
656 NwConstants.IP_PROT_ICMP);
657 FlowEntity flow = MDSALUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
658 NwConstants.TABLE_MISS_PRIORITY, "icmp drop flow", 0, 0,
659 NwConstants.COOKIE_OUTBOUND_NAPT_TABLE, matches, instructions);
663 protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId, int protocol) {
664 LOG.debug("buildOutboundFlowEntity : called for dpId {} and routerId{}", dpId, routerId);
665 BigInteger cookie = getCookieOutboundFlow(routerId);
666 List<MatchInfo> matches = new ArrayList<>();
667 matches.add(MatchEthernetType.IPV4);
668 matches.add(new MatchIpProtocol((short)protocol));
669 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
671 List<InstructionInfo> instructions = new ArrayList<>();
672 List<ActionInfo> actionsInfos = new ArrayList<>();
673 actionsInfos.add(new ActionPuntToController());
674 if (snatPuntTimeout != 0) {
675 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
677 instructions.add(new InstructionApplyActions(actionsInfos));
679 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
680 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
682 cookie, matches, instructions);
683 LOG.debug("installOutboundMissEntry : returning flowEntity {}", flowEntity);
687 public void createOutboundTblEntry(BigInteger dpnId, long routerId, WriteTransaction writeFlowInvTx) {
688 LOG.debug("createOutboundTblEntry : called for dpId {} and routerId {}", dpnId, routerId);
689 FlowEntity tcpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_TCP);
690 LOG.debug("createOutboundTblEntry : Installing tcp flow {}", tcpflowEntity);
691 mdsalManager.addFlowToTx(tcpflowEntity, writeFlowInvTx);
693 FlowEntity udpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_UDP);
694 LOG.debug("createOutboundTblEntry : Installing udp flow {}", udpflowEntity);
695 mdsalManager.addFlowToTx(udpflowEntity, writeFlowInvTx);
697 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, routerId);
698 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
699 mdsalManager.addFlowToTx(icmpDropFlow, writeFlowInvTx);
702 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
703 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
704 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
706 Future<RpcResult<GetTunnelInterfaceNameOutput>> result =
707 itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
708 .setSourceDpid(srcDpId)
709 .setDestinationDpid(dstDpId)
710 .setTunnelType(tunType)
712 rpcResult = result.get();
713 if (!rpcResult.isSuccessful()) {
714 tunType = TunnelTypeGre.class;
715 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
716 .setSourceDpid(srcDpId)
717 .setDestinationDpid(dstDpId)
718 .setTunnelType(tunType)
720 rpcResult = result.get();
721 if (!rpcResult.isSuccessful()) {
722 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
723 rpcResult.getErrors());
725 return rpcResult.getResult().getInterfaceName();
727 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
728 rpcResult.getErrors());
730 return rpcResult.getResult().getInterfaceName();
732 } catch (InterruptedException | ExecutionException | NullPointerException e) {
733 LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
734 + "between {} and {}", srcDpId, dstDpId, e);
740 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName, long routerId,
741 WriteTransaction writeFlowInvTx) {
742 LOG.debug("installSnatMissEntry : called for for the primary NAPT switch dpnId {} ", dpnId);
743 // Install miss entry pointing to group
744 FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName, routerId);
745 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
748 protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo,
749 String routerName, long routerId) {
750 LOG.debug("installSnatMissEntry : called for dpnId {} with primaryBucket {} ",
751 dpnId, bucketInfo.get(0));
752 // Install the select group
753 long groupId = createGroupId(getGroupIdKey(routerName));
754 GroupEntity groupEntity =
755 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
756 LOG.debug("installSnatMissEntry : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
757 mdsalManager.syncInstallGroup(groupEntity);
758 // Install miss entry pointing to group
759 FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, routerId, groupId);
760 if (flowEntity == null) {
761 LOG.error("installSnatMissEntry : Flow entity received as NULL. "
762 + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
763 + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
766 mdsalManager.installFlow(flowEntity);
769 long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo) {
770 long groupId = createGroupId(getGroupIdKey(routerName));
771 GroupEntity groupEntity =
772 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
773 LOG.debug("installGroup : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
774 mdsalManager.syncInstallGroup(groupEntity);
778 private FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long routerId, long groupId) {
779 LOG.debug("buildSnatFlowEntity : called for dpId {}, routerName {} and groupId {}",
780 dpId, routerName, groupId);
781 List<MatchInfo> matches = new ArrayList<>();
782 matches.add(MatchEthernetType.IPV4);
783 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
785 List<ActionInfo> actionsInfo = new ArrayList<>();
786 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
788 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
789 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
790 actionsInfo.add(new ActionGroup(groupId));
791 List<InstructionInfo> instructions = new ArrayList<>();
792 instructions.add(new InstructionApplyActions(actionsInfo));
793 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
794 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
795 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
796 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
798 LOG.debug("buildSnatFlowEntity : Returning SNAT Flow Entity {}", flowEntity);
802 private FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName, long routerId) {
804 LOG.debug("buildSnatFlowEntityForPrmrySwtch : called for primary NAPT switch dpId {}, routerName {}", dpId,
806 List<MatchInfo> matches = new ArrayList<>();
807 matches.add(MatchEthernetType.IPV4);
808 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
810 List<InstructionInfo> instructions = new ArrayList<>();
811 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
813 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
814 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
815 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
816 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
818 LOG.debug("buildSnatFlowEntityForPrmrySwtch : Returning SNAT Flow Entity {}", flowEntity);
822 // TODO : Replace this with ITM Rpc once its available with full functionality
823 protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName, long routerId,
824 WriteTransaction writeFlowInvTx) {
825 LOG.debug("installTerminatingServiceTblEntry : for switch {}, routerName {}",
827 FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName, routerId);
828 if (flowEntity == null) {
829 LOG.error("installTerminatingServiceTblEntry : Flow entity received as NULL. "
830 + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
831 + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
835 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
839 private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName, long routerId) {
840 List<MatchInfo> matches = new ArrayList<>();
841 matches.add(MatchEthernetType.IPV4);
842 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
844 matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
845 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
846 List<InstructionInfo> instructions = new ArrayList<>();
847 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
848 MetaDataUtil.METADATA_MASK_VRFID));
849 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
850 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
851 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
856 public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
857 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
858 .FLOWID_SEPARATOR + routerID;
861 public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
862 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
863 .FLOWID_SEPARATOR + routerID;
866 private String getGroupIdKey(String routerName) {
867 return "snatmiss." + routerName;
870 protected long createGroupId(String groupIdKey) {
871 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
872 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
875 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
876 RpcResult<AllocateIdOutput> rpcResult = result.get();
877 return rpcResult.getResult().getIdValue();
878 } catch (NullPointerException | InterruptedException | ExecutionException e) {
879 LOG.error("Exception While allocating id for group: {}", groupIdKey, e);
884 protected void handleSwitches(BigInteger dpnId, String routerName, long routerId, BigInteger primarySwitchId) {
885 LOG.debug("handleSwitches : Installing SNAT miss entry in switch {}", dpnId);
886 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
887 String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
888 List<BucketInfo> listBucketInfo = new ArrayList<>();
890 if (ifNamePrimary != null) {
891 LOG.debug("handleSwitches : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
892 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
893 interfaceManager, ifNamePrimary, routerId);
894 if (listActionInfoPrimary.isEmpty()) {
895 LOG.error("handleSwitches : Unable to retrieve output actions on Non-NAPT switch {} for router {}"
896 + " towards Napt-switch {} via tunnel interface {}", dpnId, routerName, primarySwitchId,
900 LOG.error("handleSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} from "
901 + "Non-Napt switch {} for router {}", primarySwitchId, dpnId, routerName);
903 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
905 listBucketInfo.add(0, bucketPrimary);
906 installSnatMissEntry(dpnId, listBucketInfo, routerName, routerId);
909 List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
910 BigInteger primarySwitchId, String routerName, long routerId) {
911 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
912 String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
913 List<BucketInfo> listBucketInfo = new ArrayList<>();
915 if (ifNamePrimary != null) {
916 LOG.debug("getBucketInfoForNonNaptSwitches : On Non- Napt switch , Primary Tunnel interface is {}",
918 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
919 interfaceManager, ifNamePrimary, routerId);
920 if (listActionInfoPrimary.isEmpty()) {
921 LOG.error("getBucketInfoForNonNaptSwitches : Unable to retrieve output actions on Non-NAPT switch {} "
922 + "for router {} towards Napt-switch {} via tunnel interface {}",
923 nonNaptSwitchId, routerName, primarySwitchId, ifNamePrimary);
926 LOG.error("getBucketInfoForNonNaptSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} "
927 + "from Non-Napt switch {} for router {}", primarySwitchId, nonNaptSwitchId, routerName);
929 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
931 listBucketInfo.add(0, bucketPrimary);
932 return listBucketInfo;
935 protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName, long routerId,
936 WriteTransaction writeFlowInvTx) {
938 * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
941 LOG.debug("handlePrimaryNaptSwitch : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
944 List<BucketInfo> listBucketInfo = new ArrayList<>();
945 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
946 listActionInfoPrimary.add(new ActionNxResubmit(NatConstants.TERMINATING_SERVICE_TABLE));
947 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
948 listBucketInfo.add(0, bucketPrimary);
951 installSnatMissEntryForPrimrySwch(dpnId, routerName, routerId, writeFlowInvTx);
952 installTerminatingServiceTblEntry(dpnId, routerName, routerId, writeFlowInvTx);
953 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
954 installNaptPfibEntry(dpnId, routerId, writeFlowInvTx);
955 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
956 if (networkId != null) {
957 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
958 if (vpnUuid != null) {
959 Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
960 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
961 installNaptPfibEntriesForExternalSubnets(routerName, dpnId, null);
962 //Install the NAPT PFIB TABLE which forwards outgoing packet to FIB Table matching on the VPN ID.
963 if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
964 installNaptPfibEntry(dpnId, vpnId, null);
966 return Collections.emptyList();
969 LOG.warn("handlePrimaryNaptSwitch : External Vpn ID missing for Ext-Network : {}", networkId);
972 LOG.warn("handlePrimaryNaptSwitch : External Network not available for router : {}", routerName);
976 List<BucketInfo> getBucketInfoForPrimaryNaptSwitch() {
977 List<BucketInfo> listBucketInfo = new ArrayList<>();
978 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
979 listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
980 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
981 listBucketInfo.add(0, bucketPrimary);
982 return listBucketInfo;
985 public void installNaptPfibEntry(BigInteger dpnId, long segmentId, WriteTransaction writeFlowInvTx) {
986 LOG.debug("installNaptPfibEntry : called for dpnId {} and segmentId {} ", dpnId, segmentId);
987 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
988 if (writeFlowInvTx != null) {
989 mdsalManager.addFlowToTx(naptPfibFlowEntity, writeFlowInvTx);
991 mdsalManager.installFlow(naptPfibFlowEntity);
995 public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
997 LOG.debug("buildNaptPfibFlowEntity : called for dpId {}, segmentId {}", dpId, segmentId);
998 List<MatchInfo> matches = new ArrayList<>();
999 matches.add(MatchEthernetType.IPV4);
1000 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
1002 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
1003 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
1004 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
1005 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
1006 instructionInfo.add(new InstructionApplyActions(listActionInfo));
1008 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
1009 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
1010 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
1011 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
1012 LOG.debug("buildNaptPfibFlowEntity : Returning NaptPFib Flow Entity {}", flowEntity);
1016 public void handleSnatReverseTraffic(BigInteger dpnId, Routers router, long routerId, String routerName,
1017 String externalIp, WriteTransaction writeFlowInvTx) {
1018 LOG.debug("handleSnatReverseTraffic : entry for DPN ID {}, routerId {}, externalIp: {}",
1019 dpnId, routerId, externalIp);
1020 Uuid networkId = router.getNetworkId();
1021 if (networkId == null) {
1022 LOG.error("handleSnatReverseTraffic : networkId is null for the router ID {}", routerId);
1025 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1026 if (vpnName == null) {
1027 LOG.error("handleSnatReverseTraffic : No VPN associated with ext nw {} to handle add external ip "
1028 + "configuration {} in router {}", networkId, externalIp, routerId);
1031 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1032 externalIp, networkId, router, writeFlowInvTx);
1033 LOG.debug("handleSnatReverseTraffic : exit for DPN ID {}, routerId {}, externalIp : {}",
1034 dpnId, routerId, externalIp);
1037 public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
1038 final long routerId, final String routerName, final String externalIp,
1039 final Uuid extNetworkId, final Routers router,
1040 final WriteTransaction writeFlowInvTx) {
1041 LOG.debug("advToBgpAndInstallFibAndTsFlows : entry for DPN ID {}, tableId {}, vpnname {} "
1042 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
1043 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
1044 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1045 if (rd == null || rd.isEmpty()) {
1046 LOG.error("advToBgpAndInstallFibAndTsFlows : Unable to get RD for VPN Name {}", vpnName);
1049 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
1050 if (extNwProvType == null) {
1051 LOG.error("advToBgpAndInstallFibAndTsFlows : External Network Provider Type missing");
1054 if (extNwProvType == ProviderTypes.VXLAN) {
1055 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
1056 tx -> evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp,
1057 vpnName, rd, nextHopIp, tx, routerId, routerName, writeFlowInvTx)), LOG,
1058 "Error installing FIB and TS flows");
1061 //Generate VPN label for the external IP
1062 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
1063 .setIpPrefix(externalIp).build();
1064 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
1066 //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
1067 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
1068 if (result.isSuccessful()) {
1069 LOG.debug("advToBgpAndInstallFibAndTsFlows : inside apply with result success");
1070 GenerateVpnLabelOutput output = result.getResult();
1071 final long label = output.getLabel();
1073 int externalIpInDsFlag = 0;
1074 //Get IPMaps from the DB for the router ID
1075 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
1076 if (dbIpMaps != null) {
1077 for (IpMap dbIpMap : dbIpMaps) {
1078 String dbExternalIp = dbIpMap.getExternalIp();
1079 //Select the IPMap, whose external IP is the IP for which FIB is installed
1080 if (dbExternalIp.contains(externalIp)) {
1081 String dbInternalIp = dbIpMap.getInternalIp();
1082 IpMapKey dbIpMapKey = dbIpMap.key();
1083 LOG.debug("advToBgpAndInstallFibAndTsFlows : Setting label {} for internalIp {} "
1084 + "and externalIp {}", label, dbInternalIp, externalIp);
1085 IpMap newIpm = new IpMapBuilder().withKey(dbIpMapKey).setInternalIp(dbInternalIp)
1086 .setExternalIp(dbExternalIp).setLabel(label).build();
1087 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1088 naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
1089 externalIpInDsFlag++;
1092 if (externalIpInDsFlag <= 0) {
1093 LOG.debug("advToBgpAndInstallFibAndTsFlows : External Ip {} not found in DS, "
1094 + "Failed to update label {} for routerId {} in DS",
1095 externalIp, label, routerId);
1096 String errMsg = String.format("Failed to update label %s due to external Ip %s not"
1097 + " found in DS for router %s", label, externalIp, routerId);
1098 return Futures.immediateFailedFuture(new Exception(errMsg));
1101 LOG.error("advToBgpAndInstallFibAndTsFlows : Failed to write label {} for externalIp {} for"
1102 + " routerId {} in DS", label, externalIp, routerId);
1106 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1107 l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
1109 Routers extRouter = router != null ? router :
1110 NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1111 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp,
1113 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, externalSubnetId,
1114 externalIp, nextHopIp, extRouter.getNetworkId().getValue(), null, label, l3vni,
1115 RouteOrigin.STATIC, dpnId);
1117 //Install custom FIB routes
1118 List<Instruction> tunnelTableCustomInstructions = new ArrayList<>();
1119 tunnelTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
1120 makeTunnelTableEntry(dpnId, label, l3vni, tunnelTableCustomInstructions, writeFlowInvTx,
1122 makeLFibTableEntry(dpnId, label, tableId, writeFlowInvTx);
1124 //Install custom FIB routes - FIB table.
1125 List<Instruction> fibTableCustomInstructions = createFibTableCustomInstructions(tableId,
1126 routerName, externalIp);
1127 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1128 //Install the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
1129 NatUtil.makePreDnatToSnatTableEntry(mdsalManager, dpnId,
1130 NwConstants.INBOUND_NAPT_TABLE,writeFlowInvTx);
1132 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1133 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
1135 String externalVpn = vpnName;
1136 if (externalSubnet.isPresent()) {
1137 externalVpn = externalSubnetId.getValue();
1139 CreateFibEntryInput input = new CreateFibEntryInputBuilder()
1140 .setVpnName(externalVpn)
1141 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
1142 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
1143 .setInstruction(fibTableCustomInstructions).build();
1144 return fibService.createFibEntry(input);
1146 LOG.error("advToBgpAndInstallFibAndTsFlows : inside apply with result failed");
1147 String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
1148 externalIp, vpnName, result.getErrors());
1149 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1151 }, MoreExecutors.directExecutor());
1153 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
1156 public void onFailure(@Nonnull Throwable error) {
1157 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in generate label or fib install process", error);
1161 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
1162 if (result.isSuccessful()) {
1163 LOG.info("advToBgpAndInstallFibAndTsFlows : Successfully installed custom FIB routes for prefix {}",
1166 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in rpc call to create custom Fib entries "
1167 + "for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
1170 }, MoreExecutors.directExecutor());
1173 private List<Instruction> createFibTableCustomInstructions(short tableId, String routerName,
1174 String externalIp) {
1175 List<Instruction> fibTableCustomInstructions = new ArrayList<>();
1176 Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1177 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
1178 externalIp, router);
1179 int instructionIndex = 0;
1180 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
1181 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
1182 fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
1183 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
1187 fibTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(instructionIndex));
1188 return fibTableCustomInstructions;
1191 private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId, WriteTransaction writeFlowInvTx) {
1192 List<MatchInfo> matches = new ArrayList<>();
1193 matches.add(MatchEthernetType.MPLS_UNICAST);
1194 matches.add(new MatchMplsLabel(serviceId));
1196 List<Instruction> instructions = new ArrayList<>();
1197 List<ActionInfo> actionsInfos = new ArrayList<>();
1198 actionsInfos.add(new ActionPopMpls());
1199 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
1200 instructions.add(writeInstruction);
1201 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
1203 // Install the flow entry in L3_LFIB_TABLE
1204 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1206 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1208 COOKIE_VM_LFIB_TABLE, matches, instructions);
1210 mdsalManager.addFlowToTx(dpId, flowEntity, writeFlowInvTx);
1212 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
1215 private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, long l3Vni,
1216 List<Instruction> customInstructions, WriteTransaction writeFlowInvTx, ProviderTypes extNwProvType) {
1217 List<MatchInfo> mkMatches = new ArrayList<>();
1219 LOG.debug("makeTunnelTableEntry : DpnId = {} and serviceId = {} and actions = {}",
1220 dpnId, serviceId, customInstructions);
1222 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1223 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
1225 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
1228 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1229 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5,
1230 String.format("%s:%d", "TST Flow Entry ", serviceId),
1231 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1233 mdsalManager.addFlowToTx(dpnId, terminatingServiceTableFlowEntity, writeFlowInvTx);
1236 protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1237 InstanceIdentifier<RouterIds> id = InstanceIdentifier.builder(
1238 RouterIdName.class).child(RouterIds.class, new RouterIdsKey(routerId)).build();
1242 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1243 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
1244 .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
1248 protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1249 String routerName = original.getRouterName();
1250 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1251 if (routerId == NatConstants.INVALID_ID) {
1252 LOG.error("update : external router event - Invalid routerId for routerName {}", routerName);
1255 // Check if its update on SNAT flag
1256 boolean originalSNATEnabled = original.isEnableSnat();
1257 boolean updatedSNATEnabled = update.isEnableSnat();
1258 LOG.debug("update :called with originalFlag and updatedFlag for SNAT enabled "
1259 + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
1260 /* Get Primary Napt Switch for existing router from "router-to-napt-switch" DS.
1261 * if dpnId value is null or zero then go for electing new Napt switch for existing router.
1263 long bgpVpnId = NatConstants.INVALID_ID;
1264 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1265 if (bgpVpnUuid != null) {
1266 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1268 BigInteger dpnId = getPrimaryNaptSwitch(routerName);
1269 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1270 // Router has no interface attached
1273 final long finalBgpVpnId = bgpVpnId;
1274 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + update.key(), () -> {
1275 List<ListenableFuture<Void>> futures = new ArrayList<>();
1276 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(writeFlowInvTx -> {
1277 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(removeFlowInvTx -> {
1278 Uuid networkId = original.getNetworkId();
1279 if (originalSNATEnabled != updatedSNATEnabled) {
1280 if (originalSNATEnabled) {
1281 //SNAT disabled for the router
1282 Uuid networkUuid = original.getNetworkId();
1283 LOG.info("update : SNAT disabled for Router {}", routerName);
1284 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1285 handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId, routerId,
1288 LOG.info("update : SNAT enabled for Router {}", original.getRouterName());
1289 handleEnableSnat(original, routerId, dpnId, finalBgpVpnId, removeFlowInvTx);
1292 if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1293 NatUtil.installRouterGwFlows(txRunner, vpnManager, original, dpnId, NwConstants.DEL_FLOW);
1294 NatUtil.installRouterGwFlows(txRunner, vpnManager, update, dpnId, NwConstants.ADD_FLOW);
1297 //Check if the Update is on External IPs
1298 LOG.debug("update : Checking if this is update on External IPs");
1299 List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
1300 List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
1302 //Check if the External IPs are added during the update.
1303 Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
1304 addedExternalIps.removeAll(originalExternalIps);
1305 if (addedExternalIps.size() != 0) {
1306 LOG.debug("update : Start processing of the External IPs addition during the update "
1308 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
1309 update.getExtGwMacAddress(), dpnId,
1310 update.getNetworkId(), null);
1312 for (String addedExternalIp : addedExternalIps) {
1314 1) Do nothing in the IntExtIp model.
1315 2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1317 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1318 String externalIp = externalIpParts[0];
1319 String externalIpPrefix = externalIpParts[1];
1320 String externalpStr = externalIp + "/" + externalIpPrefix;
1321 LOG.debug("update : Initialise the count mapping of the external IP {} for the "
1322 + "router ID {} in the ExternalIpsCounter model.",
1323 externalpStr, routerId);
1324 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1327 "update : End processing of the External IPs addition during the update operation");
1330 //Check if the External IPs are removed during the update.
1331 Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
1332 removedExternalIps.removeAll(updatedExternalIps);
1333 if (removedExternalIps.size() > 0) {
1334 LOG.debug("update : Start processing of the External IPs removal during the update "
1336 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
1337 removedExternalIps, original.getExtGwMacAddress(),
1340 for (String removedExternalIp : removedExternalIps) {
1342 1) Remove the mappings in the IntExt IP model which has external IP.
1343 2) Remove the external IP in the ExternalCounter model.
1344 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the
1345 least loaded external IP.
1346 Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1347 4) Increase the count of the allocated external IP by one.
1348 5) Advertise to the BGP if external IP is allocated for the first time for the router
1349 i.e. the route for the external IP is absent.
1350 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for
1351 the removed external IPs and also from the model.
1352 7) Advertise to the BGP for removing the route for the removed external IPs.
1355 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1356 String externalIp = externalIpParts[0];
1357 String externalIpPrefix = externalIpParts[1];
1358 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1360 LOG.debug("update : Clear the routes from the BGP and remove the FIB and TS "
1361 + "entries for removed external IP {}", externalIpAddrStr);
1362 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1363 String vpnName = "";
1364 if (vpnUuId != null) {
1365 vpnName = vpnUuId.getValue();
1367 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName, networkId,
1368 update.getExtGwMacAddress(), removeFlowInvTx);
1370 LOG.debug("update : Remove the mappings in the IntExtIP model which has external IP.");
1371 //Get the internal IPs which are associated to the removed external IPs
1372 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1373 List<String> removedInternalIps = new ArrayList<>();
1374 for (IpMap ipMap : ipMaps) {
1375 if (ipMap.getExternalIp().equals(externalIpAddrStr)) {
1376 removedInternalIps.add(ipMap.getInternalIp());
1380 LOG.debug("update : Remove the mappings of the internal IPs from the IntExtIP model.");
1381 for (String removedInternalIp : removedInternalIps) {
1382 LOG.debug("update : Remove the IP mapping of the internal IP {} for the "
1383 + "router ID {} from the IntExtIP model",
1384 removedInternalIp, routerId);
1385 naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1388 LOG.debug("update : Remove the count mapping of the external IP {} for the "
1389 + "router ID {} from the ExternalIpsCounter model.",
1390 externalIpAddrStr, routerId);
1391 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1393 LOG.debug("update : Allocate the least loaded external IPs to the subnets "
1394 + "whose external IPs were removed.");
1395 for (String removedInternalIp : removedInternalIps) {
1396 allocateExternalIp(dpnId, update, routerId, routerName, networkId,
1397 removedInternalIp, writeFlowInvTx);
1400 LOG.debug("update : Remove the NAPT translation entries from "
1401 + "Inbound and Outbound NAPT tables for the removed external IPs.");
1402 //Get the internalIP and internal Port which were associated to the removed external IP.
1403 List<Integer> externalPorts = new ArrayList<>();
1404 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1405 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier
1406 .builder(IntextIpPortMap.class)
1407 .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1408 Optional<IpPortMapping> ipPortMapping =
1409 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1410 if (ipPortMapping.isPresent()) {
1411 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get()
1412 .getIntextIpProtocolType();
1413 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1414 ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1415 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1416 for (IpPortMap ipPortMap : ipPortMaps) {
1417 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1418 if (ipPortExternal.getIpAddress().equals(externalIp)) {
1419 externalPorts.add(ipPortExternal.getPortNum());
1420 List<String> removedInternalIpPorts =
1421 protoTypesIntIpPortsMap.get(protoType);
1422 if (removedInternalIpPorts != null) {
1423 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1424 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1426 removedInternalIpPorts = new ArrayList<>();
1427 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1428 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1435 //Remove the IP port map from the intext-ip-port-map model, which were containing
1436 // the removed external IP.
1437 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts =
1438 protoTypesIntIpPortsMap.entrySet();
1439 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1440 for (Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts) {
1441 ProtocolTypes protocolType = (ProtocolTypes) protoTypesIntIpPort.getKey();
1442 List<String> removedInternalIpPorts = (List<String>) protoTypesIntIpPort.getValue();
1443 for (String removedInternalIpPort : removedInternalIpPorts) {
1444 // Remove the IP port map from the intext-ip-port-map model,
1445 // which were containing the removed external IP
1446 naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort,
1448 //Remove the IP port incomint packer map.
1449 naptPacketInHandler.removeIncomingPacketMap(
1450 routerId + NatConstants.COLON_SEPARATOR + removedInternalIpPort);
1451 String[] removedInternalIpPortParts = removedInternalIpPort
1452 .split(NatConstants.COLON_SEPARATOR);
1453 if (removedInternalIpPortParts.length == 2) {
1454 String removedInternalIp = removedInternalIpPortParts[0];
1455 String removedInternalPort = removedInternalIpPortParts[1];
1456 List<String> removedInternalPortsList =
1457 internalIpPortMap.get(removedInternalPort);
1458 if (removedInternalPortsList != null) {
1459 removedInternalPortsList.add(removedInternalPort);
1460 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1462 removedInternalPortsList = new ArrayList<>();
1463 removedInternalPortsList.add(removedInternalPort);
1464 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1470 // Delete the entry from SnatIntIpPortMap DS
1471 Set<String> internalIps = internalIpPortMap.keySet();
1472 for (String internalIp : internalIps) {
1473 LOG.debug("update : Removing IpPort having the internal IP {} from the "
1474 + "model SnatIntIpPortMap", internalIp);
1475 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1478 naptManager.removeNaptPortPool(externalIp);
1480 LOG.debug("update : Remove the NAPT translation entries from Inbound NAPT tables for "
1481 + "the removed external IP {}", externalIp);
1482 for (Integer externalPort : externalPorts) {
1483 //Remove the NAPT translation entries from Inbound NAPT table
1484 naptEventHandler.removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1485 routerId, externalIp, externalPort);
1488 Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
1489 for (Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
1490 String internalIp = internalIpPort.getKey();
1491 LOG.debug("update : Remove the NAPT translation entries from Outbound NAPT tables "
1492 + "for the removed internal IP {}", internalIp);
1493 List<String> internalPorts = internalIpPort.getValue();
1494 for (String internalPort : internalPorts) {
1495 //Remove the NAPT translation entries from Outbound NAPT table
1496 naptPacketInHandler.removeIncomingPacketMap(
1497 routerId + NatConstants.COLON_SEPARATOR + internalIp
1498 + NatConstants.COLON_SEPARATOR + internalPort);
1499 naptEventHandler.removeNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1500 routerId, internalIp, Integer.parseInt(internalPort));
1505 "update : End processing of the External IPs removal during the update operation");
1508 //Check if its Update on subnets
1509 LOG.debug("update : Checking if this is update on subnets");
1510 List<Uuid> originalSubnetIds = original.getSubnetIds();
1511 List<Uuid> updatedSubnetIds = update.getSubnetIds();
1512 Set<Uuid> addedSubnetIds = new HashSet<>(updatedSubnetIds);
1513 addedSubnetIds.removeAll(originalSubnetIds);
1515 //Check if the Subnet IDs are added during the update.
1516 if (addedSubnetIds.size() != 0) {
1518 "update : Start processing of the Subnet IDs addition during the update operation");
1519 for (Uuid addedSubnetId : addedSubnetIds) {
1521 1) Select the least loaded external IP for the subnet and store the mapping of the
1522 subnet IP and the external IP in the IntExtIp model.
1523 2) Increase the count of the selected external IP by one.
1524 3) Advertise to the BGP if external IP is allocated for the first time for the
1525 router i.e. the route for the external IP is absent.
1527 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1528 if (subnetIp != null) {
1529 allocateExternalIp(dpnId, update, routerId, routerName, networkId, subnetIp,
1533 LOG.debug("update : End processing of the Subnet IDs addition during the update operation");
1536 //Check if the Subnet IDs are removed during the update.
1537 Set<Uuid> removedSubnetIds = new HashSet<>(originalSubnetIds);
1538 removedSubnetIds.removeAll(updatedSubnetIds);
1539 if (removedSubnetIds.size() != 0) {
1541 "update : Start processing of the Subnet IDs removal during the update operation");
1542 for (Uuid removedSubnetId : removedSubnetIds) {
1543 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1544 if (subnetAddr != null) {
1546 1) Remove the subnet IP and the external IP in the IntExtIp map
1547 2) Decrease the count of the coresponding external IP by one.
1548 3) Advertise to the BGP for removing the routes of the corresponding external
1549 IP if its not allocated to any other internal IP.
1552 String externalIp = naptManager.getExternalIpAllocatedForSubnet(routerId,
1553 subnetAddr[0] + "/" + subnetAddr[1]);
1554 if (externalIp == null) {
1555 LOG.error("update : No mapping found for router ID {} and internal IP {}",
1556 routerId, subnetAddr[0]);
1560 naptManager.updateCounter(routerId, externalIp, false);
1561 // Traverse entire model of external-ip counter whether external ip is not
1562 // used by any other internal ip in any router
1563 if (!isExternalIpAllocated(externalIp)) {
1564 LOG.debug("update : external ip is not allocated to any other "
1565 + "internal IP so proceeding to remove routes");
1566 clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId,
1567 Collections.singleton(externalIp), null, update.getExtGwMacAddress(),
1569 LOG.debug("update : Successfully removed fib entries in switch {} for "
1570 + "router {} with networkId {} and externalIp {}",
1571 dpnId, routerId, networkId, externalIp);
1574 LOG.debug("update : Remove the IP mapping for the router ID {} and "
1575 + "internal IP {} external IP {}", routerId, subnetAddr[0], externalIp);
1576 naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1579 LOG.debug("update : End processing of the Subnet IDs removal during the update operation");
1584 }, NatConstants.NAT_DJC_MAX_RETRIES);
1587 private boolean isExternalIpAllocated(String externalIp) {
1588 InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1589 Optional<ExternalIpsCounter> externalCountersData =
1590 MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1591 if (externalCountersData.isPresent()) {
1592 ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1593 List<ExternalCounters> externalCounters = externalIpsCounters.getExternalCounters();
1594 for (ExternalCounters ext : externalCounters) {
1595 for (ExternalIpCounter externalIpCount : ext.getExternalIpCounter()) {
1596 if (externalIpCount.getExternalIp().equals(externalIp)) {
1597 if (externalIpCount.getCounter() != 0) {
1608 private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
1609 Uuid networkId, String subnetIp, WriteTransaction writeFlowInvTx) {
1610 String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1612 InetAddress address = InetAddress.getByName(subnetIpParts[0]);
1613 if (address instanceof Inet6Address) {
1614 LOG.debug("allocateExternalIp : Skipping ipv6 address {} for the router {}.", address, routerName);
1617 } catch (UnknownHostException e) {
1618 LOG.error("allocateExternalIp : Invalid ip address {}", subnetIpParts[0], e);
1621 String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1622 if (leastLoadedExtIpAddr != null) {
1623 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1624 String leastLoadedExtIp = externalIpParts[0];
1625 String leastLoadedExtIpPrefix = externalIpParts[1];
1626 IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1627 subnetIp = subnetIpParts[0];
1628 String subnetIpPrefix = subnetIpParts[1];
1629 IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1630 LOG.debug("allocateExternalIp : Add the IP mapping for the router ID {} and internal "
1631 + "IP {} and prefix {} -> external IP {} and prefix {}",
1632 routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1633 naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1636 // Check if external IP is already assigned a route. (i.e. External IP is previously
1637 // allocated to any of the subnets)
1638 // If external IP is already assigned a route, (, do not re-advertise to the BGP
1639 String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1640 Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1641 if (label != null) {
1643 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1644 IpMapKey ipMapKey = new IpMapKey(internalIp);
1645 LOG.debug("allocateExternalIp : Setting label {} for internalIp {} and externalIp {}",
1646 label, internalIp, leastLoadedExtIpAddrStr);
1647 IpMap newIpm = new IpMapBuilder().withKey(ipMapKey).setInternalIp(internalIp)
1648 .setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1649 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1650 naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1654 // Re-advertise to the BGP for the external IP, which is allocated to the subnet
1655 // for the first time and hence not having a route.
1656 //Get the VPN Name using the network ID
1657 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1658 if (vpnName != null) {
1659 LOG.debug("allocateExternalIp : Retrieved vpnName {} for networkId {}", vpnName, networkId);
1660 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1661 LOG.debug("allocateExternalIp : Best effort for getting primary napt switch when router i/f are"
1662 + "added after gateway-set");
1663 dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1664 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1665 LOG.error("allocateExternalIp : dpnId is null or Zero for the router {}", routerName);
1669 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1670 leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, networkId, router,
1676 protected Long checkExternalIpLabel(long routerId, String externalIp) {
1677 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1678 for (IpMap ipMap : ipMaps) {
1679 if (ipMap.getExternalIp().equals(externalIp)) {
1680 if (ipMap.getLabel() != null) {
1681 return ipMap.getLabel();
1685 LOG.error("checkExternalIpLabel : no ipMaps found for routerID:{} and externalIP:{}", routerId, externalIp);
1690 protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1691 LOG.trace("remove : Router delete method");
1693 ROUTER DELETE SCENARIO
1694 1) Get the router ID from the event.
1695 2) Build the cookie information from the router ID.
1696 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1697 4) Build the flow with the cookie value.
1698 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1699 6) Remove the flows from the other switches which points to the primary and secondary
1700 switches for the flows related the router ID.
1701 7) Get the list of external IP address maintained for the router ID.
1702 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1703 9) Withdraw the corresponding routes from the BGP.
1706 if (identifier == null || router == null) {
1707 LOG.error("remove : returning without processing since routers is null");
1711 String routerName = router.getRouterName();
1712 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.key(),
1713 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
1714 LOG.info("remove : Removing default NAT route from FIB on all dpns part of router {} ",
1716 List<ListenableFuture<Void>> futures = new ArrayList<>();
1717 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1718 if (routerId == NatConstants.INVALID_ID) {
1719 LOG.error("remove : Remove external router event - Invalid routerId for routerName {}",
1723 long bgpVpnId = NatConstants.INVALID_ID;
1724 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1725 if (bgpVpnUuid != null) {
1726 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1728 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, false,
1730 Uuid networkUuid = router.getNetworkId();
1732 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1733 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
1734 // No NAPT switch for external router, probably because the router is not attached to
1736 // internal networks
1738 "No NAPT switch for router {}, check if router is attached to any internal "
1743 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1744 handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId,
1747 NatOverVxlanUtil.releaseVNI(routerName, idManager);
1748 })), NatConstants.NAT_DJC_MAX_RETRIES);
1751 // TODO Clean up the exception handling
1752 @SuppressWarnings("checkstyle:IllegalCatch")
1753 public void handleDisableSnat(Routers router, Uuid networkUuid, @Nonnull Collection<String> externalIps,
1754 boolean routerFlag, String vpnName, BigInteger naptSwitchDpnId,
1755 long routerId, WriteTransaction removeFlowInvTx) {
1756 LOG.info("handleDisableSnat : Entry");
1757 String routerName = router.getRouterName();
1760 removeNaptSwitch(routerName);
1762 updateNaptSwitch(routerName, BigInteger.ZERO);
1765 LOG.debug("handleDisableSnat : Remove the ExternalCounter model for the router ID {}", routerId);
1766 naptManager.removeExternalCounter(routerId);
1768 LOG.debug("handleDisableSnat : got primarySwitch as dpnId {}", naptSwitchDpnId);
1769 if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
1770 LOG.error("handleDisableSnat : Unable to retrieve the primary NAPT switch for the "
1771 + "router ID {} from RouterNaptSwitch model", routerId);
1774 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
1776 if (extNwProvType == null) {
1777 LOG.error("handleDisableSnat : External Network Provider Type missing");
1780 Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps());
1781 removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnName, externalIps,
1782 externalSubnetList, removeFlowInvTx, extNwProvType);
1783 removeFlowsFromNonActiveSwitches(routerId, routerName, naptSwitchDpnId, removeFlowInvTx);
1785 String externalSubnetVpn = null;
1786 for (Uuid externalSubnetId : externalSubnetList) {
1787 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, externalSubnetId);
1788 // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
1789 if (externalSubnet.isPresent()) {
1790 externalSubnetVpn = externalSubnetId.getValue();
1791 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, externalSubnetVpn,
1792 router.getExtGwMacAddress(), removeFlowInvTx);
1795 if (externalSubnetVpn == null) {
1796 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnName,
1797 router.getExtGwMacAddress(), removeFlowInvTx);
1799 } catch (Exception ex) {
1800 LOG.error("handleDisableSnat : Failed to remove fib entries for routerId {} in naptSwitchDpnId {}",
1801 routerId, naptSwitchDpnId, ex);
1803 // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
1804 // for the router ID.
1805 LOG.debug("handleDisableSnat : Remove the Internal to external IP address maintained for the "
1806 + "router ID {} in the DS", routerId);
1807 naptManager.removeMapping(routerId);
1808 } catch (Exception ex) {
1809 LOG.error("handleDisableSnat : Exception while handling disableSNAT for router :{}", routerName, ex);
1811 LOG.info("handleDisableSnat : Exit");
1814 // TODO Clean up the exception handling
1815 @SuppressWarnings("checkstyle:IllegalCatch")
1816 public void handleDisableSnatInternetVpn(String routerName, long routerId, Uuid networkUuid,
1817 @Nonnull Collection<String> externalIps,
1818 String vpnId, WriteTransaction writeFlowInvTx) {
1819 LOG.debug("handleDisableSnatInternetVpn: Started to process handle disable snat for router {} "
1820 + "with internet vpn {}", routerName, vpnId);
1822 BigInteger naptSwitchDpnId = null;
1823 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
1824 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1825 Optional<RouterToNaptSwitch> rtrToNapt =
1826 read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1827 if (rtrToNapt.isPresent()) {
1828 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1830 LOG.debug("handleDisableSnatInternetVpn : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1832 removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId,
1835 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1836 if (extGwMacAddress != null) {
1837 LOG.debug("handleDisableSnatInternetVpn : External Gateway MAC address {} found for "
1838 + "External Router ID {}", extGwMacAddress, routerId);
1840 LOG.error("handleDisableSnatInternetVpn : No External Gateway MAC address found for "
1841 + "External Router ID {}", routerId);
1844 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId, extGwMacAddress,
1846 } catch (Exception ex) {
1847 LOG.error("handleDisableSnatInternetVpn : Failed to remove fib entries for routerId {} "
1848 + "in naptSwitchDpnId {}", routerId, naptSwitchDpnId, ex);
1850 NatOverVxlanUtil.releaseVNI(vpnId, idManager);
1851 } catch (Exception ex) {
1852 LOG.error("handleDisableSnatInternetVpn: Exception while handling disableSNATInternetVpn for router {} "
1853 + "with internet vpn {}", routerName, vpnId, ex);
1855 LOG.debug("handleDisableSnatInternetVpn: Processed handle disable snat for router {} with internet vpn {}",
1859 // TODO Clean up the exception handling
1860 @SuppressWarnings("checkstyle:IllegalCatch")
1861 public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1862 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
1863 .setPrimarySwitchId(naptSwitchId).build();
1865 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1866 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1867 } catch (Exception ex) {
1868 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
1869 naptSwitchId, routerName);
1871 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
1872 naptSwitchId, routerName);
1875 protected void removeNaptSwitch(String routerName) {
1876 // Remove router and switch from model
1877 InstanceIdentifier<RouterToNaptSwitch> id =
1878 InstanceIdentifier.builder(NaptSwitches.class)
1879 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1880 LOG.debug("removeNaptSwitch : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1881 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1882 //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
1883 NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
1886 public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
1887 BigInteger dpnId, Uuid networkId, String vpnName,
1888 @Nonnull Collection<String> externalIps,
1889 Collection<Uuid> externalSubnetList,
1890 WriteTransaction removeFlowInvTx, ProviderTypes extNwProvType) {
1891 LOG.debug("removeNaptFlowsFromActiveSwitch : Remove NAPT flows from Active switch");
1892 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1894 //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1895 // traffic which comes from the VMs of the NAPT switches)
1896 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1897 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1899 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1900 + "and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
1901 mdsalManager.removeFlowToTx(preSnatFlowEntity, removeFlowInvTx);
1903 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1904 // traffic which comes from the VMs of the non NAPT switches)
1905 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
1907 String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
1908 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1909 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1910 + "and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
1911 mdsalManager.removeFlowToTx(tsNatFlowEntity, removeFlowInvTx);
1913 //Remove the flow table 25->44 from NAPT Switch
1914 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1915 NatUtil.removePreDnatToSnatTableEntry(mdsalManager, dpnId, removeFlowInvTx);
1918 //Remove the Outbound flow entry which forwards the packet to FIB Table
1919 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {}"
1920 + " and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1922 String outboundTcpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1923 NwConstants.IP_PROT_TCP);
1924 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1925 outboundTcpNatFlowRef);
1926 mdsalManager.removeFlowToTx(outboundTcpNatFlowEntity, removeFlowInvTx);
1928 String outboundUdpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1929 NwConstants.IP_PROT_UDP);
1930 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1931 outboundUdpNatFlowRef);
1932 mdsalManager.removeFlowToTx(outboundUdpNatFlowEntity, removeFlowInvTx);
1934 String icmpDropFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1935 NwConstants.IP_PROT_ICMP);
1936 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1938 mdsalManager.removeFlowToTx(icmpDropFlowEntity, removeFlowInvTx);
1940 removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps, removeFlowInvTx);
1941 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
1942 // External Subnet Vpn Id.
1943 for (Uuid externalSubnetId : externalSubnetList) {
1944 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
1945 if (subnetVpnId != -1) {
1946 String natPfibSubnetFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
1947 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE,
1948 natPfibSubnetFlowRef);
1949 mdsalManager.removeFlowToTx(natPfibFlowEntity, removeFlowInvTx);
1950 LOG.debug("removeNaptFlowsFromActiveSwitch : Removed the flow in table {} with external subnet "
1951 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
1952 subnetVpnId, dpnId);
1956 //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1957 String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1958 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1960 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1961 + "and router ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
1962 mdsalManager.removeFlowToTx(natPfibFlowEntity, removeFlowInvTx);
1964 // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
1965 // - This does not work since ext-routers is deleted already - no network info
1966 //Get the VPN ID from the ExternalNetworks model
1968 if (vpnName == null || vpnName.isEmpty()) {
1969 // ie called from router delete cases
1970 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1971 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnUuid is {}", vpnUuid);
1972 if (vpnUuid != null) {
1973 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1974 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId {} for external network {} router delete or "
1975 + "disableSNAT scenario", vpnId, networkId);
1978 // ie called from disassociate vpn case
1979 LOG.debug("removeNaptFlowsFromActiveSwitch : This is disassociate nw with vpn case with vpnName {}",
1981 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1982 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId for disassociate nw with vpn scenario {}", vpnId);
1985 if (vpnId != NatConstants.INVALID_ID) {
1986 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1987 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
1988 FlowEntity natPfibVpnFlowEntity =
1989 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1990 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in {} for the active switch with the DPN ID {} "
1991 + "and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
1992 mdsalManager.removeFlowToTx(natPfibVpnFlowEntity, removeFlowInvTx);
1995 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
1996 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1997 if (ipPortMapping == null) {
1998 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the IpPortMapping");
2002 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2003 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
2004 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2005 for (IpPortMap ipPortMap : ipPortMaps) {
2006 String ipPortInternal = ipPortMap.getIpPortInternal();
2007 String[] ipPortParts = ipPortInternal.split(":");
2008 if (ipPortParts.length != 2) {
2009 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the Internal IP and port");
2012 String internalIp = ipPortParts[0];
2013 String internalPort = ipPortParts[1];
2015 //Build the flow for the outbound NAPT table
2016 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2017 + NatConstants.COLON_SEPARATOR + internalPort);
2018 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2019 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
2020 FlowEntity outboundNaptFlowEntity =
2021 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2023 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch "
2024 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2025 mdsalManager.removeFlowToTx(outboundNaptFlowEntity, removeFlowInvTx);
2027 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2028 String externalIp = ipPortExternal.getIpAddress();
2029 int externalPort = ipPortExternal.getPortNum();
2031 //Build the flow for the inbound NAPT table
2032 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2033 String.valueOf(routerId), externalIp, externalPort);
2034 FlowEntity inboundNaptFlowEntity =
2035 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2037 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active active switch "
2038 + "with the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2039 mdsalManager.removeFlowToTx(inboundNaptFlowEntity, removeFlowInvTx);
2044 protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
2045 @Nonnull Collection<String> externalIps,
2046 WriteTransaction writeFlowInvTx) {
2047 long extVpnId = NatConstants.INVALID_ID;
2048 if (networkId != null) {
2049 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
2050 if (vpnUuid != null) {
2051 extVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2053 LOG.debug("removeNaptFibExternalOutputFlows : vpnUuid is null");
2056 LOG.debug("removeNaptFibExternalOutputFlows : networkId is null");
2057 extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2059 if (extVpnId == NatConstants.INVALID_ID) {
2060 LOG.warn("removeNaptFibExternalOutputFlows : extVpnId not found for routerId {}", routerId);
2061 extVpnId = routerId;
2063 for (String ip : externalIps) {
2064 String extIp = removeMaskFromIp(ip);
2065 String naptFlowRef = getFlowRefNaptPreFib(dpnId, NwConstants.NAPT_PFIB_TABLE, extVpnId);
2066 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in table {} for the active switch"
2067 + " with the DPN ID {} and router ID {} and IP {} flowRef {}",
2068 NwConstants.NAPT_PFIB_TABLE, dpnId, routerId, extIp, naptFlowRef);
2069 FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef);
2070 mdsalManager.removeFlowToTx(natPfibVpnFlowEntity, writeFlowInvTx);
2074 private String removeMaskFromIp(String ip) {
2075 if (ip != null && !ip.trim().isEmpty()) {
2076 return ip.split("/")[0];
2081 public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
2082 BigInteger dpnId, Uuid networkId, String vpnName,
2083 WriteTransaction writeFlowInvTx) {
2084 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : Remove NAPT flows from Active switch Internet Vpn");
2085 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
2087 //Remove the NAPT PFIB TABLE entry
2089 if (vpnName != null) {
2090 // ie called from disassociate vpn case
2091 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : This is disassociate nw with vpn case "
2092 + "with vpnName {}", vpnName);
2093 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2094 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : vpnId for disassociate nw with vpn scenario {}",
2098 if (vpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker,
2099 networkId, routerName, dpnId)) {
2100 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2101 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2102 FlowEntity natPfibVpnFlowEntity =
2103 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2104 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the active switch "
2105 + "with the DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2106 mdsalManager.removeFlowToTx(natPfibVpnFlowEntity, writeFlowInvTx);
2108 // Remove IP-PORT active NAPT entries and release port from IdManager
2109 // For the router ID get the internal IP , internal port and the corresponding
2110 // external IP and external Port.
2111 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2112 if (ipPortMapping == null) {
2113 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the IpPortMapping");
2116 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2117 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
2118 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2119 for (IpPortMap ipPortMap : ipPortMaps) {
2120 String ipPortInternal = ipPortMap.getIpPortInternal();
2121 String[] ipPortParts = ipPortInternal.split(":");
2122 if (ipPortParts.length != 2) {
2123 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the Internal IP "
2127 String internalIp = ipPortParts[0];
2128 String internalPort = ipPortParts[1];
2130 //Build the flow for the outbound NAPT table
2131 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2132 + NatConstants.COLON_SEPARATOR + internalPort);
2133 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2134 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
2135 FlowEntity outboundNaptFlowEntity =
2136 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2138 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2139 + "active switch with the DPN ID {} and router ID {}",
2140 NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2141 mdsalManager.removeFlowToTx(outboundNaptFlowEntity, writeFlowInvTx);
2143 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2144 String externalIp = ipPortExternal.getIpAddress();
2145 int externalPort = ipPortExternal.getPortNum();
2147 //Build the flow for the inbound NAPT table
2148 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2149 String.valueOf(routerId), externalIp, externalPort);
2150 FlowEntity inboundNaptFlowEntity =
2151 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2153 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2154 + "active active switch with the DPN ID {} and router ID {}",
2155 NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2156 mdsalManager.removeFlowToTx(inboundNaptFlowEntity, writeFlowInvTx);
2158 // Finally release port from idmanager
2159 String internalIpPort = internalIp + ":" + internalPort;
2160 naptManager.removePortFromPool(internalIpPort, externalIp);
2162 //Remove sessions from models
2163 naptManager.removeIpPortMappingForRouterID(routerId);
2164 naptManager.removeIntIpPortMappingForRouterID(routerId);
2168 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Invalid vpnId {}", vpnId);
2172 public void removeFlowsFromNonActiveSwitches(long routerId, String routerName,
2173 BigInteger naptSwitchDpnId, WriteTransaction removeFlowInvTx) {
2174 LOG.debug("removeFlowsFromNonActiveSwitches : Remove NAPT related flows from non active switches");
2176 // Remove the flows from the other switches which points to the primary and secondary switches
2177 // for the flows related the router ID.
2178 List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
2179 if (allSwitchList.isEmpty()) {
2180 LOG.error("removeFlowsFromNonActiveSwitches : Unable to get the swithces for the router {}", routerName);
2183 for (BigInteger dpnId : allSwitchList) {
2184 if (!naptSwitchDpnId.equals(dpnId)) {
2185 LOG.info("removeFlowsFromNonActiveSwitches : Handle Ordinary switch");
2187 //Remove the PSNAT entry which forwards the packet to Terminating Service table
2188 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
2189 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
2191 LOG.info("removeFlowsFromNonActiveSwitches : Remove the flow in the {} for the non active switch "
2192 + "with the DPN ID {} and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
2193 mdsalManager.removeFlowToTx(preSnatFlowEntity, removeFlowInvTx);
2195 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
2196 long groupId = createGroupId(getGroupIdKey(routerName));
2197 List<BucketInfo> listBucketInfo = new ArrayList<>();
2198 GroupEntity preSnatGroupEntity =
2199 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
2201 LOG.info("removeFlowsFromNonActiveSwitches : Remove the group {} for the non active switch with "
2202 + "the DPN ID {} and router ID {}", groupId, dpnId, routerId);
2203 mdsalManager.removeGroup(preSnatGroupEntity);
2209 public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2210 @Nonnull Collection<String> externalIps, String vpnName,
2211 String extGwMacAddress, WriteTransaction removeFlowInvTx) {
2212 //Withdraw the corresponding routes from the BGP.
2213 //Get the network ID using the router ID.
2214 LOG.debug("clrRtsFromBgpAndDelFibTs : Advertise to BGP and remove routes for externalIps {} with routerId {},"
2215 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2216 if (networkUuid == null) {
2217 LOG.error("clrRtsFromBgpAndDelFibTs : networkId is null");
2221 if (externalIps.isEmpty()) {
2222 LOG.error("clrRtsFromBgpAndDelFibTs : externalIps is empty");
2226 if (vpnName == null) {
2227 //Get the VPN Name using the network ID
2228 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2229 if (vpnName == null) {
2230 LOG.error("clrRtsFromBgpAndDelFibTs : No VPN associated with ext nw {} for the router {}",
2231 networkUuid, routerId);
2235 LOG.debug("clrRtsFromBgpAndDelFibTs : Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2237 //Remove custom FIB routes
2238 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2239 for (String extIp : externalIps) {
2240 clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, removeFlowInvTx);
2244 protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2245 final Uuid networkUuid, String extGwMacAddress,
2246 WriteTransaction removeFlowInvTx) {
2247 clearBgpRoutes(extIp, vpnName);
2248 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2252 protected void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp,
2253 final String vpnName, Uuid extNetworkId, long tempLabel,
2254 String gwMacAddress, boolean switchOver,
2255 WriteTransaction removeFlowInvTx) {
2256 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2257 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2258 if (routerName == null) {
2259 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2262 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
2263 if (extNwProvType == null) {
2264 LOG.error("delFibTsAndReverseTraffic : External Network Provider Type Missing");
2267 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2268 * external network provided type is VxLAN
2270 if (extNwProvType == ProviderTypes.VXLAN) {
2271 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, gwMacAddress,
2275 if (tempLabel < 0) {
2276 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2281 final long label = tempLabel;
2282 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2283 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
2284 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label)
2285 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
2286 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2288 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2289 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2290 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2291 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2292 NatUtil.removePreDnatToSnatTableEntry(mdsalManager, dpnId, removeFlowInvTx);
2295 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2296 Futures.transformAsync(future, result -> {
2298 if (result.isSuccessful()) {
2299 NatUtil.removePreDnatToSnatTableEntry(mdsalManager, dpnId, removeFlowInvTx);
2300 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2301 .setVpnName(vpnName).setIpPrefix(externalIp).build();
2302 return vpnService.removeVpnLabel(labelInput);
2305 String.format("RPC call to remove custom FIB entries on dpn %s for "
2306 + "prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
2308 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2310 }, MoreExecutors.directExecutor());
2312 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2315 public void onFailure(@Nonnull Throwable error) {
2316 LOG.error("delFibTsAndReverseTraffic : Error in removing the label:{} or custom fib entries"
2317 + "got external ip {}", label, extIp, error);
2321 public void onSuccess(@Nonnull RpcResult<RemoveVpnLabelOutput> result) {
2322 if (result.isSuccessful()) {
2323 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2324 + "from VPN {}", externalIp, vpnName);
2326 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2327 + " from VPN {}, {}", externalIp, vpnName, result.getErrors());
2330 }, MoreExecutors.directExecutor());
2332 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2333 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2337 private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2338 final Uuid networkUuid, String extGwMacAddress, boolean switchOver,
2339 WriteTransaction removeFlowInvTx) {
2340 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2341 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2342 if (routerName == null) {
2343 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2346 //Get the external network provider type from networkId
2347 ProviderTypes extNwProvType = NatUtil.getProviderTypefromNetworkId(dataBroker, networkUuid);
2348 if (extNwProvType == null) {
2349 LOG.error("delFibTsAndReverseTraffic : Could not retrieve provider type for external network {} ",
2353 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2354 * external network provided type is VxLAN
2356 if (extNwProvType == ProviderTypes.VXLAN) {
2357 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, extGwMacAddress,
2361 //Get IPMaps from the DB for the router ID
2362 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
2363 if (dbIpMaps.isEmpty()) {
2364 LOG.error("delFibTsAndReverseTraffic : IPMaps not found for router {}", routerId);
2368 long tempLabel = NatConstants.INVALID_ID;
2369 for (IpMap dbIpMap : dbIpMaps) {
2370 String dbExternalIp = dbIpMap.getExternalIp();
2371 LOG.debug("delFibTsAndReverseTraffic : Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
2372 //Select the IPMap, whose external IP is the IP for which FIB is installed
2373 if (extIp.equals(dbExternalIp)) {
2374 tempLabel = dbIpMap.getLabel();
2375 LOG.debug("delFibTsAndReverseTraffic : Retrieved label {} for dbExternalIp {} with router id {}",
2376 tempLabel, dbExternalIp, routerId);
2380 if (tempLabel == NatConstants.INVALID_ID) {
2381 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2386 final long label = tempLabel;
2387 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2388 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
2389 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp)
2390 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).setServiceId(label).build();
2391 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2393 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2394 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2395 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2396 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2397 NatUtil.removePreDnatToSnatTableEntry(mdsalManager, dpnId, removeFlowInvTx);
2400 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2401 Futures.transformAsync(future, result -> {
2403 if (result.isSuccessful()) {
2404 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2405 .setVpnName(vpnName).setIpPrefix(externalIp).build();
2406 return vpnService.removeVpnLabel(labelInput);
2409 String.format("RPC call to remove custom FIB entries on dpn %s for "
2410 + "prefix %s Failed - %s",
2411 dpnId, externalIp, result.getErrors());
2413 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2415 }, MoreExecutors.directExecutor());
2417 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2420 public void onFailure(@Nonnull Throwable error) {
2421 LOG.error("delFibTsAndReverseTraffic : Error in removing the label or custom fib entries", error);
2425 public void onSuccess(@Nonnull RpcResult<RemoveVpnLabelOutput> result) {
2426 if (result.isSuccessful()) {
2427 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2428 + "from VPN {}", externalIp, vpnName);
2430 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2431 + " from VPN {}, {}", externalIp, vpnName, result.getErrors());
2434 }, MoreExecutors.directExecutor());
2436 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2437 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2441 protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2442 List<String> externalIps, String vpnName, String extGwMacAddress,
2443 WriteTransaction writeFlowInvTx) {
2444 //Withdraw the corresponding routes from the BGP.
2445 //Get the network ID using the router ID.
2446 LOG.debug("clearFibTsAndReverseTraffic : for externalIps {} with routerId {},"
2447 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2448 if (networkUuid == null) {
2449 LOG.error("clearFibTsAndReverseTraffic : networkId is null");
2453 if (externalIps == null || externalIps.isEmpty()) {
2454 LOG.error("clearFibTsAndReverseTraffic : externalIps is null");
2458 if (vpnName == null) {
2459 //Get the VPN Name using the network ID
2460 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2461 if (vpnName == null) {
2462 LOG.error("clearFibTsAndReverseTraffic : No VPN associated with ext nw {} for the router {}",
2463 networkUuid, routerId);
2467 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2469 //Remove custom FIB routes
2470 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2471 for (String extIp : externalIps) {
2472 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2477 protected void clearBgpRoutes(String externalIp, final String vpnName) {
2478 //Inform BGP about the route removal
2479 LOG.info("clearBgpRoutes : Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
2480 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
2481 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
2484 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId, WriteTransaction writeFlowInvTx) {
2485 LOG.info("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
2486 List<MatchInfo> mkMatches = new ArrayList<>();
2487 // Matching metadata
2488 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
2489 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
2490 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
2491 5, String.format("%s:%d", "TST Flow Entry ", serviceId), 0, 0,
2492 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
2493 mdsalManager.removeFlowToTx(dpnId, flowEntity, writeFlowInvTx);
2494 LOG.debug("removeTunnelTableEntry : dpID {} : label : {} removed successfully", dpnId, serviceId);
2497 private void removeLFibTableEntry(BigInteger dpnId, long serviceId, WriteTransaction writeFlowInvTx) {
2498 List<MatchInfo> matches = new ArrayList<>();
2499 matches.add(MatchEthernetType.MPLS_UNICAST);
2500 matches.add(new MatchMplsLabel(serviceId));
2502 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2504 LOG.debug("removeLFibTableEntry : with flow ref {}", flowRef);
2506 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
2508 COOKIE_VM_LFIB_TABLE, matches, null);
2510 mdsalManager.removeFlowToTx(dpnId, flowEntity, writeFlowInvTx);
2512 LOG.debug("removeLFibTableEntry : dpID : {} label : {} removed successfully", dpnId, serviceId);
2516 * router association to vpn.
2518 * @param routerName - Name of router
2519 * @param routerId - router id
2520 * @param bgpVpnName BGP VPN name
2522 public void changeLocalVpnIdToBgpVpnId(String routerName, long routerId, String bgpVpnName,
2523 WriteTransaction writeFlowInvTx, ProviderTypes extNwProvType) {
2524 LOG.debug("changeLocalVpnIdToBgpVpnId : Router associated to BGP VPN");
2525 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2526 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2528 LOG.debug("changeLocalVpnIdToBgpVpnId : BGP VPN ID value {} ", bgpVpnId);
2530 if (bgpVpnId != NatConstants.INVALID_ID) {
2531 LOG.debug("changeLocalVpnIdToBgpVpnId : Populate the router-id-name container with the "
2532 + "mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
2533 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
2534 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2535 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2536 getRoutersIdentifier(bgpVpnId), rtrs);
2538 // Get the allocated Primary NAPT Switch for this router
2539 LOG.debug("changeLocalVpnIdToBgpVpnId : Router ID value {} ", routerId);
2541 LOG.debug("changeLocalVpnIdToBgpVpnId : Update the Router ID {} to the BGP VPN ID {} ",
2542 routerId, bgpVpnId);
2543 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, true, writeFlowInvTx);
2546 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2547 createGroupId(getGroupIdKey(routerName));
2548 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true, writeFlowInvTx,
2555 * router disassociation from vpn.
2557 * @param routerName - Name of router
2558 * @param routerId - router id
2559 * @param bgpVpnName BGP VPN name
2561 public void changeBgpVpnIdToLocalVpnId(String routerName, long routerId, String bgpVpnName,
2562 WriteTransaction writeFlowInvTx, ProviderTypes extNwProvType) {
2563 LOG.debug("changeBgpVpnIdToLocalVpnId : Router dissociated from BGP VPN");
2564 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2565 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2566 LOG.debug("changeBgpVpnIdToLocalVpnId : BGP VPN ID value {} ", bgpVpnId);
2568 // Get the allocated Primary NAPT Switch for this router
2569 LOG.debug("changeBgpVpnIdToLocalVpnId : Router ID value {} ", routerId);
2571 LOG.debug("changeBgpVpnIdToLocalVpnId : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2572 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, NatConstants.INVALID_ID,
2573 true, writeFlowInvTx);
2576 createGroupId(getGroupIdKey(routerName));
2577 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2578 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true,
2579 writeFlowInvTx, extNwProvType);
2583 boolean chkExtRtrAndSnatEnbl(Uuid routerUuid) {
2584 InstanceIdentifier<Routers> routerInstanceIndentifier =
2585 InstanceIdentifier.builder(ExtRouters.class)
2586 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
2587 Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2588 return routerData.isPresent() && routerData.get().isEnableSnat();
2591 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2592 long routerId, boolean isSnatCfgd, WriteTransaction writeFlowInvTx,
2593 ProviderTypes extNwProvType) {
2594 long changedVpnId = bgpVpnId;
2595 String idType = "BGP VPN";
2596 if (bgpVpnId == NatConstants.INVALID_ID) {
2597 changedVpnId = routerId;
2601 List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2602 if (switches.isEmpty()) {
2603 LOG.error("installFlowsWithUpdatedVpnId : No switches found for router {}", routerName);
2606 for (BigInteger dpnId : switches) {
2607 // Update the BGP VPN ID in the SNAT miss entry to group
2608 if (!dpnId.equals(primarySwitchId)) {
2609 LOG.debug("installFlowsWithUpdatedVpnId : Install group in non NAPT switch {}", dpnId);
2610 List<BucketInfo> bucketInfoForNonNaptSwitches =
2611 getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName, routerId);
2612 long groupId = createGroupId(getGroupIdKey(routerName));
2614 groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
2618 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2619 + "{} in the non NAPT switch {}", idType, changedVpnId, groupId, dpnId);
2620 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
2621 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
2624 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2625 + "in the primary switch {}", idType, changedVpnId, primarySwitchId);
2626 FlowEntity flowEntity =
2627 buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2628 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
2631 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Terminating Service table (table "
2632 + "ID 36) which forwards the packet to the table 46 in the Primary switch {}",
2633 idType, changedVpnId, primarySwitchId);
2634 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, routerId,
2635 changedVpnId, writeFlowInvTx, extNwProvType);
2638 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Outbound NAPT table (table ID 46) "
2639 + "which punts the packet to the controller in the Primary switch {}",
2640 idType, changedVpnId, primarySwitchId);
2641 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, writeFlowInvTx);
2644 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT PFIB TABLE which forwards the"
2645 + " outgoing packet to FIB Table in the Primary switch {}",
2646 idType, changedVpnId, primarySwitchId);
2647 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, writeFlowInvTx);
2650 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT flows for the Outbound NAPT "
2651 + "table (table ID 46) and the INBOUND NAPT table (table ID 44) in the Primary switch"
2652 + " {}", idType, changedVpnId, primarySwitchId);
2653 updateNaptFlowsWithVpnId(primarySwitchId, routerName, routerId, bgpVpnId);
2655 LOG.debug("installFlowsWithUpdatedVpnId : Installing SNAT PFIB flow in the primary switch {}",
2657 Long vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2658 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2659 if (vpnId != NatConstants.INVALID_ID) {
2660 installNaptPfibEntry(primarySwitchId, vpnId, writeFlowInvTx);
2666 public void updateNaptFlowsWithVpnId(BigInteger dpnId, String routerName, long routerId, long bgpVpnId) {
2667 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2668 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2669 if (ipPortMapping == null) {
2670 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the IpPortMapping");
2673 // Get the External Gateway MAC Address
2674 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
2675 if (extGwMacAddress != null) {
2676 LOG.debug("updateNaptFlowsWithVpnId : External Gateway MAC address {} found for External Router ID {}",
2677 extGwMacAddress, routerId);
2679 LOG.error("updateNaptFlowsWithVpnId : No External Gateway MAC address found for External Router ID {}",
2683 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2684 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
2685 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2686 for (IpPortMap ipPortMap : ipPortMaps) {
2687 String ipPortInternal = ipPortMap.getIpPortInternal();
2688 String[] ipPortParts = ipPortInternal.split(":");
2689 if (ipPortParts.length != 2) {
2690 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the Internal IP and port");
2693 String internalIp = ipPortParts[0];
2694 String internalPort = ipPortParts[1];
2695 LOG.debug("updateNaptFlowsWithVpnId : Found Internal IP {} and Internal Port {}",
2696 internalIp, internalPort);
2697 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2698 NAPTEntryEvent.Protocol protocol;
2699 switch (protocolTypes) {
2701 protocol = NAPTEntryEvent.Protocol.TCP;
2704 protocol = NAPTEntryEvent.Protocol.UDP;
2707 protocol = NAPTEntryEvent.Protocol.TCP;
2709 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.parseInt(internalPort));
2710 SessionAddress externalAddress =
2711 naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2712 long internetVpnid = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2713 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
2714 routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
2715 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
2716 routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
2721 public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
2722 long changedVpnId) {
2724 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : called for dpId {}, routerName {} groupId {} "
2725 + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
2726 List<MatchInfo> matches = new ArrayList<>();
2727 matches.add(MatchEthernetType.IPV4);
2728 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2730 List<ActionInfo> actionsInfo = new ArrayList<>();
2731 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, changedVpnId,
2733 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
2734 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Setting the tunnel to the list of action infos {}",
2736 actionsInfo.add(new ActionGroup(groupId));
2737 List<InstructionInfo> instructions = new ArrayList<>();
2738 instructions.add(new InstructionApplyActions(actionsInfo));
2739 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2740 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2741 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2742 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2744 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Returning SNAT Flow Entity {}", flowEntity);
2748 public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
2749 long changedVpnId) {
2751 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : called for dpId {}, routerName {} "
2752 + "changed VPN ID {}", dpId, routerName, changedVpnId);
2753 List<MatchInfo> matches = new ArrayList<>();
2754 matches.add(MatchEthernetType.IPV4);
2755 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2757 List<InstructionInfo> instructions = new ArrayList<>();
2758 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2760 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2761 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2762 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2763 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2765 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : Returning SNAT Flow Entity {}", flowEntity);
2769 // TODO : Replace this with ITM Rpc once its available with full functionality
2770 protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
2771 long routerId, long changedVpnId, WriteTransaction writeFlowInvTx, ProviderTypes extNwProvType) {
2772 LOG.debug("installTerminatingServiceTblEntryWithUpdatedVpnId : called for switch {}, "
2773 + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2774 FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, routerId, changedVpnId,
2776 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
2779 private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName,
2780 long routerIdLongVal, long changedVpnId, ProviderTypes extNwProvType) {
2781 LOG.debug("buildTsFlowEntityWithUpdatedVpnId : called for switch {}, routerName {}, BGP VPN ID {}",
2782 dpId, routerName, changedVpnId);
2783 List<MatchInfo> matches = new ArrayList<>();
2784 matches.add(MatchEthernetType.IPV4);
2786 BigInteger tunnelId = BigInteger.valueOf(changedVpnId);
2787 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2788 tunnelId = NatOverVxlanUtil.getRouterVni(idManager, routerName, changedVpnId);
2790 matches.add(new MatchTunnelId(tunnelId));
2792 List<InstructionInfo> instructions = new ArrayList<>();
2793 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2794 MetaDataUtil.METADATA_MASK_VRFID));
2795 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2796 BigInteger routerId = BigInteger.valueOf(routerIdLongVal);
2797 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2798 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2799 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2800 NwConstants.COOKIE_TS_TABLE, matches, instructions);
2804 public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId,
2805 WriteTransaction writeFlowInvTx) {
2806 LOG.debug("createOutboundTblEntryWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2807 dpnId, routerId, changedVpnId);
2808 FlowEntity tcpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2809 NwConstants.IP_PROT_TCP);
2810 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing tcp flow {}", tcpFlowEntity);
2811 mdsalManager.addFlowToTx(tcpFlowEntity, writeFlowInvTx);
2813 FlowEntity udpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2814 NwConstants.IP_PROT_UDP);
2815 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing udp flow {}", udpFlowEntity);
2816 mdsalManager.addFlowToTx(udpFlowEntity, writeFlowInvTx);
2818 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, changedVpnId);
2819 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
2820 mdsalManager.addFlowToTx(icmpDropFlow, writeFlowInvTx);
2823 protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId,
2824 long changedVpnId, int protocol) {
2825 LOG.debug("buildOutboundFlowEntityWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2826 dpId, routerId, changedVpnId);
2827 BigInteger cookie = getCookieOutboundFlow(routerId);
2828 List<MatchInfo> matches = new ArrayList<>();
2829 matches.add(MatchEthernetType.IPV4);
2830 matches.add(new MatchIpProtocol((short)protocol));
2831 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2833 List<InstructionInfo> instructions = new ArrayList<>();
2834 List<ActionInfo> actionsInfos = new ArrayList<>();
2835 actionsInfos.add(new ActionPuntToController());
2836 if (snatPuntTimeout != 0) {
2837 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
2839 instructions.add(new InstructionApplyActions(actionsInfos));
2841 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
2842 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
2843 flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
2844 LOG.debug("createOutboundTblEntryWithBgpVpn : returning flowEntity {}", flowEntity);
2848 public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId,
2849 WriteTransaction writeFlowInvTx) {
2850 LOG.debug("installNaptPfibEntryWithBgpVpn : called for dpnId {} and segmentId {} ,BGP VPN ID {}",
2851 dpnId, segmentId, changedVpnId);
2852 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2853 mdsalManager.addFlowToTx(naptPfibFlowEntity, writeFlowInvTx);
2856 public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2858 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : called for dpId {}, "
2859 + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2860 List<MatchInfo> matches = new ArrayList<>();
2861 matches.add(MatchEthernetType.IPV4);
2862 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2864 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2865 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2866 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
2867 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2868 instructionInfo.add(new InstructionApplyActions(listActionInfo));
2870 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2871 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2872 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2873 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2874 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : Returning NaptPFib Flow Entity {}", flowEntity);
2879 protected ExternalRoutersListener getDataTreeChangeListener() {
2880 return ExternalRoutersListener.this;
2883 protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId,
2884 WriteTransaction writeFlowInvTx) {
2885 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
2887 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
2888 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
2889 if (subnetVpnId != -1) {
2890 LOG.debug("installNaptPfibEntriesForExternalSubnets : called for dpnId {} "
2891 + "and vpnId {}", dpnId, subnetVpnId);
2892 installNaptPfibEntry(dpnId, subnetVpnId, writeFlowInvTx);