2 * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.natservice.internal;
10 import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import com.google.common.base.Optional;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.math.BigInteger;
19 import java.net.Inet6Address;
20 import java.net.InetAddress;
21 import java.net.UnknownHostException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
30 import java.util.Objects;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.Future;
34 import javax.annotation.PostConstruct;
35 import javax.inject.Inject;
36 import javax.inject.Singleton;
37 import org.eclipse.jdt.annotation.NonNull;
38 import org.eclipse.jdt.annotation.Nullable;
39 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
40 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
41 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
42 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
43 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
44 import org.opendaylight.genius.infra.Datastore.Configuration;
45 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
46 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
47 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
48 import org.opendaylight.genius.infra.TypedWriteTransaction;
49 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
50 import org.opendaylight.genius.mdsalutil.ActionInfo;
51 import org.opendaylight.genius.mdsalutil.BucketInfo;
52 import org.opendaylight.genius.mdsalutil.FlowEntity;
53 import org.opendaylight.genius.mdsalutil.GroupEntity;
54 import org.opendaylight.genius.mdsalutil.InstructionInfo;
55 import org.opendaylight.genius.mdsalutil.MDSALUtil;
56 import org.opendaylight.genius.mdsalutil.MatchInfo;
57 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
58 import org.opendaylight.genius.mdsalutil.NwConstants;
59 import org.opendaylight.genius.mdsalutil.NwConstants.NxmOfFieldType;
60 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
61 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
62 import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
63 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromField;
64 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromValue;
65 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
66 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
67 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
68 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
69 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
70 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
71 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
72 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
73 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
74 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
75 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
76 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
77 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
78 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
79 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
80 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
81 import org.opendaylight.netvirt.elanmanager.api.IElanService;
82 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
83 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
84 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
85 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
86 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
87 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
130 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;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIds;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsBuilder;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsKey;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
143 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
144 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
145 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelOutput;
146 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
147 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
148 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
149 import org.opendaylight.yangtools.yang.common.RpcResult;
150 import org.slf4j.Logger;
151 import org.slf4j.LoggerFactory;
155 public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener> {
156 private static final Logger LOG = LoggerFactory.getLogger(ExternalRoutersListener.class);
158 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
159 private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
161 private final DataBroker dataBroker;
162 private final ManagedNewTransactionRunner txRunner;
163 private final IMdsalApiManager mdsalManager;
164 private final ItmRpcService itmManager;
165 private final OdlInterfaceRpcService odlInterfaceRpcService;
166 private final IdManagerService idManager;
167 private final NaptManager naptManager;
168 private final NAPTSwitchSelector naptSwitchSelector;
169 private final IBgpManager bgpManager;
170 private final VpnRpcService vpnService;
171 private final FibRpcService fibService;
172 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
173 private final NaptEventHandler naptEventHandler;
174 private final NaptPacketInHandler naptPacketInHandler;
175 private final IFibManager fibManager;
176 private final IVpnManager vpnManager;
177 private final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer;
178 private final NatMode natMode;
179 private final IElanService elanManager;
180 private final JobCoordinator coordinator;
181 private final IInterfaceManager interfaceManager;
182 private final NatOverVxlanUtil natOverVxlanUtil;
183 private final int snatPuntTimeout;
186 public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
187 final ItmRpcService itmManager,
188 final OdlInterfaceRpcService odlInterfaceRpcService,
189 final IdManagerService idManager,
190 final NaptManager naptManager,
191 final NAPTSwitchSelector naptSwitchSelector,
192 final IBgpManager bgpManager,
193 final VpnRpcService vpnService,
194 final FibRpcService fibService,
195 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
196 final NaptEventHandler naptEventHandler,
197 final NaptPacketInHandler naptPacketInHandler,
198 final IFibManager fibManager,
199 final IVpnManager vpnManager,
200 final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer,
201 final NatserviceConfig config,
202 final IElanService elanManager,
203 final JobCoordinator coordinator,
204 final NatOverVxlanUtil natOverVxlanUtil,
205 final IInterfaceManager interfaceManager) {
206 super(Routers.class, ExternalRoutersListener.class);
207 this.dataBroker = dataBroker;
208 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
209 this.mdsalManager = mdsalManager;
210 this.itmManager = itmManager;
211 this.odlInterfaceRpcService = odlInterfaceRpcService;
212 this.idManager = idManager;
213 this.naptManager = naptManager;
214 this.naptSwitchSelector = naptSwitchSelector;
215 this.bgpManager = bgpManager;
216 this.vpnService = vpnService;
217 this.fibService = fibService;
218 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
219 this.naptEventHandler = naptEventHandler;
220 this.naptPacketInHandler = naptPacketInHandler;
221 this.fibManager = fibManager;
222 this.vpnManager = vpnManager;
223 this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
224 this.elanManager = elanManager;
225 this.coordinator = coordinator;
226 this.interfaceManager = interfaceManager;
227 this.natOverVxlanUtil = natOverVxlanUtil;
228 if (config != null) {
229 this.natMode = config.getNatMode();
230 this.snatPuntTimeout = config.getSnatPuntTimeout().intValue();
232 this.natMode = NatMode.Controller;
233 this.snatPuntTimeout = 0;
240 LOG.info("{} init", getClass().getSimpleName());
241 // This class handles ExternalRouters for Controller SNAT mode.
242 // For Conntrack SNAT mode, its handled in SnatExternalRoutersListener.java
243 if (natMode == NatMode.Controller) {
244 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
245 NatUtil.createGroupIdPool(idManager);
250 protected InstanceIdentifier<Routers> getWildCardPath() {
251 return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
255 // TODO Clean up the exception handling
256 @SuppressWarnings("checkstyle:IllegalCatch")
257 protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
258 // Populate the router-id-name container
259 String routerName = routers.getRouterName();
260 LOG.info("add : external router event for {}", routerName);
261 long routerId = NatUtil.getVpnId(dataBroker, routerName);
262 NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
263 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
265 if (routers.isEnableSnat()) {
266 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routers.key(),
267 () -> Collections.singletonList(
268 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
269 LOG.info("add : Installing NAT default route on all dpns part of router {}", routerName);
270 long bgpVpnId = NatConstants.INVALID_ID;
271 if (bgpVpnUuid != null) {
272 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
274 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, true, confTx);
275 // Allocate Primary Napt Switch for this router
276 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName);
277 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
278 handleEnableSnat(routers, routerId, primarySwitchId, bgpVpnId, confTx);
281 )), NatConstants.NAT_DJC_MAX_RETRIES);
283 LOG.info("add : SNAT is disabled for external router {} ", routerName);
285 } catch (Exception ex) {
286 LOG.error("add : Exception while Installing NAT flows on all dpns as part of router {}",
291 public void handleEnableSnat(Routers routers, long routerId, BigInteger primarySwitchId, long bgpVpnId,
292 TypedWriteTransaction<Configuration> confTx) {
293 String routerName = routers.getRouterName();
294 LOG.info("handleEnableSnat : Handling SNAT for router {}", routerName);
296 naptManager.initialiseExternalCounter(routers, routerId);
297 subnetRegisterMapping(routers, routerId);
299 LOG.debug("handleEnableSnat:About to create and install outbound miss entry in Primary Switch {} for router {}",
300 primarySwitchId, routerName);
302 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
303 routers.getNetworkId());
304 if (extNwProvType == null) {
305 LOG.error("handleEnableSnat : External Network Provider Type missing");
309 if (bgpVpnId != NatConstants.INVALID_ID) {
310 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, false, confTx,
313 // write metadata and punt
314 installOutboundMissEntry(routerName, routerId, primarySwitchId, confTx);
315 // Now install entries in SNAT tables to point to Primary for each router
316 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
317 for (BigInteger dpnId : switches) {
318 // Handle switches and NAPT switches separately
319 if (!dpnId.equals(primarySwitchId)) {
320 LOG.debug("handleEnableSnat : Handle Ordinary switch");
321 handleSwitches(dpnId, routerName, routerId, primarySwitchId);
323 LOG.debug("handleEnableSnat : Handle NAPT switch");
324 handlePrimaryNaptSwitch(dpnId, routerName, routerId, confTx);
329 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
330 if (externalIps.isEmpty()) {
331 LOG.error("handleEnableSnat : Internal External mapping not found for router {}", routerName);
334 for (String externalIpAddrPrefix : externalIps) {
335 LOG.debug("handleEnableSnat : Calling handleSnatReverseTraffic for primarySwitchId {}, "
336 + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
337 handleSnatReverseTraffic(confTx, primarySwitchId, routers, routerId, routerName, externalIpAddrPrefix
341 LOG.debug("handleEnableSnat : Exit");
344 private BigInteger getPrimaryNaptSwitch(String routerName) {
345 // Allocate Primary Napt Switch for this router
346 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
347 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
348 LOG.debug("getPrimaryNaptSwitch : Primary NAPT switch with DPN ID {} is already elected for router {}",
349 primarySwitchId, routerName);
350 return primarySwitchId;
352 // Allocated an id from VNI pool for the Router.
353 natOverVxlanUtil.getRouterVni(routerName, NatConstants.INVALID_ID);
354 primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
355 LOG.debug("getPrimaryNaptSwitch : Primary NAPT switch DPN ID {}", primarySwitchId);
357 return primarySwitchId;
360 protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId,
361 TypedWriteTransaction<Configuration> confTx) {
362 Long extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
363 if (extVpnId == NatConstants.INVALID_ID) {
364 LOG.error("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
367 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
368 if (externalIps.isEmpty()) {
369 LOG.error("installNaptPfibExternalOutputFlow - empty external Ips list for dpnId {} extVpnId {}",
373 for (String ip : externalIps) {
374 Uuid subnetId = getSubnetIdForFixedIp(ip);
375 if (subnetId != null) {
376 long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
377 if (subnetVpnId != NatConstants.INVALID_ID) {
378 extVpnId = subnetVpnId;
380 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
381 dpnId, extVpnId, subnetId);
382 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
383 mdsalManager.addFlow(confTx, postNaptFlowEntity);
389 private Uuid getSubnetIdForFixedIp(String ip) {
391 IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
392 Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
393 return NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
395 LOG.error("getSubnetIdForFixedIp : ip is null");
399 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
400 LOG.debug("subnetRegisterMapping : Fetching values from extRouters model");
401 List<String> externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
403 int extIpCounter = externalIps.size();
404 LOG.debug("subnetRegisterMapping : counter values before looping counter {} and extIpCounter {}",
405 counter, extIpCounter);
406 @Nullable List<Uuid> subnetIds = routerEntry.getSubnetIds();
407 if (subnetIds == null) {
410 for (Uuid subnet : subnetIds) {
411 LOG.debug("subnetRegisterMapping : Looping internal subnets for subnet {}", subnet);
412 InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
413 .builder(Subnetmaps.class)
414 .child(Subnetmap.class, new SubnetmapKey(subnet))
416 Optional<Subnetmap> sn;
418 sn = SingleTransactionDataBroker.syncReadOptional(dataBroker,
419 LogicalDatastoreType.CONFIGURATION, subnetmapId);
420 } catch (ReadFailedException e) {
421 LOG.error("Failed to read SubnetMap for subnetmap Id {}", subnetmapId, e);
422 sn = Optional.absent();
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, TypedReadWriteTransaction<Configuration> confTx)
493 throws ExecutionException, InterruptedException {
494 //Check if BGP VPN exists. If exists then invoke the new method.
495 if (bgpVpnId != NatConstants.INVALID_ID) {
496 if (bgpVpnUuid != null) {
497 String bgpVpnName = bgpVpnUuid.getValue();
498 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
499 bgpVpnId, bgpVpnName);
500 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
501 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
502 confTx.put(getRoutersIdentifier(bgpVpnId), rtrs, CREATE_MISSING_PARENTS);
505 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
507 removeDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
512 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
513 addOrDelDefaultFibRouteForSNAT(routerName, routerId, create, confTx);
516 private void addOrDelDefaultFibRouteForSNAT(String routerName, long routerId, boolean create,
517 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
518 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
519 if (switches.isEmpty()) {
520 LOG.info("addOrDelDefaultFibRouteForSNAT : No switches found for router {}", routerName);
523 if (routerId == NatConstants.INVALID_ID) {
524 LOG.error("addOrDelDefaultFibRouteForSNAT : Could not retrieve router Id for {} to program "
525 + "default NAT route in FIB", routerName);
528 for (BigInteger dpnId : switches) {
530 LOG.debug("addOrDelDefaultFibRouteForSNAT : installing default NAT route for router {} in dpn {} "
531 + "for the internal vpn-id {}", routerId, dpnId, routerId);
532 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
534 LOG.debug("addOrDelDefaultFibRouteForSNAT : removing default NAT route for router {} in dpn {} "
535 + "for the internal vpn-id {}", routerId, dpnId, routerId);
536 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
541 private void addDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
542 long bgpVpnId, TypedWriteTransaction<Configuration> confTx) {
543 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
544 if (dpnIds.isEmpty()) {
545 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
546 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
549 for (BigInteger dpnId : dpnIds) {
550 if (bgpVpnId != NatConstants.INVALID_ID) {
551 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
552 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
553 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
555 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
556 + "in dpn {} for the internal vpn", routerId, dpnId);
557 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
562 private void removeDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
563 long bgpVpnId, TypedReadWriteTransaction<Configuration> confTx)
564 throws ExecutionException, InterruptedException {
565 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
566 if (dpnIds.isEmpty()) {
567 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
568 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
571 for (BigInteger dpnId : dpnIds) {
572 if (bgpVpnId != NatConstants.INVALID_ID) {
573 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
574 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
575 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
577 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
578 + "in dpn {} for the internal vpn", routerId, dpnId);
579 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
584 protected void installOutboundMissEntry(String routerName, long routerId, BigInteger primarySwitchId,
585 TypedWriteTransaction<Configuration> confTx) {
586 LOG.debug("installOutboundMissEntry : Router ID from getVpnId {}", routerId);
587 if (routerId != NatConstants.INVALID_ID) {
588 LOG.debug("installOutboundMissEntry : Creating miss entry on primary {}, for router {}",
589 primarySwitchId, routerId);
590 createOutboundTblEntry(primarySwitchId, routerId, confTx);
592 LOG.error("installOutboundMissEntry : Unable to fetch Router Id for RouterName {}, failed to "
593 + "createAndInstallMissEntry", routerName);
597 public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID, int protocol) {
598 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
599 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + protocol;
602 private String getFlowRefNaptPreFib(BigInteger dpnId, short tableId, long vpnId) {
603 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
604 .FLOWID_SEPARATOR + vpnId;
607 public BigInteger getCookieOutboundFlow(long routerId) {
608 return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
609 BigInteger.valueOf(routerId));
612 private ActionLearn getLearnActionForPunt(int protocol, int hardTimeout, BigInteger cookie) {
615 int l4portFieldLen = NxmOfFieldType.NXM_OF_TCP_SRC.getFlowModHeaderLenInt();
617 if (protocol == NwConstants.IP_PROT_TCP) {
618 l4SrcPortField = NxmOfFieldType.NXM_OF_TCP_SRC.getType();
619 l4DstPortField = NxmOfFieldType.NXM_OF_TCP_DST.getType();
621 l4SrcPortField = NxmOfFieldType.NXM_OF_UDP_SRC.getType();
622 l4DstPortField = NxmOfFieldType.NXM_OF_UDP_DST.getType();
624 List<ActionLearn.FlowMod> flowMods = Arrays.asList(
625 new MatchFromValue(NwConstants.ETHTYPE_IPV4, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
626 NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
627 new MatchFromValue(protocol, NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
628 NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
629 new MatchFromField(NxmOfFieldType.NXM_OF_IP_SRC.getType(), NxmOfFieldType.NXM_OF_IP_SRC.getType(),
630 NxmOfFieldType.NXM_OF_IP_SRC.getFlowModHeaderLenInt()),
631 new MatchFromField(NxmOfFieldType.NXM_OF_IP_DST.getType(), NxmOfFieldType.NXM_OF_IP_DST.getType(),
632 NxmOfFieldType.NXM_OF_IP_DST.getFlowModHeaderLenInt()),
633 new MatchFromField(l4SrcPortField, l4SrcPortField, l4portFieldLen),
634 new MatchFromField(l4DstPortField, l4DstPortField, l4portFieldLen),
635 new MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
636 MetaDataUtil.METADATA_VPN_ID_OFFSET,
637 NxmOfFieldType.OXM_OF_METADATA.getType(), MetaDataUtil.METADATA_VPN_ID_OFFSET,
638 MetaDataUtil.METADATA_VPN_ID_BITLEN));
640 return new ActionLearn(0, hardTimeout, 7, cookie, 0,
641 NwConstants.OUTBOUND_NAPT_TABLE, 0, 0, flowMods);
644 private FlowEntity buildIcmpDropFlow(BigInteger dpnId, long routerId, long vpnId) {
645 List<MatchInfo> matches = new ArrayList<>();
646 matches.add(MatchEthernetType.IPV4);
647 matches.add(MatchIpProtocol.ICMP);
648 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
650 List<ActionInfo> actionInfos = new ArrayList<>();
651 actionInfos.add(new ActionDrop());
653 List<InstructionInfo> instructions = new ArrayList<>();
654 instructions.add(new InstructionApplyActions(actionInfos));
656 String flowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
657 NwConstants.IP_PROT_ICMP);
658 FlowEntity flow = MDSALUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
659 NwConstants.TABLE_MISS_PRIORITY, "icmp drop flow", 0, 0,
660 NwConstants.COOKIE_OUTBOUND_NAPT_TABLE, matches, instructions);
664 protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId, int protocol) {
665 LOG.debug("buildOutboundFlowEntity : called for dpId {} and routerId{}", dpId, routerId);
666 BigInteger cookie = getCookieOutboundFlow(routerId);
667 List<MatchInfo> matches = new ArrayList<>();
668 matches.add(MatchEthernetType.IPV4);
669 matches.add(new MatchIpProtocol((short)protocol));
670 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
672 List<InstructionInfo> instructions = new ArrayList<>();
673 List<ActionInfo> actionsInfos = new ArrayList<>();
674 actionsInfos.add(new ActionPuntToController());
675 if (snatPuntTimeout != 0) {
676 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
678 instructions.add(new InstructionApplyActions(actionsInfos));
680 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
681 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
683 cookie, matches, instructions);
684 LOG.debug("installOutboundMissEntry : returning flowEntity {}", flowEntity);
688 public void createOutboundTblEntry(BigInteger dpnId, long routerId, TypedWriteTransaction<Configuration> confTx) {
689 LOG.debug("createOutboundTblEntry : called for dpId {} and routerId {}", dpnId, routerId);
690 FlowEntity tcpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_TCP);
691 LOG.debug("createOutboundTblEntry : Installing tcp flow {}", tcpflowEntity);
692 mdsalManager.addFlow(confTx, tcpflowEntity);
694 FlowEntity udpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_UDP);
695 LOG.debug("createOutboundTblEntry : Installing udp flow {}", udpflowEntity);
696 mdsalManager.addFlow(confTx, udpflowEntity);
698 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, routerId);
699 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
700 mdsalManager.addFlow(confTx, icmpDropFlow);
704 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
705 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
706 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
708 Future<RpcResult<GetTunnelInterfaceNameOutput>> result =
709 itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
710 .setSourceDpid(srcDpId)
711 .setDestinationDpid(dstDpId)
712 .setTunnelType(tunType)
714 rpcResult = result.get();
715 if (!rpcResult.isSuccessful()) {
716 tunType = TunnelTypeGre.class;
717 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
718 .setSourceDpid(srcDpId)
719 .setDestinationDpid(dstDpId)
720 .setTunnelType(tunType)
722 rpcResult = result.get();
723 if (!rpcResult.isSuccessful()) {
724 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
725 rpcResult.getErrors());
727 return rpcResult.getResult().getInterfaceName();
729 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
730 rpcResult.getErrors());
732 return rpcResult.getResult().getInterfaceName();
734 } catch (InterruptedException | ExecutionException | NullPointerException e) {
735 LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
736 + "between {} and {}", srcDpId, dstDpId, e);
742 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName, long routerId,
743 TypedWriteTransaction<Configuration> confTx) {
745 LOG.debug("installSnatMissEntry : called for for the primary NAPT switch dpnId {} ", dpnId);
746 // Install miss entry pointing to group
747 FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName, routerId);
748 mdsalManager.addFlow(confTx, flowEntity);
751 protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo,
752 String routerName, long routerId) {
753 LOG.debug("installSnatMissEntry : called for dpnId {} with primaryBucket {} ",
754 dpnId, bucketInfo.get(0));
755 // Install the select group
756 long groupId = createGroupId(getGroupIdKey(routerName));
757 GroupEntity groupEntity =
758 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
759 LOG.debug("installSnatMissEntry : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
760 mdsalManager.syncInstallGroup(groupEntity);
761 // Install miss entry pointing to group
762 FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, routerId, groupId);
763 if (flowEntity == null) {
764 LOG.error("installSnatMissEntry : Flow entity received as NULL. "
765 + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
766 + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
769 mdsalManager.installFlow(flowEntity);
772 long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo) {
773 long groupId = createGroupId(getGroupIdKey(routerName));
774 GroupEntity groupEntity =
775 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
776 LOG.debug("installGroup : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
777 mdsalManager.syncInstallGroup(groupEntity);
781 private FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long routerId, long groupId) {
782 LOG.debug("buildSnatFlowEntity : called for dpId {}, routerName {} and groupId {}",
783 dpId, routerName, groupId);
784 List<MatchInfo> matches = new ArrayList<>();
785 matches.add(MatchEthernetType.IPV4);
786 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
788 List<ActionInfo> actionsInfo = new ArrayList<>();
789 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager, idManager,
790 routerId, routerName);
791 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
792 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
793 actionsInfo.add(new ActionGroup(groupId));
794 List<InstructionInfo> instructions = new ArrayList<>();
795 instructions.add(new InstructionApplyActions(actionsInfo));
796 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
797 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
798 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
799 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
801 LOG.debug("buildSnatFlowEntity : Returning SNAT Flow Entity {}", flowEntity);
805 private FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName, long routerId) {
807 LOG.debug("buildSnatFlowEntityForPrmrySwtch : called for primary NAPT switch dpId {}, routerName {}", dpId,
809 List<MatchInfo> matches = new ArrayList<>();
810 matches.add(MatchEthernetType.IPV4);
811 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
813 List<InstructionInfo> instructions = new ArrayList<>();
814 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
816 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
817 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
818 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
819 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
821 LOG.debug("buildSnatFlowEntityForPrmrySwtch : Returning SNAT Flow Entity {}", flowEntity);
825 // TODO : Replace this with ITM Rpc once its available with full functionality
826 protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName, long routerId,
827 TypedWriteTransaction<Configuration> confTx) {
829 LOG.debug("installTerminatingServiceTblEntry : for switch {}, routerName {}",
831 FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName, routerId);
832 if (flowEntity == null) {
833 LOG.error("installTerminatingServiceTblEntry : Flow entity received as NULL. "
834 + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
835 + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
839 mdsalManager.addFlow(confTx, flowEntity);
843 private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName, long routerId) {
844 List<MatchInfo> matches = new ArrayList<>();
845 matches.add(MatchEthernetType.IPV4);
846 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
847 idManager, routerId, routerName);
848 matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
849 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
850 List<InstructionInfo> instructions = new ArrayList<>();
851 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
852 MetaDataUtil.METADATA_MASK_VRFID));
853 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
854 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
855 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
860 public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
861 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
862 .FLOWID_SEPARATOR + routerID;
865 public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
866 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
867 .FLOWID_SEPARATOR + routerID;
870 private String getGroupIdKey(String routerName) {
871 return "snatmiss." + routerName;
874 protected long createGroupId(String groupIdKey) {
875 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
876 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
879 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
880 RpcResult<AllocateIdOutput> rpcResult = result.get();
881 return rpcResult.getResult().getIdValue();
882 } catch (NullPointerException | InterruptedException | ExecutionException e) {
883 LOG.error("Exception While allocating id for group: {}", groupIdKey, e);
888 protected void handleSwitches(BigInteger dpnId, String routerName, long routerId, BigInteger primarySwitchId) {
889 LOG.debug("handleSwitches : Installing SNAT miss entry in switch {}", dpnId);
890 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
891 String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
892 List<BucketInfo> listBucketInfo = new ArrayList<>();
894 if (ifNamePrimary != null) {
895 LOG.debug("handleSwitches : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
896 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
897 interfaceManager, ifNamePrimary, routerId, true);
898 if (listActionInfoPrimary.isEmpty()) {
899 LOG.error("handleSwitches : Unable to retrieve output actions on Non-NAPT switch {} for router {}"
900 + " towards Napt-switch {} via tunnel interface {}", dpnId, routerName, primarySwitchId,
904 LOG.error("handleSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} from "
905 + "Non-Napt switch {} for router {}", primarySwitchId, dpnId, routerName);
907 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
909 listBucketInfo.add(0, bucketPrimary);
910 installSnatMissEntry(dpnId, listBucketInfo, routerName, routerId);
913 List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
914 BigInteger primarySwitchId, String routerName, long routerId) {
915 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
916 String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
917 List<BucketInfo> listBucketInfo = new ArrayList<>();
919 if (ifNamePrimary != null) {
920 LOG.debug("getBucketInfoForNonNaptSwitches : On Non- Napt switch , Primary Tunnel interface is {}",
922 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
923 interfaceManager, ifNamePrimary, routerId, true);
924 if (listActionInfoPrimary.isEmpty()) {
925 LOG.error("getBucketInfoForNonNaptSwitches : Unable to retrieve output actions on Non-NAPT switch {} "
926 + "for router {} towards Napt-switch {} via tunnel interface {}",
927 nonNaptSwitchId, routerName, primarySwitchId, ifNamePrimary);
930 LOG.error("getBucketInfoForNonNaptSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} "
931 + "from Non-Napt switch {} for router {}", primarySwitchId, nonNaptSwitchId, routerName);
933 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
935 listBucketInfo.add(0, bucketPrimary);
936 return listBucketInfo;
939 protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName, long routerId,
940 TypedWriteTransaction<Configuration> confTx) {
943 * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
946 LOG.debug("handlePrimaryNaptSwitch : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
949 List<BucketInfo> listBucketInfo = new ArrayList<>();
950 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
951 listActionInfoPrimary.add(new ActionNxResubmit(NatConstants.TERMINATING_SERVICE_TABLE));
952 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
953 listBucketInfo.add(0, bucketPrimary);
956 installSnatMissEntryForPrimrySwch(dpnId, routerName, routerId, confTx);
957 installTerminatingServiceTblEntry(dpnId, routerName, routerId, confTx);
958 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
959 installNaptPfibEntry(dpnId, routerId, confTx);
960 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
961 if (networkId != null) {
962 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
963 if (vpnUuid != null) {
964 long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
965 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
966 installNaptPfibEntriesForExternalSubnets(routerName, dpnId, null);
967 //Install the NAPT PFIB TABLE which forwards outgoing packet to FIB Table matching on the VPN ID.
968 if (vpnId != NatConstants.INVALID_ID) {
969 installNaptPfibEntry(dpnId, vpnId, null);
971 return Collections.emptyList();
974 LOG.warn("handlePrimaryNaptSwitch : External Vpn ID missing for Ext-Network : {}", networkId);
977 LOG.warn("handlePrimaryNaptSwitch : External Network not available for router : {}", routerName);
981 public void installNaptPfibEntry(BigInteger dpnId, long segmentId,
982 @Nullable TypedWriteTransaction<Configuration> confTx) {
983 LOG.debug("installNaptPfibEntry : called for dpnId {} and segmentId {} ", dpnId, segmentId);
984 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
985 if (confTx != null) {
986 mdsalManager.addFlow(confTx, naptPfibFlowEntity);
988 mdsalManager.installFlow(naptPfibFlowEntity);
992 public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
994 LOG.debug("buildNaptPfibFlowEntity : called for dpId {}, segmentId {}", dpId, segmentId);
995 List<MatchInfo> matches = new ArrayList<>();
996 matches.add(MatchEthernetType.IPV4);
997 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
999 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
1000 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
1001 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
1002 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
1003 instructionInfo.add(new InstructionApplyActions(listActionInfo));
1005 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
1006 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
1007 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
1008 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
1009 LOG.debug("buildNaptPfibFlowEntity : Returning NaptPFib Flow Entity {}", flowEntity);
1013 public void handleSnatReverseTraffic(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, Routers router,
1014 long routerId, String routerName, String externalIp) {
1015 LOG.debug("handleSnatReverseTraffic : entry for DPN ID {}, routerId {}, externalIp: {}",
1016 dpnId, routerId, externalIp);
1017 Uuid networkId = router.getNetworkId();
1018 if (networkId == null) {
1019 LOG.error("handleSnatReverseTraffic : networkId is null for the router ID {}", routerId);
1022 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1023 if (vpnName == null) {
1024 LOG.error("handleSnatReverseTraffic : No VPN associated with ext nw {} to handle add external ip "
1025 + "configuration {} in router {}", networkId, externalIp, routerId);
1028 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1029 externalIp, networkId, router, confTx);
1030 LOG.debug("handleSnatReverseTraffic : exit for DPN ID {}, routerId {}, externalIp : {}",
1031 dpnId, routerId, externalIp);
1034 public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
1035 final long routerId, final String routerName, final String externalIp,
1036 final Uuid extNetworkId, @Nullable final Routers router,
1037 final TypedWriteTransaction<Configuration> confTx) {
1038 LOG.debug("advToBgpAndInstallFibAndTsFlows : entry for DPN ID {}, tableId {}, vpnname {} "
1039 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
1040 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
1041 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1042 if (rd == null || rd.isEmpty()) {
1043 LOG.error("advToBgpAndInstallFibAndTsFlows : Unable to get RD for VPN Name {}", vpnName);
1046 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
1047 if (extNwProvType == null) {
1048 LOG.error("advToBgpAndInstallFibAndTsFlows : External Network Provider Type missing");
1051 if (extNwProvType == ProviderTypes.VXLAN) {
1052 evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
1053 nextHopIp, routerId, routerName, extNetworkId, confTx);
1056 //Generate VPN label for the external IP
1057 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
1058 .setIpPrefix(externalIp).build();
1059 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
1061 //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
1062 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
1063 if (result.isSuccessful()) {
1064 LOG.debug("advToBgpAndInstallFibAndTsFlows : inside apply with result success");
1065 GenerateVpnLabelOutput output = result.getResult();
1066 final long label = output.getLabel();
1068 int externalIpInDsFlag = 0;
1069 //Get IPMaps from the DB for the router ID
1070 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
1071 for (IpMap dbIpMap : dbIpMaps) {
1072 String dbExternalIp = dbIpMap.getExternalIp();
1073 //Select the IPMap, whose external IP is the IP for which FIB is installed
1074 if (dbExternalIp.contains(externalIp)) {
1075 String dbInternalIp = dbIpMap.getInternalIp();
1076 IpMapKey dbIpMapKey = dbIpMap.key();
1077 LOG.debug("advToBgpAndInstallFibAndTsFlows : Setting label {} for internalIp {} "
1078 + "and externalIp {}", label, dbInternalIp, externalIp);
1079 IpMap newIpm = new IpMapBuilder().withKey(dbIpMapKey).setInternalIp(dbInternalIp)
1080 .setExternalIp(dbExternalIp).setLabel(label).build();
1081 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1082 naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
1083 externalIpInDsFlag++;
1086 if (externalIpInDsFlag <= 0) {
1087 LOG.debug("advToBgpAndInstallFibAndTsFlows : External Ip {} not found in DS, "
1088 + "Failed to update label {} for routerId {} in DS",
1089 externalIp, label, routerId);
1090 String errMsg = String.format("Failed to update label %s due to external Ip %s not"
1091 + " found in DS for router %s", label, externalIp, routerId);
1092 return Futures.immediateFailedFuture(new Exception(errMsg));
1096 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1097 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni).longValue();
1099 Routers extRouter = router != null ? router :
1100 NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1101 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
1102 externalIp, nextHopIp, extRouter.getNetworkId().getValue(), null, label, l3vni,
1103 RouteOrigin.STATIC, dpnId);
1105 //Install custom FIB routes
1106 List<Instruction> tunnelTableCustomInstructions = new ArrayList<>();
1107 tunnelTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
1108 makeTunnelTableEntry(dpnId, label, l3vni, tunnelTableCustomInstructions, confTx,
1110 makeLFibTableEntry(dpnId, label, tableId, confTx);
1112 //Install custom FIB routes - FIB table.
1113 List<Instruction> fibTableCustomInstructions = createFibTableCustomInstructions(tableId,
1114 routerName, externalIp);
1115 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1116 //Install the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
1117 NatUtil.makePreDnatToSnatTableEntry(mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, confTx);
1119 String externalVpn = vpnName;
1120 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp, extRouter);
1121 if (extNwProvType == ProviderTypes.VLAN || extNwProvType == ProviderTypes.FLAT) {
1122 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
1124 if (externalSubnet.isPresent()) {
1125 externalVpn = externalSubnetId.getValue();
1128 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1129 CreateFibEntryInput input = new CreateFibEntryInputBuilder()
1130 .setVpnName(externalVpn)
1131 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
1132 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
1133 .setInstruction(fibTableCustomInstructions).build();
1134 return fibService.createFibEntry(input);
1136 LOG.error("advToBgpAndInstallFibAndTsFlows : inside apply with result failed");
1137 String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
1138 externalIp, vpnName, result.getErrors());
1139 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1141 }, MoreExecutors.directExecutor());
1143 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
1146 public void onFailure(@NonNull Throwable error) {
1147 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in generate label or fib install process", error);
1151 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
1152 if (result.isSuccessful()) {
1153 LOG.info("advToBgpAndInstallFibAndTsFlows : Successfully installed custom FIB routes for prefix {}",
1156 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in rpc call to create custom Fib entries "
1157 + "for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
1160 }, MoreExecutors.directExecutor());
1163 private List<Instruction> createFibTableCustomInstructions(short tableId, String routerName,
1164 String externalIp) {
1165 List<Instruction> fibTableCustomInstructions = new ArrayList<>();
1166 Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1167 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
1168 externalIp, router);
1169 int instructionIndex = 0;
1170 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
1171 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
1172 fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
1173 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
1177 fibTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(instructionIndex));
1178 return fibTableCustomInstructions;
1181 private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId,
1182 TypedWriteTransaction<Configuration> confTx) {
1183 List<MatchInfo> matches = new ArrayList<>();
1184 matches.add(MatchEthernetType.MPLS_UNICAST);
1185 matches.add(new MatchMplsLabel(serviceId));
1187 List<Instruction> instructions = new ArrayList<>();
1188 List<ActionInfo> actionsInfos = new ArrayList<>();
1189 //NAT is required for IPv4 only. Hence always etherType will be IPv4
1190 actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
1191 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
1192 instructions.add(writeInstruction);
1193 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
1195 // Install the flow entry in L3_LFIB_TABLE
1196 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1198 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1200 COOKIE_VM_LFIB_TABLE, matches, instructions);
1202 mdsalManager.addFlow(confTx, dpId, flowEntity);
1204 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
1207 private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, long l3Vni,
1208 List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx,
1209 ProviderTypes extNwProvType) {
1211 List<MatchInfo> mkMatches = new ArrayList<>();
1213 LOG.debug("makeTunnelTableEntry : DpnId = {} and serviceId = {} and actions = {}",
1214 dpnId, serviceId, customInstructions);
1216 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1217 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
1219 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
1222 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1223 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5,
1224 String.format("%s:%d", "TST Flow Entry ", serviceId),
1225 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1227 mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
1230 protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1231 return InstanceIdentifier.builder(RouterIdName.class).child(RouterIds.class,
1232 new RouterIdsKey(routerId)).build();
1235 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1236 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
1237 .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
1241 protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1242 String routerName = original.getRouterName();
1243 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1244 if (routerId == NatConstants.INVALID_ID) {
1245 LOG.error("update : external router event - Invalid routerId for routerName {}", routerName);
1248 // Check if its update on SNAT flag
1249 boolean originalSNATEnabled = original.isEnableSnat();
1250 boolean updatedSNATEnabled = update.isEnableSnat();
1251 LOG.debug("update :called with originalFlag and updatedFlag for SNAT enabled "
1252 + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
1253 /* Get Primary Napt Switch for existing router from "router-to-napt-switch" DS.
1254 * if dpnId value is null or zero then go for electing new Napt switch for existing router.
1256 long bgpVpnId = NatConstants.INVALID_ID;
1257 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1258 if (bgpVpnUuid != null) {
1259 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1261 BigInteger dpnId = getPrimaryNaptSwitch(routerName);
1262 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1263 // Router has no interface attached
1266 final long finalBgpVpnId = bgpVpnId;
1267 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + update.key(), () -> {
1268 List<ListenableFuture<Void>> futures = new ArrayList<>();
1269 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeFlowInvTx -> {
1270 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, removeFlowInvTx -> {
1271 Uuid networkId = original.getNetworkId();
1272 if (originalSNATEnabled != updatedSNATEnabled) {
1273 if (originalSNATEnabled) {
1274 //SNAT disabled for the router
1275 Uuid networkUuid = original.getNetworkId();
1276 LOG.info("update : SNAT disabled for Router {}", routerName);
1277 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1278 handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId, routerId,
1281 LOG.info("update : SNAT enabled for Router {}", original.getRouterName());
1282 addOrDelDefFibRouteToSNAT(routerName, routerId, finalBgpVpnId, bgpVpnUuid,
1283 true, writeFlowInvTx);
1284 handleEnableSnat(update, routerId, dpnId, finalBgpVpnId, writeFlowInvTx);
1287 if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1288 NatUtil.installRouterGwFlows(txRunner, vpnManager, original, dpnId, NwConstants.DEL_FLOW);
1289 NatUtil.installRouterGwFlows(txRunner, vpnManager, update, dpnId, NwConstants.ADD_FLOW);
1292 if (updatedSNATEnabled != originalSNATEnabled) {
1293 LOG.info("update : no need to process external/subnet changes as it's will taken care in "
1294 + "handleDisableSnat/handleEnableSnat");
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 removed during the update.
1303 Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
1304 removedExternalIps.removeAll(updatedExternalIps);
1305 if (removedExternalIps.size() > 0) {
1306 LOG.debug("update : Start processing of the External IPs removal during the update "
1308 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
1309 removedExternalIps, original.getExtGwMacAddress(),
1312 for (String removedExternalIp : removedExternalIps) {
1314 1) Remove the mappings in the IntExt IP model which has external IP.
1315 2) Remove the external IP in the ExternalCounter model.
1316 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the
1317 least loaded external IP.
1318 Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1319 4) Increase the count of the allocated external IP by one.
1320 5) Advertise to the BGP if external IP is allocated for the first time for the router
1321 i.e. the route for the external IP is absent.
1322 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for
1323 the removed external IPs and also from the model.
1324 7) Advertise to the BGP for removing the route for the removed external IPs.
1327 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1328 String externalIp = externalIpParts[0];
1329 String externalIpPrefix = externalIpParts[1];
1330 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1332 LOG.debug("update : Clear the routes from the BGP and remove the FIB and TS "
1333 + "entries for removed external IP {}", externalIpAddrStr);
1334 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1335 String vpnName = "";
1336 if (vpnUuId != null) {
1337 vpnName = vpnUuId.getValue();
1339 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName, networkId,
1340 update.getExtGwMacAddress(), removeFlowInvTx);
1342 LOG.debug("update : Remove the mappings in the IntExtIP model which has external IP.");
1343 //Get the internal IPs which are associated to the removed external IPs
1344 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1345 List<String> removedInternalIps = new ArrayList<>();
1346 for (IpMap ipMap : ipMaps) {
1347 if (ipMap.getExternalIp().equals(externalIpAddrStr)) {
1348 removedInternalIps.add(ipMap.getInternalIp());
1352 LOG.debug("update : Remove the mappings of the internal IPs from the IntExtIP model.");
1353 for (String removedInternalIp : removedInternalIps) {
1354 LOG.debug("update : Remove the IP mapping of the internal IP {} for the "
1355 + "router ID {} from the IntExtIP model",
1356 removedInternalIp, routerId);
1357 naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1360 LOG.debug("update : Remove the count mapping of the external IP {} for the "
1361 + "router ID {} from the ExternalIpsCounter model.",
1362 externalIpAddrStr, routerId);
1363 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1365 LOG.debug("update : Allocate the least loaded external IPs to the subnets "
1366 + "whose external IPs were removed.");
1367 for (String removedInternalIp : removedInternalIps) {
1368 allocateExternalIp(dpnId, update, routerId, routerName, networkId,
1369 removedInternalIp, writeFlowInvTx);
1371 LOG.debug("update : Remove the NAPT translation entries from "
1372 + "Inbound and Outbound NAPT tables for the removed external IPs.");
1373 //Get the internalIP and internal Port which were associated to the removed external IP.
1374 List<Integer> externalPorts = new ArrayList<>();
1375 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1376 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier
1377 .builder(IntextIpPortMap.class)
1378 .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1379 Optional<IpPortMapping> ipPortMapping;
1381 ipPortMapping = SingleTransactionDataBroker
1382 .syncReadOptional(dataBroker,
1383 LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1384 } catch (ReadFailedException e) {
1385 LOG.error("Failed to read ipPortMapping for router id {}", routerId, e);
1386 ipPortMapping = Optional.absent();
1389 if (ipPortMapping.isPresent()) {
1390 for (IntextIpProtocolType intextIpProtocolType :
1391 ipPortMapping.get().nonnullIntextIpProtocolType()) {
1392 ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1393 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
1394 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1395 if (ipPortExternal.getIpAddress().equals(externalIp)) {
1396 externalPorts.add(ipPortExternal.getPortNum());
1397 List<String> removedInternalIpPorts =
1398 protoTypesIntIpPortsMap.get(protoType);
1399 if (removedInternalIpPorts != null) {
1400 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1401 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1403 removedInternalIpPorts = new ArrayList<>();
1404 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1405 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1412 //Remove the IP port map from the intext-ip-port-map model, which were containing
1413 // the removed external IP.
1414 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts =
1415 protoTypesIntIpPortsMap.entrySet();
1416 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1417 for (Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts) {
1418 ProtocolTypes protocolType = (ProtocolTypes) protoTypesIntIpPort.getKey();
1419 List<String> removedInternalIpPorts = (List<String>) protoTypesIntIpPort.getValue();
1420 for (String removedInternalIpPort : removedInternalIpPorts) {
1421 // Remove the IP port map from the intext-ip-port-map model,
1422 // which were containing the removed external IP
1423 naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort,
1425 //Remove the IP port incomint packer map.
1426 naptPacketInHandler.removeIncomingPacketMap(
1427 routerId + NatConstants.COLON_SEPARATOR + removedInternalIpPort);
1428 String[] removedInternalIpPortParts = removedInternalIpPort
1429 .split(NatConstants.COLON_SEPARATOR);
1430 if (removedInternalIpPortParts.length == 2) {
1431 String removedInternalIp = removedInternalIpPortParts[0];
1432 String removedInternalPort = removedInternalIpPortParts[1];
1433 List<String> removedInternalPortsList =
1434 internalIpPortMap.get(removedInternalPort);
1435 if (removedInternalPortsList != null) {
1436 removedInternalPortsList.add(removedInternalPort);
1437 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1439 removedInternalPortsList = new ArrayList<>();
1440 removedInternalPortsList.add(removedInternalPort);
1441 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1447 // Delete the entry from SnatIntIpPortMap DS
1448 Set<String> internalIps = internalIpPortMap.keySet();
1449 for (String internalIp : internalIps) {
1450 LOG.debug("update : Removing IpPort having the internal IP {} from the "
1451 + "model SnatIntIpPortMap", internalIp);
1452 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1455 naptManager.removeNaptPortPool(externalIp);
1457 LOG.debug("update : Remove the NAPT translation entries from Inbound NAPT tables for "
1458 + "the removed external IP {}", externalIp);
1459 for (Integer externalPort : externalPorts) {
1460 //Remove the NAPT translation entries from Inbound NAPT table
1461 naptEventHandler.removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1462 routerId, externalIp, externalPort);
1465 Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
1466 for (Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
1467 String internalIp = internalIpPort.getKey();
1468 LOG.debug("update : Remove the NAPT translation entries from Outbound NAPT tables "
1469 + "for the removed internal IP {}", internalIp);
1470 List<String> internalPorts = internalIpPort.getValue();
1471 for (String internalPort : internalPorts) {
1472 //Remove the NAPT translation entries from Outbound NAPT table
1473 naptPacketInHandler.removeIncomingPacketMap(
1474 routerId + NatConstants.COLON_SEPARATOR + internalIp
1475 + NatConstants.COLON_SEPARATOR + internalPort);
1476 naptEventHandler.removeNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1477 routerId, internalIp, Integer.parseInt(internalPort));
1482 "update : End processing of the External IPs removal during the update operation");
1485 //Check if the External IPs are added during the update.
1486 Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
1487 addedExternalIps.removeAll(originalExternalIps);
1488 if (addedExternalIps.size() != 0) {
1489 LOG.debug("update : Start processing of the External IPs addition during the update "
1491 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
1492 update.getExtGwMacAddress(), dpnId,
1493 update.getNetworkId());
1495 for (String addedExternalIp : addedExternalIps) {
1497 1) Do nothing in the IntExtIp model.
1498 2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1500 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1501 String externalIp = externalIpParts[0];
1502 String externalIpPrefix = externalIpParts[1];
1503 String externalpStr = externalIp + "/" + externalIpPrefix;
1504 LOG.debug("update : Initialise the count mapping of the external IP {} for the "
1505 + "router ID {} in the ExternalIpsCounter model.",
1506 externalpStr, routerId);
1507 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1508 subnetRegisterMapping(update, routerId);
1509 LOG.info("update : Installing fib flow fo newly added Ips");
1510 handleSnatReverseTraffic(writeFlowInvTx, dpnId, update, routerId, routerName, externalpStr);
1513 "update : End processing of the External IPs addition during the update operation");
1516 //Check if its Update on subnets
1517 LOG.debug("update : Checking if this is update on subnets");
1518 List<Uuid> originalSubnetIds = original.getSubnetIds();
1519 List<Uuid> updatedSubnetIds = update.getSubnetIds();
1520 Set<Uuid> addedSubnetIds =
1521 updatedSubnetIds != null ? new HashSet<>(updatedSubnetIds) : new HashSet<>();
1522 if (originalSubnetIds != null) {
1523 addedSubnetIds.removeAll(originalSubnetIds);
1526 //Check if the Subnet IDs are added during the update.
1527 if (addedSubnetIds.size() != 0) {
1529 "update : Start processing of the Subnet IDs addition during the update operation");
1530 for (Uuid addedSubnetId : addedSubnetIds) {
1532 1) Select the least loaded external IP for the subnet and store the mapping of the
1533 subnet IP and the external IP in the IntExtIp model.
1534 2) Increase the count of the selected external IP by one.
1535 3) Advertise to the BGP if external IP is allocated for the first time for the
1536 router i.e. the route for the external IP is absent.
1538 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1539 if (subnetIp != null) {
1540 allocateExternalIp(dpnId, update, routerId, routerName, networkId, subnetIp,
1544 LOG.debug("update : End processing of the Subnet IDs addition during the update operation");
1547 //Check if the Subnet IDs are removed during the update.
1548 Set<Uuid> removedSubnetIds = new HashSet<>(originalSubnetIds);
1549 removedSubnetIds.removeAll(updatedSubnetIds);
1550 if (removedSubnetIds.size() != 0) {
1552 "update : Start processing of the Subnet IDs removal during the update operation");
1553 for (Uuid removedSubnetId : removedSubnetIds) {
1554 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1555 if (subnetAddr != null) {
1557 1) Remove the subnet IP and the external IP in the IntExtIp map
1558 2) Decrease the count of the coresponding external IP by one.
1559 3) Advertise to the BGP for removing the routes of the corresponding external
1560 IP if its not allocated to any other internal IP.
1563 String externalIp = naptManager.getExternalIpAllocatedForSubnet(routerId,
1564 subnetAddr[0] + "/" + subnetAddr[1]);
1565 if (externalIp == null) {
1566 LOG.error("update : No mapping found for router ID {} and internal IP {}",
1567 routerId, subnetAddr[0]);
1571 naptManager.updateCounter(routerId, externalIp, false);
1572 // Traverse entire model of external-ip counter whether external ip is not
1573 // used by any other internal ip in any router
1574 if (!isExternalIpAllocated(externalIp)) {
1575 LOG.debug("update : external ip is not allocated to any other "
1576 + "internal IP so proceeding to remove routes");
1577 clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId,
1578 Collections.singleton(externalIp), null, update.getExtGwMacAddress(),
1580 LOG.debug("update : Successfully removed fib entries in switch {} for "
1581 + "router {} with networkId {} and externalIp {}",
1582 dpnId, routerId, networkId, externalIp);
1585 LOG.debug("update : Remove the IP mapping for the router ID {} and "
1586 + "internal IP {} external IP {}", routerId, subnetAddr[0], externalIp);
1587 naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1590 LOG.debug("update : End processing of the Subnet IDs removal during the update operation");
1595 }, NatConstants.NAT_DJC_MAX_RETRIES);
1598 private boolean isExternalIpAllocated(String externalIp) {
1599 InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1600 Optional<ExternalIpsCounter> externalCountersData;
1602 externalCountersData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1603 LogicalDatastoreType.OPERATIONAL, id);
1604 } catch (ReadFailedException e) {
1605 LOG.error("Failed to read external counters data for ExternalIp {}", externalIp, e);
1606 externalCountersData = Optional.absent();
1608 if (externalCountersData.isPresent()) {
1609 ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1610 for (ExternalCounters ext : externalIpsCounters.nonnullExternalCounters()) {
1611 for (ExternalIpCounter externalIpCount : ext.nonnullExternalIpCounter()) {
1612 if (externalIpCount.getExternalIp().equals(externalIp)) {
1613 if (externalIpCount.getCounter() != 0) {
1624 private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
1625 Uuid networkId, String subnetIp, TypedWriteTransaction<Configuration> writeFlowInvTx) {
1626 String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1628 InetAddress address = InetAddress.getByName(subnetIpParts[0]);
1629 if (address instanceof Inet6Address) {
1630 LOG.debug("allocateExternalIp : Skipping ipv6 address {} for the router {}.", address, routerName);
1633 } catch (UnknownHostException e) {
1634 LOG.error("allocateExternalIp : Invalid ip address {}", subnetIpParts[0], e);
1637 String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1638 if (leastLoadedExtIpAddr != null) {
1639 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1640 String leastLoadedExtIp = externalIpParts[0];
1641 String leastLoadedExtIpPrefix = externalIpParts[1];
1642 IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1643 subnetIp = subnetIpParts[0];
1644 String subnetIpPrefix = subnetIpParts[1];
1645 IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1646 LOG.debug("allocateExternalIp : Add the IP mapping for the router ID {} and internal "
1647 + "IP {} and prefix {} -> external IP {} and prefix {}",
1648 routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1649 naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1652 // Check if external IP is already assigned a route. (i.e. External IP is previously
1653 // allocated to any of the subnets)
1654 // If external IP is already assigned a route, (, do not re-advertise to the BGP
1655 String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1656 Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1657 if (label != null) {
1659 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1660 IpMapKey ipMapKey = new IpMapKey(internalIp);
1661 LOG.debug("allocateExternalIp : Setting label {} for internalIp {} and externalIp {}",
1662 label, internalIp, leastLoadedExtIpAddrStr);
1663 IpMap newIpm = new IpMapBuilder().withKey(ipMapKey).setInternalIp(internalIp)
1664 .setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1665 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1666 naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1670 // Re-advertise to the BGP for the external IP, which is allocated to the subnet
1671 // for the first time and hence not having a route.
1672 //Get the VPN Name using the network ID
1673 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1674 if (vpnName != null) {
1675 LOG.debug("allocateExternalIp : Retrieved vpnName {} for networkId {}", vpnName, networkId);
1676 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1677 LOG.debug("allocateExternalIp : Best effort for getting primary napt switch when router i/f are"
1678 + "added after gateway-set");
1679 dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1680 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1681 LOG.error("allocateExternalIp : dpnId is null or Zero for the router {}", routerName);
1685 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1686 leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, networkId, router,
1693 protected Long checkExternalIpLabel(long routerId, String externalIp) {
1694 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1695 for (IpMap ipMap : ipMaps) {
1696 if (ipMap.getExternalIp().equals(externalIp)) {
1697 if (ipMap.getLabel() != null) {
1698 return ipMap.getLabel();
1702 LOG.error("checkExternalIpLabel : no ipMaps found for routerID:{} and externalIP:{}", routerId, externalIp);
1707 protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1708 LOG.trace("remove : Router delete method");
1710 ROUTER DELETE SCENARIO
1711 1) Get the router ID from the event.
1712 2) Build the cookie information from the router ID.
1713 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1714 4) Build the flow with the cookie value.
1715 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1716 6) Remove the flows from the other switches which points to the primary and secondary
1717 switches for the flows related the router ID.
1718 7) Get the list of external IP address maintained for the router ID.
1719 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1720 9) Withdraw the corresponding routes from the BGP.
1723 if (identifier == null || router == null) {
1724 LOG.error("remove : returning without processing since routers is null");
1728 String routerName = router.getRouterName();
1729 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.key(),
1730 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
1731 LOG.info("remove : Removing default NAT route from FIB on all dpns part of router {} ",
1733 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1734 if (routerId == NatConstants.INVALID_ID) {
1735 LOG.error("remove : Remove external router event - Invalid routerId for routerName {}",
1739 long bgpVpnId = NatConstants.INVALID_ID;
1740 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1741 if (bgpVpnUuid != null) {
1742 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1744 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, false,
1746 Uuid networkUuid = router.getNetworkId();
1748 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1749 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
1750 // No NAPT switch for external router, probably because the router is not attached to
1752 // internal networks
1754 "No NAPT switch for router {}, check if router is attached to any internal "
1759 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1760 handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId,
1763 natOverVxlanUtil.releaseVNI(routerName);
1764 })), NatConstants.NAT_DJC_MAX_RETRIES);
1767 public void handleDisableSnat(Routers router, Uuid networkUuid, @NonNull Collection<String> externalIps,
1768 boolean routerFlag, @Nullable String vpnName, BigInteger naptSwitchDpnId,
1769 long routerId, TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
1770 LOG.info("handleDisableSnat : Entry");
1771 String routerName = router.getRouterName();
1774 removeNaptSwitch(routerName);
1776 updateNaptSwitch(routerName, BigInteger.ZERO);
1779 LOG.debug("handleDisableSnat : Remove the ExternalCounter model for the router ID {}", routerId);
1780 naptManager.removeExternalCounter(routerId);
1782 LOG.debug("handleDisableSnat : got primarySwitch as dpnId {}", naptSwitchDpnId);
1783 if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
1784 LOG.error("handleDisableSnat : Unable to retrieve the primary NAPT switch for the "
1785 + "router ID {} from RouterNaptSwitch model", routerId);
1788 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
1790 if (extNwProvType == null) {
1791 LOG.error("handleDisableSnat : External Network Provider Type missing");
1794 Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps());
1795 removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnName, externalIps,
1796 externalSubnetList, removeFlowInvTx, extNwProvType);
1797 removeFlowsFromNonActiveSwitches(routerId, routerName, naptSwitchDpnId, removeFlowInvTx);
1798 String externalSubnetVpn = null;
1799 for (Uuid externalSubnetId : externalSubnetList) {
1800 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, externalSubnetId);
1801 // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
1802 if (externalSubnet.isPresent()) {
1803 externalSubnetVpn = externalSubnetId.getValue();
1804 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, externalSubnetVpn,
1805 router.getExtGwMacAddress(), removeFlowInvTx);
1808 if (externalSubnetVpn == null) {
1809 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnName,
1810 router.getExtGwMacAddress(), removeFlowInvTx);
1812 // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
1813 // for the router ID.
1814 LOG.debug("handleDisableSnat : Remove the Internal to external IP address maintained for the "
1815 + "router ID {} in the DS", routerId);
1816 naptManager.removeMapping(routerId);
1817 } catch (InterruptedException | ExecutionException e) {
1818 LOG.error("handleDisableSnat : Exception while handling disableSNAT for router :{}", routerName, e);
1820 LOG.info("handleDisableSnat : Exit");
1823 // TODO Clean up the exception handling
1824 @SuppressWarnings("checkstyle:IllegalCatch")
1825 public void handleDisableSnatInternetVpn(String routerName, long routerId, Uuid networkUuid,
1826 @NonNull Collection<String> externalIps,
1827 String vpnId, TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
1828 LOG.debug("handleDisableSnatInternetVpn: Started to process handle disable snat for router {} "
1829 + "with internet vpn {}", routerName, vpnId);
1831 BigInteger naptSwitchDpnId = null;
1832 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
1833 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1834 Optional<RouterToNaptSwitch> rtrToNapt;
1836 rtrToNapt = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1837 LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1838 } catch (ReadFailedException e) {
1839 LOG.error("Failed to read NAPT switch for router {}", routerName, e);
1840 rtrToNapt = Optional.absent();
1842 if (rtrToNapt.isPresent()) {
1843 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1845 LOG.debug("handleDisableSnatInternetVpn : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1847 removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId,
1850 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1851 if (extGwMacAddress != null) {
1852 LOG.debug("handleDisableSnatInternetVpn : External Gateway MAC address {} found for "
1853 + "External Router ID {}", extGwMacAddress, routerId);
1855 LOG.error("handleDisableSnatInternetVpn : No External Gateway MAC address found for "
1856 + "External Router ID {}", routerId);
1859 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId, extGwMacAddress,
1861 } catch (Exception ex) {
1862 LOG.error("handleDisableSnatInternetVpn : Failed to remove fib entries for routerId {} "
1863 + "in naptSwitchDpnId {}", routerId, naptSwitchDpnId, ex);
1865 natOverVxlanUtil.releaseVNI(vpnId);
1866 } catch (InterruptedException | ExecutionException e) {
1867 LOG.error("handleDisableSnatInternetVpn: Exception while handling disableSNATInternetVpn for router {} "
1868 + "with internet vpn {}", routerName, vpnId, e);
1870 LOG.debug("handleDisableSnatInternetVpn: Processed handle disable snat for router {} with internet vpn {}",
1874 // TODO Clean up the exception handling
1875 @SuppressWarnings("checkstyle:IllegalCatch")
1876 public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1877 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
1878 .setPrimarySwitchId(naptSwitchId).build();
1880 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1881 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1882 } catch (Exception ex) {
1883 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
1884 naptSwitchId, routerName);
1886 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
1887 naptSwitchId, routerName);
1890 protected void removeNaptSwitch(String routerName) {
1891 // Remove router and switch from model
1892 InstanceIdentifier<RouterToNaptSwitch> id =
1893 InstanceIdentifier.builder(NaptSwitches.class)
1894 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1895 LOG.debug("removeNaptSwitch : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1896 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1897 //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
1898 NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
1901 public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
1902 BigInteger dpnId, Uuid networkId, String vpnName,
1903 @NonNull Collection<String> externalIps,
1904 Collection<Uuid> externalSubnetList,
1905 TypedReadWriteTransaction<Configuration> confTx,
1906 ProviderTypes extNwProvType)
1907 throws InterruptedException, ExecutionException {
1909 LOG.debug("removeNaptFlowsFromActiveSwitch : Remove NAPT flows from Active switch");
1910 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1912 //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1913 // traffic which comes from the VMs of the NAPT switches)
1914 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1915 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1918 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1919 + "and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
1920 mdsalManager.removeFlow(confTx, preSnatFlowEntity);
1922 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1923 // traffic which comes from the VMs of the non NAPT switches)
1924 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
1925 elanManager, idManager, routerId, routerName);
1926 String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
1927 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1929 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1930 + "and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
1931 mdsalManager.removeFlow(confTx, tsNatFlowEntity);
1933 //Remove the flow table 25->44 from NAPT Switch
1934 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1935 NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, dpnId);
1938 //Remove the Outbound flow entry which forwards the packet to FIB Table
1940 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {}"
1941 + " and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1943 String outboundTcpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1944 NwConstants.IP_PROT_TCP);
1945 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1946 outboundTcpNatFlowRef);
1947 mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
1949 String outboundUdpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1950 NwConstants.IP_PROT_UDP);
1951 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1952 outboundUdpNatFlowRef);
1953 mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
1955 String icmpDropFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1956 NwConstants.IP_PROT_ICMP);
1957 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1959 mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
1960 boolean lastRouterOnExternalNetwork =
1961 !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker, networkId, routerName, dpnId);
1962 if (lastRouterOnExternalNetwork) {
1963 removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps, confTx);
1965 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
1966 // External Subnet Vpn Id.
1967 for (Uuid externalSubnetId : externalSubnetList) {
1968 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
1969 if (subnetVpnId != -1 && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
1970 dataBroker, externalSubnetId, routerName, dpnId)) {
1971 String natPfibSubnetFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
1972 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE,
1973 natPfibSubnetFlowRef);
1974 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
1975 LOG.debug("removeNaptFlowsFromActiveSwitch : Removed the flow in table {} with external subnet "
1976 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
1977 subnetVpnId, dpnId);
1981 //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1982 String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1983 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1986 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1987 + "and router ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
1988 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
1990 if (lastRouterOnExternalNetwork) {
1991 // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
1992 // - This does not work since ext-routers is deleted already - no network info
1993 //Get the VPN ID from the ExternalNetworks model
1995 if (vpnName == null || vpnName.isEmpty()) {
1996 // ie called from router delete cases
1997 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1998 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnUuid is {}", vpnUuid);
1999 if (vpnUuid != null) {
2000 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2001 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId {} for external network {} router delete "
2002 + "or disableSNAT scenario", vpnId, networkId);
2005 // ie called from disassociate vpn case
2006 LOG.debug("removeNaptFlowsFromActiveSwitch : This is disassociate nw with vpn case with vpnName {}",
2008 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2009 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId for disassociate nw with vpn scenario {}",
2013 if (vpnId != NatConstants.INVALID_ID) {
2014 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2015 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2016 FlowEntity natPfibVpnFlowEntity =
2017 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2018 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in {} for the active switch with the "
2019 + "DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2020 mdsalManager.removeFlow(confTx, natPfibVpnFlowEntity);
2024 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2025 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2026 if (ipPortMapping == null) {
2027 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the IpPortMapping");
2031 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2032 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2033 String ipPortInternal = ipPortMap.getIpPortInternal();
2034 String[] ipPortParts = ipPortInternal.split(":");
2035 if (ipPortParts.length != 2) {
2036 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the Internal IP and port");
2039 String internalIp = ipPortParts[0];
2040 String internalPort = ipPortParts[1];
2042 //Build the flow for the outbound NAPT table
2043 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2044 + NatConstants.COLON_SEPARATOR + internalPort);
2045 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2046 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
2047 FlowEntity outboundNaptFlowEntity =
2048 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2050 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch "
2051 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2052 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
2054 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2055 String externalIp = ipPortExternal.getIpAddress();
2056 int externalPort = ipPortExternal.getPortNum();
2058 //Build the flow for the inbound NAPT table
2059 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2060 String.valueOf(routerId), externalIp, externalPort);
2061 FlowEntity inboundNaptFlowEntity =
2062 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2064 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active active switch "
2065 + "with the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2066 mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
2071 protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
2072 @NonNull Collection<String> externalIps,
2073 TypedReadWriteTransaction<Configuration> writeFlowInvTx)
2074 throws ExecutionException, InterruptedException {
2075 long extVpnId = NatConstants.INVALID_ID;
2076 if (networkId != null) {
2077 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
2078 if (vpnUuid != null) {
2079 extVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2081 LOG.debug("removeNaptFibExternalOutputFlows : vpnUuid is null");
2084 LOG.debug("removeNaptFibExternalOutputFlows : networkId is null");
2085 extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2087 if (extVpnId == NatConstants.INVALID_ID) {
2088 LOG.warn("removeNaptFibExternalOutputFlows : extVpnId not found for routerId {}", routerId);
2089 extVpnId = routerId;
2091 for (String ip : externalIps) {
2092 String extIp = removeMaskFromIp(ip);
2093 String naptFlowRef = getFlowRefNaptPreFib(dpnId, NwConstants.NAPT_PFIB_TABLE, extVpnId);
2094 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in table {} for the active switch"
2095 + " with the DPN ID {} and router ID {} and IP {} flowRef {}",
2096 NwConstants.NAPT_PFIB_TABLE, dpnId, routerId, extIp, naptFlowRef);
2097 FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef);
2098 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2102 private String removeMaskFromIp(String ip) {
2103 if (ip != null && !ip.trim().isEmpty()) {
2104 return ip.split("/")[0];
2109 public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
2110 BigInteger dpnId, Uuid networkId, String vpnName,
2111 TypedReadWriteTransaction<Configuration> writeFlowInvTx)
2112 throws ExecutionException, InterruptedException {
2113 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : Remove NAPT flows from Active switch Internet Vpn");
2114 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
2116 //Remove the NAPT PFIB TABLE entry
2118 if (vpnName != null) {
2119 // ie called from disassociate vpn case
2120 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : This is disassociate nw with vpn case "
2121 + "with vpnName {}", vpnName);
2122 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2123 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : vpnId for disassociate nw with vpn scenario {}",
2127 if (vpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker,
2128 networkId, routerName, dpnId)) {
2129 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2130 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2131 FlowEntity natPfibVpnFlowEntity =
2132 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2133 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the active switch "
2134 + "with the DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2135 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2137 // Remove IP-PORT active NAPT entries and release port from IdManager
2138 // For the router ID get the internal IP , internal port and the corresponding
2139 // external IP and external Port.
2140 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2141 if (ipPortMapping == null) {
2142 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the IpPortMapping");
2145 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2146 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2147 String ipPortInternal = ipPortMap.getIpPortInternal();
2148 String[] ipPortParts = ipPortInternal.split(":");
2149 if (ipPortParts.length != 2) {
2150 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the Internal IP "
2154 String internalIp = ipPortParts[0];
2155 String internalPort = ipPortParts[1];
2157 //Build the flow for the outbound NAPT table
2158 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2159 + NatConstants.COLON_SEPARATOR + internalPort);
2160 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2161 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
2162 FlowEntity outboundNaptFlowEntity =
2163 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2165 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2166 + "active switch with the DPN ID {} and router ID {}",
2167 NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2168 mdsalManager.removeFlow(writeFlowInvTx, outboundNaptFlowEntity);
2170 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2171 String externalIp = ipPortExternal.getIpAddress();
2172 int externalPort = ipPortExternal.getPortNum();
2174 //Build the flow for the inbound NAPT table
2175 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2176 String.valueOf(routerId), externalIp, externalPort);
2177 FlowEntity inboundNaptFlowEntity =
2178 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2180 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2181 + "active active switch with the DPN ID {} and router ID {}",
2182 NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2183 mdsalManager.removeFlow(writeFlowInvTx, inboundNaptFlowEntity);
2185 // Finally release port from idmanager
2186 String internalIpPort = internalIp + ":" + internalPort;
2187 naptManager.removePortFromPool(internalIpPort, externalIp);
2189 //Remove sessions from models
2190 naptManager.removeIpPortMappingForRouterID(routerId);
2191 naptManager.removeIntIpPortMappingForRouterID(routerId);
2195 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Invalid vpnId {}", vpnId);
2199 public void removeFlowsFromNonActiveSwitches(long routerId, String routerName,
2200 BigInteger naptSwitchDpnId, TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2201 throws ExecutionException, InterruptedException {
2202 LOG.debug("removeFlowsFromNonActiveSwitches : Remove NAPT related flows from non active switches");
2204 // Remove the flows from the other switches which points to the primary and secondary switches
2205 // for the flows related the router ID.
2206 List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
2207 if (allSwitchList.isEmpty()) {
2208 LOG.error("removeFlowsFromNonActiveSwitches : Unable to get the swithces for the router {}", routerName);
2211 for (BigInteger dpnId : allSwitchList) {
2212 if (!naptSwitchDpnId.equals(dpnId)) {
2213 LOG.info("removeFlowsFromNonActiveSwitches : Handle Ordinary switch");
2215 //Remove the PSNAT entry which forwards the packet to Terminating Service table
2216 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
2217 FlowEntity preSnatFlowEntity =
2218 NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
2220 LOG.info("removeFlowsFromNonActiveSwitches : Remove the flow in the {} for the non active switch "
2221 + "with the DPN ID {} and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
2222 mdsalManager.removeFlow(removeFlowInvTx, preSnatFlowEntity);
2224 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
2225 long groupId = createGroupId(getGroupIdKey(routerName));
2227 LOG.info("removeFlowsFromNonActiveSwitches : Remove the group {} for the non active switch with "
2228 + "the DPN ID {} and router ID {}", groupId, dpnId, routerId);
2229 mdsalManager.removeGroup(removeFlowInvTx, dpnId, groupId);
2234 public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, @Nullable Uuid networkUuid,
2235 @NonNull Collection<String> externalIps, @Nullable String vpnName,
2236 String extGwMacAddress, TypedReadWriteTransaction<Configuration> confTx)
2237 throws ExecutionException, InterruptedException {
2238 //Withdraw the corresponding routes from the BGP.
2239 //Get the network ID using the router ID.
2240 LOG.debug("clrRtsFromBgpAndDelFibTs : Advertise to BGP and remove routes for externalIps {} with routerId {},"
2241 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2242 if (networkUuid == null) {
2243 LOG.error("clrRtsFromBgpAndDelFibTs : networkId is null");
2247 if (externalIps.isEmpty()) {
2248 LOG.error("clrRtsFromBgpAndDelFibTs : externalIps is empty");
2252 if (vpnName == null) {
2253 //Get the VPN Name using the network ID
2254 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2255 if (vpnName == null) {
2256 LOG.error("clrRtsFromBgpAndDelFibTs : No VPN associated with ext nw {} for the router {}",
2257 networkUuid, routerId);
2261 LOG.debug("clrRtsFromBgpAndDelFibTs : Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2263 //Remove custom FIB routes
2264 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2265 for (String extIp : externalIps) {
2266 clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, confTx);
2270 protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2271 final Uuid networkUuid, String extGwMacAddress,
2272 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2273 throws ExecutionException, InterruptedException {
2274 clearBgpRoutes(extIp, vpnName);
2275 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2279 protected void delFibTsAndReverseTraffic(final BigInteger dpnId, String routerName, long routerId, String extIp,
2280 String vpnName, Uuid extNetworkId, long tempLabel,
2281 String gwMacAddress, boolean switchOver,
2282 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2283 throws ExecutionException, InterruptedException {
2284 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2285 //String routerName = NatUtil.getRouterName(dataBroker,routerId);
2286 if (routerName == null) {
2287 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2290 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
2291 if (extNwProvType == null) {
2292 LOG.error("delFibTsAndReverseTraffic : External Network Provider Type Missing");
2295 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2296 * external network provided type is VxLAN
2298 if (extNwProvType == ProviderTypes.VXLAN) {
2299 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, gwMacAddress
2303 if (tempLabel < 0) {
2304 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2308 final long label = tempLabel;
2309 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2310 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
2311 LOG.debug("delFibTsAndReverseTraffic : Using extSubnetId as vpnName for FLAT/VLAN use-cases");
2312 Routers extRouter = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
2313 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp,
2316 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
2319 if (externalSubnet.isPresent()) {
2320 vpnName = externalSubnetId.getValue();
2323 final String externalVpn = vpnName;
2324 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(externalVpn)
2325 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label)
2326 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
2327 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2329 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2330 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2331 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2332 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2333 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2336 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2337 Futures.transformAsync(future, result -> {
2339 if (result.isSuccessful()) {
2340 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2341 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2342 .setVpnName(externalVpn).setIpPrefix(externalIp).build();
2343 return vpnService.removeVpnLabel(labelInput);
2346 String.format("RPC call to remove custom FIB entries on dpn %s for "
2347 + "prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
2349 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2351 }, MoreExecutors.directExecutor());
2353 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2356 public void onFailure(@NonNull Throwable error) {
2357 LOG.error("delFibTsAndReverseTraffic : Error in removing the label:{} or custom fib entries"
2358 + "got external ip {}", label, extIp, error);
2362 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
2363 if (result.isSuccessful()) {
2364 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2365 + "from VPN {}", externalIp, externalVpn);
2367 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2368 + " from VPN {}, {}", externalIp, externalVpn, result.getErrors());
2371 }, MoreExecutors.directExecutor());
2373 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2374 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2378 private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2379 final Uuid networkUuid, String extGwMacAddress, boolean switchOver,
2380 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2381 throws ExecutionException, InterruptedException {
2382 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2383 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2384 if (routerName == null) {
2385 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2388 //Get the external network provider type from networkId
2389 ProviderTypes extNwProvType = NatUtil.getProviderTypefromNetworkId(dataBroker, networkUuid);
2390 if (extNwProvType == null) {
2391 LOG.error("delFibTsAndReverseTraffic : Could not retrieve provider type for external network {} ",
2395 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2396 * external network provided type is VxLAN
2398 if (extNwProvType == ProviderTypes.VXLAN) {
2399 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, extGwMacAddress);
2402 //Get IPMaps from the DB for the router ID
2403 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
2404 if (dbIpMaps.isEmpty()) {
2405 LOG.error("delFibTsAndReverseTraffic : IPMaps not found for router {}", routerId);
2409 long tempLabel = NatConstants.INVALID_ID;
2410 for (IpMap dbIpMap : dbIpMaps) {
2411 String dbExternalIp = dbIpMap.getExternalIp();
2412 LOG.debug("delFibTsAndReverseTraffic : Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
2413 //Select the IPMap, whose external IP is the IP for which FIB is installed
2414 if (extIp.equals(dbExternalIp)) {
2415 tempLabel = dbIpMap.getLabel();
2416 LOG.debug("delFibTsAndReverseTraffic : Retrieved label {} for dbExternalIp {} with router id {}",
2417 tempLabel, dbExternalIp, routerId);
2421 if (tempLabel == NatConstants.INVALID_ID) {
2422 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2427 final long label = tempLabel;
2428 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2429 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
2430 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp)
2431 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).setServiceId(label).build();
2432 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2434 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2435 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2436 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2437 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2438 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2441 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2442 Futures.transformAsync(future, result -> {
2444 if (result.isSuccessful()) {
2445 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2446 .setVpnName(vpnName).setIpPrefix(externalIp).build();
2447 return vpnService.removeVpnLabel(labelInput);
2450 String.format("RPC call to remove custom FIB entries on dpn %s for "
2451 + "prefix %s Failed - %s",
2452 dpnId, externalIp, result.getErrors());
2454 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2456 }, MoreExecutors.directExecutor());
2458 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2461 public void onFailure(@NonNull Throwable error) {
2462 LOG.error("delFibTsAndReverseTraffic : Error in removing the label or custom fib entries", error);
2466 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
2467 if (result.isSuccessful()) {
2468 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2469 + "from VPN {}", externalIp, vpnName);
2471 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2472 + " from VPN {}, {}", externalIp, vpnName, result.getErrors());
2475 }, MoreExecutors.directExecutor());
2477 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2478 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2482 protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2483 List<String> externalIps, @Nullable String vpnName, String extGwMacAddress,
2484 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2485 //Withdraw the corresponding routes from the BGP.
2486 //Get the network ID using the router ID.
2487 LOG.debug("clearFibTsAndReverseTraffic : for externalIps {} with routerId {},"
2488 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2489 if (networkUuid == null) {
2490 LOG.error("clearFibTsAndReverseTraffic : networkId is null");
2494 if (externalIps == null || externalIps.isEmpty()) {
2495 LOG.error("clearFibTsAndReverseTraffic : externalIps is null");
2499 if (vpnName == null) {
2500 //Get the VPN Name using the network ID
2501 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2502 if (vpnName == null) {
2503 LOG.error("clearFibTsAndReverseTraffic : No VPN associated with ext nw {} for the router {}",
2504 networkUuid, routerId);
2508 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2510 //Remove custom FIB routes
2511 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2512 for (String extIp : externalIps) {
2513 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2518 protected void clearBgpRoutes(String externalIp, final String vpnName) {
2519 //Inform BGP about the route removal
2520 LOG.info("clearBgpRoutes : Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
2521 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
2522 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
2525 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId,
2526 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2527 LOG.info("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
2528 mdsalManager.removeFlow(writeFlowInvTx, dpnId,
2529 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), NwConstants.INTERNAL_TUNNEL_TABLE);
2530 LOG.debug("removeTunnelTableEntry : dpID {} : label : {} removed successfully", dpnId, serviceId);
2533 private void removeLFibTableEntry(BigInteger dpnId, long serviceId,
2534 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2535 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2536 LOG.debug("removeLFibTableEntry : with flow ref {}", flowRef);
2537 mdsalManager.removeFlow(writeFlowInvTx, dpnId, flowRef, NwConstants.L3_LFIB_TABLE);
2538 LOG.debug("removeLFibTableEntry : dpID : {} label : {} removed successfully", dpnId, serviceId);
2542 * router association to vpn.
2544 * @param routerName - Name of router
2545 * @param routerId - router id
2546 * @param bgpVpnName BGP VPN name
2548 public void changeLocalVpnIdToBgpVpnId(String routerName, long routerId, String bgpVpnName,
2549 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2550 LOG.debug("changeLocalVpnIdToBgpVpnId : Router associated to BGP VPN");
2551 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2552 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2554 LOG.debug("changeLocalVpnIdToBgpVpnId : BGP VPN ID value {} ", bgpVpnId);
2556 if (bgpVpnId != NatConstants.INVALID_ID) {
2557 LOG.debug("changeLocalVpnIdToBgpVpnId : Populate the router-id-name container with the "
2558 + "mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
2559 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
2560 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2561 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2562 getRoutersIdentifier(bgpVpnId), rtrs);
2564 // Get the allocated Primary NAPT Switch for this router
2565 LOG.debug("changeLocalVpnIdToBgpVpnId : Router ID value {} ", routerId);
2567 LOG.debug("changeLocalVpnIdToBgpVpnId : Update the Router ID {} to the BGP VPN ID {} ",
2568 routerId, bgpVpnId);
2569 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, writeFlowInvTx);
2572 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2573 createGroupId(getGroupIdKey(routerName));
2574 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true, writeFlowInvTx,
2581 * router disassociation from vpn.
2583 * @param routerName - Name of router
2584 * @param routerId - router id
2585 * @param bgpVpnName BGP VPN name
2587 public void changeBgpVpnIdToLocalVpnId(String routerName, long routerId, String bgpVpnName,
2588 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2589 LOG.debug("changeBgpVpnIdToLocalVpnId : Router dissociated from BGP VPN");
2590 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2591 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2592 LOG.debug("changeBgpVpnIdToLocalVpnId : BGP VPN ID value {} ", bgpVpnId);
2594 // Get the allocated Primary NAPT Switch for this router
2595 LOG.debug("changeBgpVpnIdToLocalVpnId : Router ID value {} ", routerId);
2597 LOG.debug("changeBgpVpnIdToLocalVpnId : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2598 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, NatConstants.INVALID_ID, writeFlowInvTx);
2601 createGroupId(getGroupIdKey(routerName));
2602 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2603 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true,
2604 writeFlowInvTx, extNwProvType);
2608 boolean chkExtRtrAndSnatEnbl(Uuid routerUuid) {
2609 InstanceIdentifier<Routers> routerInstanceIndentifier =
2610 InstanceIdentifier.builder(ExtRouters.class)
2611 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
2613 Optional<Routers> routerData = SingleTransactionDataBroker
2614 .syncReadOptional(dataBroker,
2615 LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2616 return routerData.isPresent() && routerData.get().isEnableSnat();
2617 } catch (ReadFailedException e) {
2618 LOG.error("Failed to read data for router id {}", routerUuid, e);
2623 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2624 long routerId, boolean isSnatCfgd, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2626 long changedVpnId = bgpVpnId;
2627 String idType = "BGP VPN";
2628 if (bgpVpnId == NatConstants.INVALID_ID) {
2629 changedVpnId = routerId;
2633 List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2634 if (switches.isEmpty()) {
2635 LOG.error("installFlowsWithUpdatedVpnId : No switches found for router {}", routerName);
2638 for (BigInteger dpnId : switches) {
2639 // Update the BGP VPN ID in the SNAT miss entry to group
2640 if (!dpnId.equals(primarySwitchId)) {
2641 LOG.debug("installFlowsWithUpdatedVpnId : Install group in non NAPT switch {}", dpnId);
2642 List<BucketInfo> bucketInfoForNonNaptSwitches =
2643 getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName, routerId);
2644 long groupId = createGroupId(getGroupIdKey(routerName));
2646 groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
2650 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2651 + "{} in the non NAPT switch {}", idType, changedVpnId, groupId, dpnId);
2652 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
2653 mdsalManager.addFlow(confTx, flowEntity);
2656 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2657 + "in the primary switch {}", idType, changedVpnId, primarySwitchId);
2658 FlowEntity flowEntity =
2659 buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2660 mdsalManager.addFlow(confTx, flowEntity);
2663 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Terminating Service table (table "
2664 + "ID 36) which forwards the packet to the table 46 in the Primary switch {}",
2665 idType, changedVpnId, primarySwitchId);
2666 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, routerId,
2667 changedVpnId, confTx, extNwProvType);
2670 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Outbound NAPT table (table ID 46) "
2671 + "which punts the packet to the controller in the Primary switch {}",
2672 idType, changedVpnId, primarySwitchId);
2673 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2676 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT PFIB TABLE which forwards the"
2677 + " outgoing packet to FIB Table in the Primary switch {}",
2678 idType, changedVpnId, primarySwitchId);
2679 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2682 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT flows for the Outbound NAPT "
2683 + "table (table ID 46) and the INBOUND NAPT table (table ID 44) in the Primary switch"
2684 + " {}", idType, changedVpnId, primarySwitchId);
2685 updateNaptFlowsWithVpnId(primarySwitchId, routerName, routerId, bgpVpnId);
2687 LOG.debug("installFlowsWithUpdatedVpnId : Installing SNAT PFIB flow in the primary switch {}",
2689 Long vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2690 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2691 if (vpnId != NatConstants.INVALID_ID) {
2692 installNaptPfibEntry(primarySwitchId, vpnId, confTx);
2698 public void updateNaptFlowsWithVpnId(BigInteger dpnId, String routerName, long routerId, long bgpVpnId) {
2699 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2700 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2701 if (ipPortMapping == null) {
2702 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the IpPortMapping");
2705 // Get the External Gateway MAC Address
2706 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
2707 if (extGwMacAddress != null) {
2708 LOG.debug("updateNaptFlowsWithVpnId : External Gateway MAC address {} found for External Router ID {}",
2709 extGwMacAddress, routerId);
2711 LOG.error("updateNaptFlowsWithVpnId : No External Gateway MAC address found for External Router ID {}",
2715 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2716 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2717 String ipPortInternal = ipPortMap.getIpPortInternal();
2718 String[] ipPortParts = ipPortInternal.split(":");
2719 if (ipPortParts.length != 2) {
2720 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the Internal IP and port");
2723 String internalIp = ipPortParts[0];
2724 String internalPort = ipPortParts[1];
2725 LOG.debug("updateNaptFlowsWithVpnId : Found Internal IP {} and Internal Port {}",
2726 internalIp, internalPort);
2727 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2728 NAPTEntryEvent.Protocol protocol;
2729 switch (protocolTypes) {
2731 protocol = NAPTEntryEvent.Protocol.TCP;
2734 protocol = NAPTEntryEvent.Protocol.UDP;
2737 protocol = NAPTEntryEvent.Protocol.TCP;
2739 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.parseInt(internalPort));
2740 SessionAddress externalAddress =
2741 naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2742 long internetVpnid = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2743 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
2744 routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
2745 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
2746 routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
2751 public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
2752 long changedVpnId) {
2754 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : called for dpId {}, routerName {} groupId {} "
2755 + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
2756 List<MatchInfo> matches = new ArrayList<>();
2757 matches.add(MatchEthernetType.IPV4);
2758 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2760 List<ActionInfo> actionsInfo = new ArrayList<>();
2761 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
2762 elanManager, idManager, changedVpnId, routerName);
2763 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
2764 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Setting the tunnel to the list of action infos {}",
2766 actionsInfo.add(new ActionGroup(groupId));
2767 List<InstructionInfo> instructions = new ArrayList<>();
2768 instructions.add(new InstructionApplyActions(actionsInfo));
2769 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2770 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2771 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2772 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2774 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Returning SNAT Flow Entity {}", flowEntity);
2778 public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
2779 long changedVpnId) {
2781 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : called for dpId {}, routerName {} "
2782 + "changed VPN ID {}", dpId, routerName, changedVpnId);
2783 List<MatchInfo> matches = new ArrayList<>();
2784 matches.add(MatchEthernetType.IPV4);
2785 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2787 List<InstructionInfo> instructions = new ArrayList<>();
2788 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2790 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2791 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2792 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2793 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2795 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : Returning SNAT Flow Entity {}", flowEntity);
2799 // TODO : Replace this with ITM Rpc once its available with full functionality
2800 protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
2801 long routerId, long changedVpnId, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2803 LOG.debug("installTerminatingServiceTblEntryWithUpdatedVpnId : called for switch {}, "
2804 + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2805 FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, routerId, changedVpnId,
2807 mdsalManager.addFlow(confTx, flowEntity);
2810 private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName,
2811 long routerIdLongVal, long changedVpnId, ProviderTypes extNwProvType) {
2812 LOG.debug("buildTsFlowEntityWithUpdatedVpnId : called for switch {}, routerName {}, BGP VPN ID {}",
2813 dpId, routerName, changedVpnId);
2814 List<MatchInfo> matches = new ArrayList<>();
2815 matches.add(MatchEthernetType.IPV4);
2817 BigInteger tunnelId = BigInteger.valueOf(changedVpnId);
2818 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2819 tunnelId = natOverVxlanUtil.getRouterVni(routerName, changedVpnId);
2821 matches.add(new MatchTunnelId(tunnelId));
2823 List<InstructionInfo> instructions = new ArrayList<>();
2824 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2825 MetaDataUtil.METADATA_MASK_VRFID));
2826 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2827 BigInteger routerId = BigInteger.valueOf(routerIdLongVal);
2828 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2829 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2830 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2831 NwConstants.COOKIE_TS_TABLE, matches, instructions);
2835 public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId,
2836 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2837 LOG.debug("createOutboundTblEntryWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2838 dpnId, routerId, changedVpnId);
2839 FlowEntity tcpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2840 NwConstants.IP_PROT_TCP);
2841 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing tcp flow {}", tcpFlowEntity);
2842 mdsalManager.addFlow(writeFlowInvTx, tcpFlowEntity);
2844 FlowEntity udpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2845 NwConstants.IP_PROT_UDP);
2846 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing udp flow {}", udpFlowEntity);
2847 mdsalManager.addFlow(writeFlowInvTx, udpFlowEntity);
2849 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, changedVpnId);
2850 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
2851 mdsalManager.addFlow(writeFlowInvTx, icmpDropFlow);
2854 protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId,
2855 long changedVpnId, int protocol) {
2856 LOG.debug("buildOutboundFlowEntityWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2857 dpId, routerId, changedVpnId);
2858 BigInteger cookie = getCookieOutboundFlow(routerId);
2859 List<MatchInfo> matches = new ArrayList<>();
2860 matches.add(MatchEthernetType.IPV4);
2861 matches.add(new MatchIpProtocol((short)protocol));
2862 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2864 List<InstructionInfo> instructions = new ArrayList<>();
2865 List<ActionInfo> actionsInfos = new ArrayList<>();
2866 actionsInfos.add(new ActionPuntToController());
2867 if (snatPuntTimeout != 0) {
2868 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
2870 instructions.add(new InstructionApplyActions(actionsInfos));
2872 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
2873 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
2874 flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
2875 LOG.debug("createOutboundTblEntryWithBgpVpn : returning flowEntity {}", flowEntity);
2879 public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId,
2880 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2881 LOG.debug("installNaptPfibEntryWithBgpVpn : called for dpnId {} and segmentId {} ,BGP VPN ID {}",
2882 dpnId, segmentId, changedVpnId);
2883 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2884 mdsalManager.addFlow(writeFlowInvTx, naptPfibFlowEntity);
2887 public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2889 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : called for dpId {}, "
2890 + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2891 List<MatchInfo> matches = new ArrayList<>();
2892 matches.add(MatchEthernetType.IPV4);
2893 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2895 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2896 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2897 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
2898 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2899 instructionInfo.add(new InstructionApplyActions(listActionInfo));
2901 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2902 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2903 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2904 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2905 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : Returning NaptPFib Flow Entity {}", flowEntity);
2910 protected ExternalRoutersListener getDataTreeChangeListener() {
2911 return ExternalRoutersListener.this;
2914 protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId,
2915 @Nullable TypedWriteTransaction<Configuration> writeFlowInvTx) {
2916 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
2918 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
2919 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
2920 if (subnetVpnId != -1) {
2921 LOG.debug("installNaptPfibEntriesForExternalSubnets : called for dpnId {} "
2922 + "and vpnId {}", dpnId, subnetVpnId);
2923 installNaptPfibEntry(dpnId, subnetVpnId, writeFlowInvTx);