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.IdManagerService;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIds;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsBuilder;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsKey;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelOutput;
143 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
144 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
145 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
146 import org.opendaylight.yangtools.yang.common.RpcResult;
147 import org.slf4j.Logger;
148 import org.slf4j.LoggerFactory;
152 public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener> {
153 private static final Logger LOG = LoggerFactory.getLogger(ExternalRoutersListener.class);
155 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
156 private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
158 private final DataBroker dataBroker;
159 private final ManagedNewTransactionRunner txRunner;
160 private final IMdsalApiManager mdsalManager;
161 private final ItmRpcService itmManager;
162 private final OdlInterfaceRpcService odlInterfaceRpcService;
163 private final IdManagerService idManager;
164 private final NaptManager naptManager;
165 private final NAPTSwitchSelector naptSwitchSelector;
166 private final IBgpManager bgpManager;
167 private final VpnRpcService vpnService;
168 private final FibRpcService fibService;
169 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
170 private final NaptEventHandler naptEventHandler;
171 private final NaptPacketInHandler naptPacketInHandler;
172 private final IFibManager fibManager;
173 private final IVpnManager vpnManager;
174 private final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer;
175 private final NatMode natMode;
176 private final IElanService elanManager;
177 private final JobCoordinator coordinator;
178 private final IInterfaceManager interfaceManager;
179 private final NatOverVxlanUtil natOverVxlanUtil;
180 private final int snatPuntTimeout;
183 public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
184 final ItmRpcService itmManager,
185 final OdlInterfaceRpcService odlInterfaceRpcService,
186 final IdManagerService idManager,
187 final NaptManager naptManager,
188 final NAPTSwitchSelector naptSwitchSelector,
189 final IBgpManager bgpManager,
190 final VpnRpcService vpnService,
191 final FibRpcService fibService,
192 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
193 final NaptEventHandler naptEventHandler,
194 final NaptPacketInHandler naptPacketInHandler,
195 final IFibManager fibManager,
196 final IVpnManager vpnManager,
197 final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer,
198 final NatserviceConfig config,
199 final IElanService elanManager,
200 final JobCoordinator coordinator,
201 final NatOverVxlanUtil natOverVxlanUtil,
202 final IInterfaceManager interfaceManager) {
203 super(Routers.class, ExternalRoutersListener.class);
204 this.dataBroker = dataBroker;
205 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
206 this.mdsalManager = mdsalManager;
207 this.itmManager = itmManager;
208 this.odlInterfaceRpcService = odlInterfaceRpcService;
209 this.idManager = idManager;
210 this.naptManager = naptManager;
211 this.naptSwitchSelector = naptSwitchSelector;
212 this.bgpManager = bgpManager;
213 this.vpnService = vpnService;
214 this.fibService = fibService;
215 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
216 this.naptEventHandler = naptEventHandler;
217 this.naptPacketInHandler = naptPacketInHandler;
218 this.fibManager = fibManager;
219 this.vpnManager = vpnManager;
220 this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
221 this.elanManager = elanManager;
222 this.coordinator = coordinator;
223 this.interfaceManager = interfaceManager;
224 this.natOverVxlanUtil = natOverVxlanUtil;
225 if (config != null) {
226 this.natMode = config.getNatMode();
227 this.snatPuntTimeout = config.getSnatPuntTimeout().intValue();
229 this.natMode = NatMode.Controller;
230 this.snatPuntTimeout = 0;
237 LOG.info("{} init", getClass().getSimpleName());
238 // This class handles ExternalRouters for Controller SNAT mode.
239 // For Conntrack SNAT mode, its handled in SnatExternalRoutersListener.java
240 if (natMode == NatMode.Controller) {
241 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
242 NatUtil.createGroupIdPool(idManager);
247 protected InstanceIdentifier<Routers> getWildCardPath() {
248 return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
252 // TODO Clean up the exception handling
253 @SuppressWarnings("checkstyle:IllegalCatch")
254 protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
255 // Populate the router-id-name container
256 String routerName = routers.getRouterName();
257 LOG.info("add : external router event for {}", routerName);
258 long routerId = NatUtil.getVpnId(dataBroker, routerName);
259 NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
260 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
262 if (routers.isEnableSnat()) {
263 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routers.key(),
264 () -> Collections.singletonList(
265 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
266 LOG.info("add : Installing NAT default route on all dpns part of router {}", routerName);
267 long bgpVpnId = NatConstants.INVALID_ID;
268 if (bgpVpnUuid != null) {
269 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
271 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, true, confTx);
272 // Allocate Primary Napt Switch for this router
273 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName);
274 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
275 handleEnableSnat(routers, routerId, primarySwitchId, bgpVpnId, confTx);
278 )), NatConstants.NAT_DJC_MAX_RETRIES);
280 LOG.info("add : SNAT is disabled for external router {} ", routerName);
282 } catch (Exception ex) {
283 LOG.error("add : Exception while Installing NAT flows on all dpns as part of router {}",
288 public void handleEnableSnat(Routers routers, long routerId, BigInteger primarySwitchId, long bgpVpnId,
289 TypedWriteTransaction<Configuration> confTx) {
290 String routerName = routers.getRouterName();
291 LOG.info("handleEnableSnat : Handling SNAT for router {}", routerName);
293 naptManager.initialiseExternalCounter(routers, routerId);
294 subnetRegisterMapping(routers, routerId);
296 LOG.debug("handleEnableSnat:About to create and install outbound miss entry in Primary Switch {} for router {}",
297 primarySwitchId, routerName);
299 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
300 routers.getNetworkId());
301 if (extNwProvType == null) {
302 LOG.error("handleEnableSnat : External Network Provider Type missing");
306 if (bgpVpnId != NatConstants.INVALID_ID) {
307 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, false, confTx,
310 // write metadata and punt
311 installOutboundMissEntry(routerName, routerId, primarySwitchId, confTx);
312 handlePrimaryNaptSwitch(primarySwitchId, routerName, routerId, confTx);
313 // Now install entries in SNAT tables to point to Primary for each router
314 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
315 for (BigInteger dpnId : switches) {
316 // Handle switches and NAPT switches separately
317 if (!dpnId.equals(primarySwitchId)) {
318 LOG.debug("handleEnableSnat : Handle Ordinary switch");
319 handleSwitches(dpnId, routerName, routerId, primarySwitchId);
324 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
325 if (externalIps.isEmpty()) {
326 LOG.error("handleEnableSnat : Internal External mapping not found for router {}", routerName);
329 for (String externalIpAddrPrefix : externalIps) {
330 LOG.debug("handleEnableSnat : Calling handleSnatReverseTraffic for primarySwitchId {}, "
331 + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
332 handleSnatReverseTraffic(confTx, primarySwitchId, routers, routerId, routerName, externalIpAddrPrefix
336 LOG.debug("handleEnableSnat : Exit");
339 private BigInteger getPrimaryNaptSwitch(String routerName) {
340 // Allocate Primary Napt Switch for this router
341 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
342 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
343 LOG.debug("getPrimaryNaptSwitch : Primary NAPT switch with DPN ID {} is already elected for router {}",
344 primarySwitchId, routerName);
345 return primarySwitchId;
347 return selectNewNAPTSwitch(routerName);
350 private BigInteger selectNewNAPTSwitch(String routerName) {
351 // Allocated an id from VNI pool for the Router.
352 natOverVxlanUtil.getRouterVni(routerName, NatConstants.INVALID_ID);
353 BigInteger primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
354 LOG.debug("getPrimaryNaptSwitch : Primary NAPT switch DPN ID {}", primarySwitchId);
356 return primarySwitchId;
359 protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId,
360 TypedWriteTransaction<Configuration> confTx) {
361 Long extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
362 if (extVpnId == NatConstants.INVALID_ID) {
363 LOG.error("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
366 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
367 if (externalIps.isEmpty()) {
368 LOG.error("installNaptPfibExternalOutputFlow - empty external Ips list for dpnId {} extVpnId {}",
372 for (String ip : externalIps) {
373 Uuid subnetId = getSubnetIdForFixedIp(ip);
374 if (subnetId != null) {
375 long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
376 if (subnetVpnId != NatConstants.INVALID_ID) {
377 extVpnId = subnetVpnId;
379 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
380 dpnId, extVpnId, subnetId);
381 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
382 if (postNaptFlowEntity != null) {
383 mdsalManager.addFlow(confTx, postNaptFlowEntity);
390 private Uuid getSubnetIdForFixedIp(String ip) {
392 IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
393 Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
394 return NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
396 LOG.error("getSubnetIdForFixedIp : ip is null");
400 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
401 LOG.debug("subnetRegisterMapping : Fetching values from extRouters model");
402 List<String> externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
404 int extIpCounter = externalIps.size();
405 LOG.debug("subnetRegisterMapping : counter values before looping counter {} and extIpCounter {}",
406 counter, extIpCounter);
407 @Nullable List<Uuid> subnetIds = routerEntry.getSubnetIds();
408 if (subnetIds == null) {
411 for (Uuid subnet : subnetIds) {
412 LOG.debug("subnetRegisterMapping : Looping internal subnets for subnet {}", subnet);
413 InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
414 .builder(Subnetmaps.class)
415 .child(Subnetmap.class, new SubnetmapKey(subnet))
417 Optional<Subnetmap> sn;
419 sn = SingleTransactionDataBroker.syncReadOptional(dataBroker,
420 LogicalDatastoreType.CONFIGURATION, subnetmapId);
421 } catch (ReadFailedException e) {
422 LOG.error("Failed to read SubnetMap for subnetmap Id {}", subnetmapId, e);
423 sn = Optional.absent();
425 if (sn.isPresent()) {
427 Subnetmap subnetmapEntry = sn.get();
428 String subnetString = subnetmapEntry.getSubnetIp();
429 String[] subnetSplit = subnetString.split("/");
430 String subnetIp = subnetSplit[0];
432 InetAddress address = InetAddress.getByName(subnetIp);
433 if (address instanceof Inet6Address) {
434 LOG.debug("subnetRegisterMapping : Skipping ipv6 subnet {} for the router {} with ipv6 address "
435 + "{} ", subnet, routerEntry.getRouterName(), address);
438 } catch (UnknownHostException e) {
439 LOG.error("subnetRegisterMapping : Invalid ip address {}", subnetIp, e);
442 String subnetPrefix = "0";
443 if (subnetSplit.length == 2) {
444 subnetPrefix = subnetSplit[1];
446 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
447 LOG.debug("subnetRegisterMapping : subnetAddr is {} and subnetPrefix is {}",
448 subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
450 LOG.debug("subnetRegisterMapping : counter values counter {} and extIpCounter {}",
451 counter, extIpCounter);
452 if (extIpCounter != 0) {
453 if (counter < extIpCounter) {
454 String[] ipSplit = externalIps.get(counter).split("/");
455 String externalIp = ipSplit[0];
456 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
457 if (ipSplit.length == 2) {
458 extPrefix = ipSplit[1];
460 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
461 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
462 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
463 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
464 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
465 + "externalIp {}. prefix {}", subnetIp, subnetPrefix, externalIp, extPrefix);
467 counter = 0; //Reset the counter which runs on externalIps for round-robbin effect
468 LOG.debug("subnetRegisterMapping : Counter on externalIps got reset");
469 String[] ipSplit = externalIps.get(counter).split("/");
470 String externalIp = ipSplit[0];
471 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
472 if (ipSplit.length == 2) {
473 extPrefix = ipSplit[1];
475 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
476 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
477 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
478 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
479 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
480 + "externalIp {}. prefix {}", subnetIp, subnetPrefix,
481 externalIp, extPrefix);
485 LOG.debug("subnetRegisterMapping : Counter on externalIps incremented to {}", counter);
487 LOG.warn("subnetRegisterMapping : No internal subnets present in extRouters Model");
492 private void addOrDelDefFibRouteToSNAT(String routerName, long routerId, long bgpVpnId,
493 Uuid bgpVpnUuid, boolean create, TypedReadWriteTransaction<Configuration> confTx)
494 throws ExecutionException, InterruptedException {
495 //Check if BGP VPN exists. If exists then invoke the new method.
496 if (bgpVpnId != NatConstants.INVALID_ID) {
497 if (bgpVpnUuid != null) {
498 String bgpVpnName = bgpVpnUuid.getValue();
499 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
500 bgpVpnId, bgpVpnName);
501 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
502 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
503 confTx.put(getRoutersIdentifier(bgpVpnId), rtrs, CREATE_MISSING_PARENTS);
506 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
508 removeDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
513 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
514 addOrDelDefaultFibRouteForSNAT(routerName, routerId, create, confTx);
517 private void addOrDelDefaultFibRouteForSNAT(String routerName, long routerId, boolean create,
518 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
519 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
520 if (switches.isEmpty()) {
521 LOG.info("addOrDelDefaultFibRouteForSNAT : No switches found for router {}", routerName);
524 if (routerId == NatConstants.INVALID_ID) {
525 LOG.error("addOrDelDefaultFibRouteForSNAT : Could not retrieve router Id for {} to program "
526 + "default NAT route in FIB", routerName);
529 for (BigInteger dpnId : switches) {
531 LOG.debug("addOrDelDefaultFibRouteForSNAT : installing default NAT route for router {} in dpn {} "
532 + "for the internal vpn-id {}", routerId, dpnId, routerId);
533 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
535 LOG.debug("addOrDelDefaultFibRouteForSNAT : removing default NAT route for router {} in dpn {} "
536 + "for the internal vpn-id {}", routerId, dpnId, routerId);
537 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
542 private void addDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
543 long bgpVpnId, TypedWriteTransaction<Configuration> confTx) {
544 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
545 if (dpnIds.isEmpty()) {
546 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
547 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
550 for (BigInteger dpnId : dpnIds) {
551 if (bgpVpnId != NatConstants.INVALID_ID) {
552 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
553 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
554 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
556 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
557 + "in dpn {} for the internal vpn", routerId, dpnId);
558 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
563 private void removeDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
564 long bgpVpnId, TypedReadWriteTransaction<Configuration> confTx)
565 throws ExecutionException, InterruptedException {
566 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
567 if (dpnIds.isEmpty()) {
568 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
569 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
572 for (BigInteger dpnId : dpnIds) {
573 if (bgpVpnId != NatConstants.INVALID_ID) {
574 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
575 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
576 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
578 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
579 + "in dpn {} for the internal vpn", routerId, dpnId);
580 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
585 protected void installOutboundMissEntry(String routerName, long routerId, BigInteger primarySwitchId,
586 TypedWriteTransaction<Configuration> confTx) {
587 LOG.debug("installOutboundMissEntry : Router ID from getVpnId {}", routerId);
588 if (routerId != NatConstants.INVALID_ID) {
589 LOG.debug("installOutboundMissEntry : Creating miss entry on primary {}, for router {}",
590 primarySwitchId, routerId);
591 createOutboundTblEntry(primarySwitchId, routerId, confTx);
593 LOG.error("installOutboundMissEntry : Unable to fetch Router Id for RouterName {}, failed to "
594 + "createAndInstallMissEntry", routerName);
598 public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID, int protocol) {
599 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
600 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + protocol;
603 private String getFlowRefNaptPreFib(BigInteger dpnId, short tableId, long vpnId) {
604 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
605 .FLOWID_SEPARATOR + vpnId;
608 public BigInteger getCookieOutboundFlow(long routerId) {
609 return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
610 BigInteger.valueOf(routerId));
613 private ActionLearn getLearnActionForPunt(int protocol, int hardTimeout, BigInteger cookie) {
616 int l4portFieldLen = NxmOfFieldType.NXM_OF_TCP_SRC.getFlowModHeaderLenInt();
618 if (protocol == NwConstants.IP_PROT_TCP) {
619 l4SrcPortField = NxmOfFieldType.NXM_OF_TCP_SRC.getType();
620 l4DstPortField = NxmOfFieldType.NXM_OF_TCP_DST.getType();
622 l4SrcPortField = NxmOfFieldType.NXM_OF_UDP_SRC.getType();
623 l4DstPortField = NxmOfFieldType.NXM_OF_UDP_DST.getType();
625 List<ActionLearn.FlowMod> flowMods = Arrays.asList(
626 new MatchFromValue(NwConstants.ETHTYPE_IPV4, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
627 NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
628 new MatchFromValue(protocol, NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
629 NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
630 new MatchFromField(NxmOfFieldType.NXM_OF_IP_SRC.getType(), NxmOfFieldType.NXM_OF_IP_SRC.getType(),
631 NxmOfFieldType.NXM_OF_IP_SRC.getFlowModHeaderLenInt()),
632 new MatchFromField(NxmOfFieldType.NXM_OF_IP_DST.getType(), NxmOfFieldType.NXM_OF_IP_DST.getType(),
633 NxmOfFieldType.NXM_OF_IP_DST.getFlowModHeaderLenInt()),
634 new MatchFromField(l4SrcPortField, l4SrcPortField, l4portFieldLen),
635 new MatchFromField(l4DstPortField, l4DstPortField, l4portFieldLen),
636 new MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
637 MetaDataUtil.METADATA_VPN_ID_OFFSET,
638 NxmOfFieldType.OXM_OF_METADATA.getType(), MetaDataUtil.METADATA_VPN_ID_OFFSET,
639 MetaDataUtil.METADATA_VPN_ID_BITLEN));
641 return new ActionLearn(0, hardTimeout, 7, cookie, 0,
642 NwConstants.OUTBOUND_NAPT_TABLE, 0, 0, flowMods);
645 private FlowEntity buildIcmpDropFlow(BigInteger dpnId, long routerId, long vpnId) {
646 List<MatchInfo> matches = new ArrayList<>();
647 matches.add(MatchEthernetType.IPV4);
648 matches.add(MatchIpProtocol.ICMP);
649 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
651 List<ActionInfo> actionInfos = new ArrayList<>();
652 actionInfos.add(new ActionDrop());
654 List<InstructionInfo> instructions = new ArrayList<>();
655 instructions.add(new InstructionApplyActions(actionInfos));
657 String flowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
658 NwConstants.IP_PROT_ICMP);
659 FlowEntity flow = MDSALUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
660 NwConstants.TABLE_MISS_PRIORITY, "icmp drop flow", 0, 0,
661 NwConstants.COOKIE_OUTBOUND_NAPT_TABLE, matches, instructions);
665 protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId, int protocol) {
666 LOG.debug("buildOutboundFlowEntity : called for dpId {} and routerId{}", dpId, routerId);
667 BigInteger cookie = getCookieOutboundFlow(routerId);
668 List<MatchInfo> matches = new ArrayList<>();
669 matches.add(MatchEthernetType.IPV4);
670 matches.add(new MatchIpProtocol((short)protocol));
671 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
673 List<InstructionInfo> instructions = new ArrayList<>();
674 List<ActionInfo> actionsInfos = new ArrayList<>();
675 actionsInfos.add(new ActionPuntToController());
676 if (snatPuntTimeout != 0) {
677 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
679 instructions.add(new InstructionApplyActions(actionsInfos));
681 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
682 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
684 cookie, matches, instructions);
685 LOG.debug("installOutboundMissEntry : returning flowEntity {}", flowEntity);
689 public void createOutboundTblEntry(BigInteger dpnId, long routerId, TypedWriteTransaction<Configuration> confTx) {
690 LOG.debug("createOutboundTblEntry : called for dpId {} and routerId {}", dpnId, routerId);
691 FlowEntity tcpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_TCP);
692 LOG.debug("createOutboundTblEntry : Installing tcp flow {}", tcpflowEntity);
693 mdsalManager.addFlow(confTx, tcpflowEntity);
695 FlowEntity udpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_UDP);
696 LOG.debug("createOutboundTblEntry : Installing udp flow {}", udpflowEntity);
697 mdsalManager.addFlow(confTx, udpflowEntity);
699 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, routerId);
700 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
701 mdsalManager.addFlow(confTx, icmpDropFlow);
705 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
706 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
707 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
709 Future<RpcResult<GetTunnelInterfaceNameOutput>> result =
710 itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
711 .setSourceDpid(srcDpId)
712 .setDestinationDpid(dstDpId)
713 .setTunnelType(tunType)
715 rpcResult = result.get();
716 if (!rpcResult.isSuccessful()) {
717 tunType = TunnelTypeGre.class;
718 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
719 .setSourceDpid(srcDpId)
720 .setDestinationDpid(dstDpId)
721 .setTunnelType(tunType)
723 rpcResult = result.get();
724 if (!rpcResult.isSuccessful()) {
725 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
726 rpcResult.getErrors());
728 return rpcResult.getResult().getInterfaceName();
730 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
731 rpcResult.getErrors());
733 return rpcResult.getResult().getInterfaceName();
735 } catch (InterruptedException | ExecutionException | NullPointerException e) {
736 LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
737 + "between {} and {}", srcDpId, dstDpId, e);
743 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName, long routerId,
744 TypedWriteTransaction<Configuration> confTx) {
746 LOG.debug("installSnatMissEntry : called for for the primary NAPT switch dpnId {} ", dpnId);
747 // Install miss entry pointing to group
748 FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName, routerId);
749 mdsalManager.addFlow(confTx, flowEntity);
752 protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo,
753 String routerName, long routerId) {
754 LOG.debug("installSnatMissEntry : called for dpnId {} with primaryBucket {} ",
755 dpnId, bucketInfo.get(0));
756 // Install the select group
757 long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
758 NatUtil.getGroupIdKey(routerName));
759 if (groupId == NatConstants.INVALID_ID) {
760 LOG.error("installSnatMissEntry: Unable to obtain group ID for Key: {}", routerName);
763 GroupEntity groupEntity =
764 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
765 LOG.debug("installSnatMissEntry : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
766 mdsalManager.syncInstallGroup(groupEntity);
767 // Install miss entry pointing to group
768 FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, routerId, groupId);
769 if (flowEntity == null) {
770 LOG.error("installSnatMissEntry : Flow entity received as NULL. "
771 + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
772 + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
775 mdsalManager.installFlow(flowEntity);
778 void installGroup(BigInteger dpnId, String routerName, long groupId, List<BucketInfo> bucketInfo) {
779 GroupEntity groupEntity =
780 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
781 LOG.debug("installGroup : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
782 mdsalManager.syncInstallGroup(groupEntity);
785 private FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long routerId, long groupId) {
786 LOG.debug("buildSnatFlowEntity : called for dpId {}, routerName {} and groupId {}",
787 dpId, routerName, groupId);
788 List<MatchInfo> matches = new ArrayList<>();
789 matches.add(MatchEthernetType.IPV4);
790 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
792 List<ActionInfo> actionsInfo = new ArrayList<>();
793 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager, idManager,
794 routerId, routerName);
795 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
796 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
797 actionsInfo.add(new ActionGroup(groupId));
798 List<InstructionInfo> instructions = new ArrayList<>();
799 instructions.add(new InstructionApplyActions(actionsInfo));
800 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
801 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
802 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
803 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
805 LOG.debug("buildSnatFlowEntity : Returning SNAT Flow Entity {}", flowEntity);
809 private FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName, long routerId) {
811 LOG.debug("buildSnatFlowEntityForPrmrySwtch : called for primary NAPT switch dpId {}, routerName {}", dpId,
813 List<MatchInfo> matches = new ArrayList<>();
814 matches.add(MatchEthernetType.IPV4);
815 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
817 List<InstructionInfo> instructions = new ArrayList<>();
818 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
820 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
821 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
822 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
823 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
825 LOG.debug("buildSnatFlowEntityForPrmrySwtch : Returning SNAT Flow Entity {}", flowEntity);
829 // TODO : Replace this with ITM Rpc once its available with full functionality
830 protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName, long routerId,
831 TypedWriteTransaction<Configuration> confTx) {
833 LOG.debug("installTerminatingServiceTblEntry : for switch {}, routerName {}",
835 FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName, routerId);
836 if (flowEntity == null) {
837 LOG.error("installTerminatingServiceTblEntry : Flow entity received as NULL. "
838 + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
839 + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
843 mdsalManager.addFlow(confTx, flowEntity);
847 private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName, long routerId) {
848 List<MatchInfo> matches = new ArrayList<>();
849 matches.add(MatchEthernetType.IPV4);
850 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
851 idManager, routerId, routerName);
852 matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
853 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
854 List<InstructionInfo> instructions = new ArrayList<>();
855 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
856 MetaDataUtil.METADATA_MASK_VRFID));
857 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
858 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
859 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
864 public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
865 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
866 .FLOWID_SEPARATOR + routerID;
869 public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
870 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
871 .FLOWID_SEPARATOR + routerID;
874 protected void handleSwitches(BigInteger dpnId, String routerName, long routerId, BigInteger primarySwitchId) {
875 LOG.debug("handleSwitches : Installing SNAT miss entry in switch {}", dpnId);
876 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
877 String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
878 List<BucketInfo> listBucketInfo = new ArrayList<>();
880 if (ifNamePrimary != null) {
881 LOG.debug("handleSwitches : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
882 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
883 interfaceManager, ifNamePrimary, routerId, true);
884 if (listActionInfoPrimary.isEmpty()) {
885 LOG.error("handleSwitches : Unable to retrieve output actions on Non-NAPT switch {} for router {}"
886 + " towards Napt-switch {} via tunnel interface {}", dpnId, routerName, primarySwitchId,
890 LOG.error("handleSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} from "
891 + "Non-Napt switch {} for router {}", primarySwitchId, dpnId, routerName);
893 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
895 listBucketInfo.add(0, bucketPrimary);
896 installSnatMissEntry(dpnId, listBucketInfo, routerName, routerId);
899 List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
900 BigInteger primarySwitchId, String routerName, long routerId) {
901 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
902 String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
903 List<BucketInfo> listBucketInfo = new ArrayList<>();
905 if (ifNamePrimary != null) {
906 LOG.debug("getBucketInfoForNonNaptSwitches : On Non- Napt switch , Primary Tunnel interface is {}",
908 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
909 interfaceManager, ifNamePrimary, routerId, true);
910 if (listActionInfoPrimary.isEmpty()) {
911 LOG.error("getBucketInfoForNonNaptSwitches : Unable to retrieve output actions on Non-NAPT switch {} "
912 + "for router {} towards Napt-switch {} via tunnel interface {}",
913 nonNaptSwitchId, routerName, primarySwitchId, ifNamePrimary);
916 LOG.error("getBucketInfoForNonNaptSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} "
917 + "from Non-Napt switch {} for router {}", primarySwitchId, nonNaptSwitchId, routerName);
919 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
921 listBucketInfo.add(0, bucketPrimary);
922 return listBucketInfo;
925 protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName, long routerId,
926 TypedWriteTransaction<Configuration> confTx) {
929 * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
932 LOG.debug("handlePrimaryNaptSwitch : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
935 List<BucketInfo> listBucketInfo = new ArrayList<>();
936 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
937 listActionInfoPrimary.add(new ActionNxResubmit(NatConstants.TERMINATING_SERVICE_TABLE));
938 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
939 listBucketInfo.add(0, bucketPrimary);
942 installSnatMissEntryForPrimrySwch(dpnId, routerName, routerId, confTx);
943 installTerminatingServiceTblEntry(dpnId, routerName, routerId, confTx);
944 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
945 installNaptPfibEntry(dpnId, routerId, confTx);
946 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
947 if (networkId != null) {
948 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
949 if (vpnUuid != null) {
950 long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
951 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
952 installNaptPfibEntriesForExternalSubnets(routerName, dpnId, null);
953 //Install the NAPT PFIB TABLE which forwards outgoing packet to FIB Table matching on the VPN ID.
954 if (vpnId != NatConstants.INVALID_ID) {
955 installNaptPfibEntry(dpnId, vpnId, null);
957 return Collections.emptyList();
960 LOG.warn("handlePrimaryNaptSwitch : External Vpn ID missing for Ext-Network : {}", networkId);
963 LOG.warn("handlePrimaryNaptSwitch : External Network not available for router : {}", routerName);
967 public void installNaptPfibEntry(BigInteger dpnId, long segmentId,
968 @Nullable TypedWriteTransaction<Configuration> confTx) {
969 LOG.debug("installNaptPfibEntry : called for dpnId {} and segmentId {} ", dpnId, segmentId);
970 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
971 if (confTx != null) {
972 mdsalManager.addFlow(confTx, naptPfibFlowEntity);
974 mdsalManager.installFlow(naptPfibFlowEntity);
978 public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
980 LOG.debug("buildNaptPfibFlowEntity : called for dpId {}, segmentId {}", dpId, segmentId);
981 List<MatchInfo> matches = new ArrayList<>();
982 matches.add(MatchEthernetType.IPV4);
983 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
985 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
986 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
987 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
988 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
989 instructionInfo.add(new InstructionApplyActions(listActionInfo));
991 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
992 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
993 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
994 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
995 LOG.debug("buildNaptPfibFlowEntity : Returning NaptPFib Flow Entity {}", flowEntity);
999 public void handleSnatReverseTraffic(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, Routers router,
1000 long routerId, String routerName, String externalIp) {
1001 LOG.debug("handleSnatReverseTraffic : entry for DPN ID {}, routerId {}, externalIp: {}",
1002 dpnId, routerId, externalIp);
1003 Uuid networkId = router.getNetworkId();
1004 if (networkId == null) {
1005 LOG.error("handleSnatReverseTraffic : networkId is null for the router ID {}", routerId);
1008 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1009 if (vpnName == null) {
1010 LOG.error("handleSnatReverseTraffic : No VPN associated with ext nw {} to handle add external ip "
1011 + "configuration {} in router {}", networkId, externalIp, routerId);
1014 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1015 externalIp, networkId, router, confTx);
1016 LOG.debug("handleSnatReverseTraffic : exit for DPN ID {}, routerId {}, externalIp : {}",
1017 dpnId, routerId, externalIp);
1020 public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
1021 final long routerId, final String routerName, final String externalIp,
1022 final Uuid extNetworkId, @Nullable final Routers router,
1023 final TypedWriteTransaction<Configuration> confTx) {
1024 LOG.debug("advToBgpAndInstallFibAndTsFlows : entry for DPN ID {}, tableId {}, vpnname {} "
1025 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
1026 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
1027 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1028 if (rd == null || rd.isEmpty()) {
1029 LOG.error("advToBgpAndInstallFibAndTsFlows : Unable to get RD for VPN Name {}", vpnName);
1032 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
1033 if (extNwProvType == null) {
1034 LOG.error("advToBgpAndInstallFibAndTsFlows : External Network Provider Type missing");
1037 if (extNwProvType == ProviderTypes.VXLAN) {
1038 evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
1039 nextHopIp, routerId, routerName, extNetworkId, confTx);
1042 //Generate VPN label for the external IP
1043 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
1044 .setIpPrefix(externalIp).build();
1045 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
1047 //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
1048 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
1049 if (result.isSuccessful()) {
1050 LOG.debug("advToBgpAndInstallFibAndTsFlows : inside apply with result success");
1051 GenerateVpnLabelOutput output = result.getResult();
1052 final long label = output.getLabel();
1054 int externalIpInDsFlag = 0;
1055 //Get IPMaps from the DB for the router ID
1056 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
1057 for (IpMap dbIpMap : dbIpMaps) {
1058 String dbExternalIp = dbIpMap.getExternalIp();
1059 //Select the IPMap, whose external IP is the IP for which FIB is installed
1060 if (dbExternalIp.contains(externalIp)) {
1061 String dbInternalIp = dbIpMap.getInternalIp();
1062 IpMapKey dbIpMapKey = dbIpMap.key();
1063 LOG.debug("advToBgpAndInstallFibAndTsFlows : Setting label {} for internalIp {} "
1064 + "and externalIp {}", label, dbInternalIp, externalIp);
1065 IpMap newIpm = new IpMapBuilder().withKey(dbIpMapKey).setInternalIp(dbInternalIp)
1066 .setExternalIp(dbExternalIp).setLabel(label).build();
1067 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1068 naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
1069 externalIpInDsFlag++;
1072 if (externalIpInDsFlag <= 0) {
1073 LOG.debug("advToBgpAndInstallFibAndTsFlows : External Ip {} not found in DS, "
1074 + "Failed to update label {} for routerId {} in DS",
1075 externalIp, label, routerId);
1076 String errMsg = String.format("Failed to update label %s due to external Ip %s not"
1077 + " found in DS for router %s", label, externalIp, routerId);
1078 return Futures.immediateFailedFuture(new Exception(errMsg));
1082 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1083 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni).longValue();
1085 Routers extRouter = router != null ? router :
1086 NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1087 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
1088 externalIp, nextHopIp, extRouter.getNetworkId().getValue(), null, label, l3vni,
1089 RouteOrigin.STATIC, dpnId);
1091 //Install custom FIB routes
1092 List<Instruction> tunnelTableCustomInstructions = new ArrayList<>();
1093 tunnelTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
1094 makeTunnelTableEntry(dpnId, label, l3vni, tunnelTableCustomInstructions, confTx,
1096 makeLFibTableEntry(dpnId, label, tableId, confTx);
1098 //Install custom FIB routes - FIB table.
1099 List<Instruction> fibTableCustomInstructions = createFibTableCustomInstructions(tableId,
1100 routerName, externalIp);
1101 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1102 //Install the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
1103 NatUtil.makePreDnatToSnatTableEntry(mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, confTx);
1105 String externalVpn = vpnName;
1106 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp, extRouter);
1107 if (extNwProvType == ProviderTypes.VLAN || extNwProvType == ProviderTypes.FLAT) {
1108 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
1110 if (externalSubnet.isPresent()) {
1111 externalVpn = externalSubnetId.getValue();
1114 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1115 CreateFibEntryInput input = new CreateFibEntryInputBuilder()
1116 .setVpnName(externalVpn)
1117 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
1118 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
1119 .setInstruction(fibTableCustomInstructions).build();
1120 return fibService.createFibEntry(input);
1122 LOG.error("advToBgpAndInstallFibAndTsFlows : inside apply with result failed");
1123 String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
1124 externalIp, vpnName, result.getErrors());
1125 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1127 }, MoreExecutors.directExecutor());
1129 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
1132 public void onFailure(@NonNull Throwable error) {
1133 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in generate label or fib install process", error);
1137 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
1138 if (result.isSuccessful()) {
1139 LOG.info("advToBgpAndInstallFibAndTsFlows : Successfully installed custom FIB routes for prefix {}",
1142 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in rpc call to create custom Fib entries "
1143 + "for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
1146 }, MoreExecutors.directExecutor());
1149 private List<Instruction> createFibTableCustomInstructions(short tableId, String routerName,
1150 String externalIp) {
1151 List<Instruction> fibTableCustomInstructions = new ArrayList<>();
1152 Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1153 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
1154 externalIp, router);
1155 int instructionIndex = 0;
1156 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
1157 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
1158 fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
1159 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
1163 fibTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(instructionIndex));
1164 return fibTableCustomInstructions;
1167 private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId,
1168 TypedWriteTransaction<Configuration> confTx) {
1169 List<MatchInfo> matches = new ArrayList<>();
1170 matches.add(MatchEthernetType.MPLS_UNICAST);
1171 matches.add(new MatchMplsLabel(serviceId));
1173 List<Instruction> instructions = new ArrayList<>();
1174 List<ActionInfo> actionsInfos = new ArrayList<>();
1175 //NAT is required for IPv4 only. Hence always etherType will be IPv4
1176 actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
1177 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
1178 instructions.add(writeInstruction);
1179 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
1181 // Install the flow entry in L3_LFIB_TABLE
1182 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1184 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1186 COOKIE_VM_LFIB_TABLE, matches, instructions);
1188 mdsalManager.addFlow(confTx, dpId, flowEntity);
1190 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
1193 private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, long l3Vni,
1194 List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx,
1195 ProviderTypes extNwProvType) {
1197 List<MatchInfo> mkMatches = new ArrayList<>();
1199 LOG.debug("makeTunnelTableEntry : DpnId = {} and serviceId = {} and actions = {}",
1200 dpnId, serviceId, customInstructions);
1202 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1203 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
1205 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
1208 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1209 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
1210 NatConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY,
1211 String.format("%s:%d", "TST Flow Entry ", serviceId), 0, 0,
1212 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1214 mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
1217 protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1218 return InstanceIdentifier.builder(RouterIdName.class).child(RouterIds.class,
1219 new RouterIdsKey(routerId)).build();
1222 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1223 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
1224 .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
1228 protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1229 LOG.trace("update : origRouter: {} updatedRouter: {}", original, update);
1230 String routerName = original.getRouterName();
1231 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1232 if (routerId == NatConstants.INVALID_ID) {
1233 LOG.error("update : external router event - Invalid routerId for routerName {}", routerName);
1236 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + update.key(), () -> {
1237 List<ListenableFuture<Void>> futures = new ArrayList<>();
1238 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeFlowInvTx -> {
1239 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, removeFlowInvTx -> {
1240 long bgpVpnId = NatConstants.INVALID_ID;
1241 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1242 if (bgpVpnUuid != null) {
1243 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1245 //BigInteger dpnId = getPrimaryNaptSwitch(routerName);
1246 /* Get Primary Napt Switch for existing router from "router-to-napt-switch" DS.
1247 * if dpnId value is null or zero then go for electing new Napt switch for existing router.
1249 BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1250 boolean isPrimaryNaptSwitchNotSelected = (dpnId == null || dpnId.equals(BigInteger.ZERO));
1251 Uuid networkId = original.getNetworkId();
1252 // Check if its update on SNAT flag
1253 boolean originalSNATEnabled = original.isEnableSnat();
1254 boolean updatedSNATEnabled = update.isEnableSnat();
1255 LOG.debug("update :called with originalFlag and updatedFlag for SNAT enabled "
1256 + "as {} and {} with Elected Dpn {}(isPrimaryNaptSwitchNotSelected:{})",
1257 originalSNATEnabled, updatedSNATEnabled, dpnId, isPrimaryNaptSwitchNotSelected);
1258 // Cluster Reboot Case Handling
1259 // 1. DPN not elected during add event(due to none of the OVS connected)
1260 // 2. Update event called with changes of parameters(but enableSnat is not changed)
1261 // 3. First Elect dpnId and process other changes with valid dpnId
1262 if (originalSNATEnabled != updatedSNATEnabled || isPrimaryNaptSwitchNotSelected) {
1263 if (originalSNATEnabled && !updatedSNATEnabled) {
1264 if (isPrimaryNaptSwitchNotSelected) {
1265 LOG.info("No Action to be taken when SNAT is disabled "
1266 + "with no Napt Switch Election for Router {}", routerName);
1269 //SNAT disabled for the router
1270 Uuid networkUuid = original.getNetworkId();
1271 LOG.info("update : SNAT disabled for Router {}", routerName);
1272 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1273 handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId, routerId,
1275 } else if (updatedSNATEnabled) {
1276 LOG.info("update : SNAT enabled for Router {}", routerName);
1277 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid,
1278 true, writeFlowInvTx);
1279 if (isPrimaryNaptSwitchNotSelected) {
1280 dpnId = selectNewNAPTSwitch(routerName);
1281 if (dpnId != null && !dpnId.equals(BigInteger.ZERO)) {
1282 handleEnableSnat(update, routerId, dpnId, bgpVpnId, removeFlowInvTx);
1284 LOG.error("update : Failed to elect Napt Switch During update event"
1285 + " of router {}", routerName);
1289 LOG.info("update : no need to process external/subnet changes as it's will taken care"
1290 + "in handleDisableSnat/handleEnableSnat");
1293 if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1294 NatUtil.installRouterGwFlows(txRunner, vpnManager, original, dpnId, NwConstants.DEL_FLOW);
1295 NatUtil.installRouterGwFlows(txRunner, vpnManager, update, dpnId, NwConstants.ADD_FLOW);
1298 if (updatedSNATEnabled != originalSNATEnabled) {
1299 LOG.info("update : no need to process external/subnet changes as it's will taken care in "
1300 + "handleDisableSnat/handleEnableSnat");
1303 //Check if the Update is on External IPs
1304 LOG.debug("update : Checking if this is update on External IPs for router {}", routerName);
1305 List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
1306 List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
1308 //Check if the External IPs are removed during the update.
1309 Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
1310 removedExternalIps.removeAll(updatedExternalIps);
1311 if (removedExternalIps.size() > 0) {
1312 LOG.debug("update : Start processing of the External IPs removal for router {}", routerName);
1313 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
1314 removedExternalIps, original.getExtGwMacAddress(),
1317 for (String removedExternalIp : removedExternalIps) {
1319 1) Remove the mappings in the IntExt IP model which has external IP.
1320 2) Remove the external IP in the ExternalCounter model.
1321 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the
1322 least loaded external IP.
1323 Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1324 4) Increase the count of the allocated external IP by one.
1325 5) Advertise to the BGP if external IP is allocated for the first time for the router
1326 i.e. the route for the external IP is absent.
1327 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for
1328 the removed external IPs and also from the model.
1329 7) Advertise to the BGP for removing the route for the removed external IPs.
1332 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1333 String externalIp = externalIpParts[0];
1334 String externalIpPrefix = externalIpParts[1];
1335 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1337 LOG.debug("update : Clear the routes from the BGP and remove the FIB and TS "
1338 + "entries for removed external IP {}", externalIpAddrStr);
1339 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1340 String vpnName = "";
1341 if (vpnUuId != null) {
1342 vpnName = vpnUuId.getValue();
1344 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName, networkId,
1345 update.getExtGwMacAddress(), removeFlowInvTx);
1347 LOG.debug("update : Remove the mappings in the IntExtIP model which has external IP.");
1348 //Get the internal IPs which are associated to the removed external IPs
1349 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1350 List<String> removedInternalIps = new ArrayList<>();
1351 for (IpMap ipMap : ipMaps) {
1352 if (ipMap.getExternalIp().equals(externalIpAddrStr)) {
1353 removedInternalIps.add(ipMap.getInternalIp());
1357 LOG.debug("update : Remove the mappings of the internal IPs from the IntExtIP model.");
1358 for (String removedInternalIp : removedInternalIps) {
1359 LOG.debug("update : Remove the IP mapping of the internal IP {} for the "
1360 + "router ID {} from the IntExtIP model",
1361 removedInternalIp, routerId);
1362 naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1365 LOG.debug("update : Remove the count mapping of the external IP {} for the "
1366 + "router ID {} from the ExternalIpsCounter model.",
1367 externalIpAddrStr, routerId);
1368 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1370 LOG.debug("update : Allocate the least loaded external IPs to the subnets "
1371 + "whose external IPs were removed.");
1372 for (String removedInternalIp : removedInternalIps) {
1373 allocateExternalIp(dpnId, update, routerId, routerName, networkId,
1374 removedInternalIp, writeFlowInvTx);
1376 LOG.debug("update : Remove the NAPT translation entries from "
1377 + "Inbound and Outbound NAPT tables for the removed external IPs.");
1378 //Get the internalIP and internal Port which were associated to the removed external IP.
1379 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1380 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier
1381 .builder(IntextIpPortMap.class)
1382 .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1383 Optional<IpPortMapping> ipPortMapping;
1385 ipPortMapping = SingleTransactionDataBroker
1386 .syncReadOptional(dataBroker,
1387 LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1388 } catch (ReadFailedException e) {
1389 LOG.error("Failed to read ipPortMapping for router id {}", routerId, e);
1390 ipPortMapping = Optional.absent();
1393 if (ipPortMapping.isPresent()) {
1394 for (IntextIpProtocolType intextIpProtocolType :
1395 ipPortMapping.get().nonnullIntextIpProtocolType()) {
1396 ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1397 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
1398 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1399 if (ipPortExternal.getIpAddress().equals(externalIp)) {
1400 List<String> removedInternalIpPorts =
1401 protoTypesIntIpPortsMap.get(protoType);
1402 if (removedInternalIpPorts != null) {
1403 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1404 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1406 removedInternalIpPorts = new ArrayList<>();
1407 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1408 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1415 //Remove the IP port map from the intext-ip-port-map model, which were containing
1416 // the removed external IP.
1417 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts =
1418 protoTypesIntIpPortsMap.entrySet();
1419 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1420 for (Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts) {
1421 ProtocolTypes protocolType = (ProtocolTypes) protoTypesIntIpPort.getKey();
1422 List<String> removedInternalIpPorts = (List<String>) protoTypesIntIpPort.getValue();
1423 for (String removedInternalIpPort : removedInternalIpPorts) {
1424 // Remove the IP port map from the intext-ip-port-map model,
1425 // which were containing the removed external IP
1426 naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort,
1428 //Remove the IP port incomint packer map.
1429 naptPacketInHandler.removeIncomingPacketMap(
1430 routerId + NatConstants.COLON_SEPARATOR + removedInternalIpPort);
1431 String[] removedInternalIpPortParts = removedInternalIpPort
1432 .split(NatConstants.COLON_SEPARATOR);
1433 if (removedInternalIpPortParts.length == 2) {
1434 String removedInternalIp = removedInternalIpPortParts[0];
1435 String removedInternalPort = removedInternalIpPortParts[1];
1436 List<String> removedInternalPortsList =
1437 internalIpPortMap.get(removedInternalPort);
1438 if (removedInternalPortsList != null) {
1439 removedInternalPortsList.add(removedInternalPort);
1440 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1441 naptPacketInHandler.removeIncomingPacketMap(routerId
1442 + NatConstants.COLON_SEPARATOR + removedInternalIp
1443 + NatConstants.COLON_SEPARATOR + removedInternalPort);
1444 //Remove the NAPT translation entries from Outbound NAPT table
1445 naptEventHandler.removeNatFlows(dpnId,
1446 NwConstants.OUTBOUND_NAPT_TABLE,
1447 routerId, removedInternalIp,
1448 Integer.parseInt(removedInternalPort),
1449 protocolType.getName());
1450 naptEventHandler.removeNatFlows(dpnId,
1451 NwConstants.INBOUND_NAPT_TABLE,
1452 routerId, removedInternalIp,
1453 Integer.parseInt(removedInternalPort),
1454 protocolType.getName());
1456 removedInternalPortsList = new ArrayList<>();
1457 removedInternalPortsList.add(removedInternalPort);
1458 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1459 naptPacketInHandler.removeIncomingPacketMap(routerId
1460 + NatConstants.COLON_SEPARATOR + removedInternalIp
1461 + NatConstants.COLON_SEPARATOR + removedInternalPort);
1462 //Remove the NAPT translation entries from Outbound NAPT table
1463 naptEventHandler.removeNatFlows(dpnId,
1464 NwConstants.OUTBOUND_NAPT_TABLE,
1465 routerId, removedInternalIp,
1466 Integer.parseInt(removedInternalPort),
1467 protocolType.getName());
1468 naptEventHandler.removeNatFlows(dpnId,
1469 NwConstants.INBOUND_NAPT_TABLE, routerId, removedInternalIp,
1470 Integer.parseInt(removedInternalPort),
1471 protocolType.getName());
1477 // Delete the entry from SnatIntIpPortMap DS
1478 Set<String> internalIps = internalIpPortMap.keySet();
1479 for (String internalIp : internalIps) {
1480 LOG.debug("update : Removing IpPort having the internal IP {} from the "
1481 + "model SnatIntIpPortMap", internalIp);
1482 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1485 naptManager.removeNaptPortPool(externalIp);
1488 "update : End processing of the External IPs removal for router {}", routerName);
1491 //Check if the External IPs are added during the update.
1492 Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
1493 addedExternalIps.removeAll(originalExternalIps);
1494 if (addedExternalIps.size() != 0) {
1495 LOG.debug("update : Start processing of the External IPs addition for router {}",
1497 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
1498 update.getExtGwMacAddress(), dpnId,
1499 update.getNetworkId());
1501 for (String addedExternalIp : addedExternalIps) {
1503 1) Do nothing in the IntExtIp model.
1504 2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1506 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1507 String externalIp = externalIpParts[0];
1508 String externalIpPrefix = externalIpParts[1];
1509 String externalpStr = externalIp + "/" + externalIpPrefix;
1510 LOG.debug("update : Initialise the count mapping of the external IP {} for the "
1511 + "router ID {} in the ExternalIpsCounter model.",
1512 externalpStr, routerId);
1513 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1514 subnetRegisterMapping(update, routerId);
1515 LOG.info("update : Installing fib flow fo newly added Ips");
1516 handleSnatReverseTraffic(writeFlowInvTx, dpnId, update, routerId, routerName, externalpStr);
1519 "update : End processing of the External IPs addition during the update operation");
1522 //Check if its Update on subnets
1523 LOG.debug("update : Checking if this is update on subnets for router {}", routerName);
1524 List<Uuid> originalSubnetIds = original.getSubnetIds();
1525 List<Uuid> updatedSubnetIds = update.getSubnetIds();
1526 Set<Uuid> addedSubnetIds =
1527 updatedSubnetIds != null ? new HashSet<>(updatedSubnetIds) : new HashSet<>();
1528 if (originalSubnetIds != null) {
1529 addedSubnetIds.removeAll(originalSubnetIds);
1532 //Check if the Subnet IDs are added during the update.
1533 if (addedSubnetIds.size() != 0) {
1535 "update : Start processing of the Subnet IDs addition for router {}", routerName);
1536 for (Uuid addedSubnetId : addedSubnetIds) {
1538 1) Select the least loaded external IP for the subnet and store the mapping of the
1539 subnet IP and the external IP in the IntExtIp model.
1540 2) Increase the count of the selected external IP by one.
1541 3) Advertise to the BGP if external IP is allocated for the first time for the
1542 router i.e. the route for the external IP is absent.
1544 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1545 if (subnetIp != null) {
1546 allocateExternalIp(dpnId, update, routerId, routerName, networkId, subnetIp,
1550 LOG.debug("update : End processing of the Subnet IDs addition for router {}", routerName);
1553 //Check if the Subnet IDs are removed during the update.
1554 Set<Uuid> removedSubnetIds = new HashSet<>(originalSubnetIds);
1555 removedSubnetIds.removeAll(updatedSubnetIds);
1556 if (removedSubnetIds.size() != 0) {
1558 "update : Start processing of the Subnet IDs removal for router {}", routerName);
1559 for (Uuid removedSubnetId : removedSubnetIds) {
1560 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1561 if (subnetAddr != null) {
1563 1) Remove the subnet IP and the external IP in the IntExtIp map
1564 2) Decrease the count of the coresponding external IP by one.
1565 3) Advertise to the BGP for removing the routes of the corresponding external
1566 IP if its not allocated to any other internal IP.
1569 String externalIp = naptManager.getExternalIpAllocatedForSubnet(routerId,
1570 subnetAddr[0] + "/" + subnetAddr[1]);
1571 if (externalIp == null) {
1572 LOG.error("update : No mapping found for router ID {} and internal IP {}",
1573 routerId, subnetAddr[0]);
1577 naptManager.updateCounter(routerId, externalIp, false);
1578 // Traverse entire model of external-ip counter whether external ip is not
1579 // used by any other internal ip in any router
1580 if (!isExternalIpAllocated(externalIp)) {
1581 LOG.debug("update : external ip is not allocated to any other "
1582 + "internal IP so proceeding to remove routes");
1583 clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId,
1584 Collections.singleton(externalIp), null, update.getExtGwMacAddress(),
1586 LOG.debug("update : Successfully removed fib entries in switch {} for "
1587 + "router {} with networkId {} and externalIp {}",
1588 dpnId, routerId, networkId, externalIp);
1591 LOG.debug("update : Remove the IP mapping for the router ID {} and "
1592 + "internal IP {} external IP {}", routerId, subnetAddr[0], externalIp);
1593 naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1596 LOG.debug("update : End processing of the Subnet IDs removal for router {}", routerName);
1601 }, NatConstants.NAT_DJC_MAX_RETRIES);
1604 private boolean isExternalIpAllocated(String externalIp) {
1605 InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1606 Optional<ExternalIpsCounter> externalCountersData;
1608 externalCountersData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1609 LogicalDatastoreType.OPERATIONAL, id);
1610 } catch (ReadFailedException e) {
1611 LOG.error("Failed to read external counters data for ExternalIp {}", externalIp, e);
1612 externalCountersData = Optional.absent();
1614 if (externalCountersData.isPresent()) {
1615 ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1616 for (ExternalCounters ext : externalIpsCounters.nonnullExternalCounters()) {
1617 for (ExternalIpCounter externalIpCount : ext.nonnullExternalIpCounter()) {
1618 if (externalIpCount.getExternalIp().equals(externalIp)) {
1619 if (externalIpCount.getCounter() != 0) {
1630 private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
1631 Uuid networkId, String subnetIp, TypedWriteTransaction<Configuration> writeFlowInvTx) {
1632 String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1634 InetAddress address = InetAddress.getByName(subnetIpParts[0]);
1635 if (address instanceof Inet6Address) {
1636 LOG.debug("allocateExternalIp : Skipping ipv6 address {} for the router {}.", address, routerName);
1639 } catch (UnknownHostException e) {
1640 LOG.error("allocateExternalIp : Invalid ip address {}", subnetIpParts[0], e);
1643 String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1644 if (leastLoadedExtIpAddr != null) {
1645 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1646 String leastLoadedExtIp = externalIpParts[0];
1647 String leastLoadedExtIpPrefix = externalIpParts[1];
1648 IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1649 subnetIp = subnetIpParts[0];
1650 String subnetIpPrefix = subnetIpParts[1];
1651 IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1652 LOG.debug("allocateExternalIp : Add the IP mapping for the router ID {} and internal "
1653 + "IP {} and prefix {} -> external IP {} and prefix {}",
1654 routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1655 naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1658 // Check if external IP is already assigned a route. (i.e. External IP is previously
1659 // allocated to any of the subnets)
1660 // If external IP is already assigned a route, (, do not re-advertise to the BGP
1661 String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1662 Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1663 if (label != null) {
1665 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1666 IpMapKey ipMapKey = new IpMapKey(internalIp);
1667 LOG.debug("allocateExternalIp : Setting label {} for internalIp {} and externalIp {}",
1668 label, internalIp, leastLoadedExtIpAddrStr);
1669 IpMap newIpm = new IpMapBuilder().withKey(ipMapKey).setInternalIp(internalIp)
1670 .setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1671 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1672 naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1676 // Re-advertise to the BGP for the external IP, which is allocated to the subnet
1677 // for the first time and hence not having a route.
1678 //Get the VPN Name using the network ID
1679 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1680 if (vpnName != null) {
1681 LOG.debug("allocateExternalIp : Retrieved vpnName {} for networkId {}", vpnName, networkId);
1682 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1683 LOG.debug("allocateExternalIp : Best effort for getting primary napt switch when router i/f are"
1684 + "added after gateway-set");
1685 dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1686 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1687 LOG.error("allocateExternalIp : dpnId is null or Zero for the router {}", routerName);
1691 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1692 leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, networkId, router,
1699 protected Long checkExternalIpLabel(long routerId, String externalIp) {
1700 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1701 for (IpMap ipMap : ipMaps) {
1702 if (ipMap.getExternalIp().equals(externalIp)) {
1703 if (ipMap.getLabel() != null) {
1704 return ipMap.getLabel();
1708 LOG.error("checkExternalIpLabel : no ipMaps found for routerID:{} and externalIP:{}", routerId, externalIp);
1713 protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1714 LOG.trace("remove : Router delete method");
1716 ROUTER DELETE SCENARIO
1717 1) Get the router ID from the event.
1718 2) Build the cookie information from the router ID.
1719 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1720 4) Build the flow with the cookie value.
1721 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1722 6) Remove the flows from the other switches which points to the primary and secondary
1723 switches for the flows related the router ID.
1724 7) Get the list of external IP address maintained for the router ID.
1725 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1726 9) Withdraw the corresponding routes from the BGP.
1729 if (identifier == null || router == null) {
1730 LOG.error("remove : returning without processing since routers is null");
1734 String routerName = router.getRouterName();
1735 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.key(),
1736 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
1737 LOG.info("remove : Removing default NAT route from FIB on all dpns part of router {} ",
1739 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1740 if (routerId == NatConstants.INVALID_ID) {
1741 LOG.error("remove : Remove external router event - Invalid routerId for routerName {}",
1745 long bgpVpnId = NatConstants.INVALID_ID;
1746 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1747 if (bgpVpnUuid != null) {
1748 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1750 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, false,
1752 Uuid networkUuid = router.getNetworkId();
1754 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1755 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
1756 // No NAPT switch for external router, probably because the router is not attached to
1758 // internal networks
1760 "No NAPT switch for router {}, check if router is attached to any internal "
1765 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1766 handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId,
1769 if (NatUtil.releaseId(idManager, NatConstants.ODL_VNI_POOL_NAME, routerName)
1770 == NatConstants.INVALID_ID) {
1771 LOG.error("remove: Unable to release VNI for router - {}", routerName);
1773 })), NatConstants.NAT_DJC_MAX_RETRIES);
1776 public void handleDisableSnat(Routers router, Uuid networkUuid, @NonNull Collection<String> externalIps,
1777 boolean routerFlag, @Nullable String vpnName, BigInteger naptSwitchDpnId,
1778 long routerId, TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
1779 LOG.info("handleDisableSnat : Entry");
1780 String routerName = router.getRouterName();
1783 removeNaptSwitch(routerName);
1785 updateNaptSwitch(routerName, BigInteger.ZERO);
1788 LOG.debug("handleDisableSnat : Remove the ExternalCounter model for the router ID {}", routerId);
1789 naptManager.removeExternalCounter(routerId);
1791 LOG.debug("handleDisableSnat : got primarySwitch as dpnId {}", naptSwitchDpnId);
1792 if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
1793 LOG.error("handleDisableSnat : Unable to retrieve the primary NAPT switch for the "
1794 + "router ID {} from RouterNaptSwitch model", routerId);
1797 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
1799 if (extNwProvType == null) {
1800 LOG.error("handleDisableSnat : External Network Provider Type missing");
1803 Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps());
1804 removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnName, externalIps,
1805 externalSubnetList, removeFlowInvTx, extNwProvType);
1806 removeFlowsFromNonActiveSwitches(routerId, routerName, naptSwitchDpnId, removeFlowInvTx);
1807 String externalSubnetVpn = null;
1808 for (Uuid externalSubnetId : externalSubnetList) {
1809 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, externalSubnetId);
1810 // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
1811 if (externalSubnet.isPresent()) {
1812 externalSubnetVpn = externalSubnetId.getValue();
1813 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, externalSubnetVpn,
1814 router.getExtGwMacAddress(), removeFlowInvTx);
1817 if (externalSubnetVpn == null) {
1818 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnName,
1819 router.getExtGwMacAddress(), removeFlowInvTx);
1821 // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
1822 // for the router ID.
1823 LOG.debug("handleDisableSnat : Remove the Internal to external IP address maintained for the "
1824 + "router ID {} in the DS", routerId);
1825 naptManager.removeMapping(routerId);
1826 } catch (InterruptedException | ExecutionException e) {
1827 LOG.error("handleDisableSnat : Exception while handling disableSNAT for router :{}", routerName, e);
1829 LOG.info("handleDisableSnat : Exit");
1832 // TODO Clean up the exception handling
1833 @SuppressWarnings("checkstyle:IllegalCatch")
1834 public void handleDisableSnatInternetVpn(String routerName, long routerId, Uuid networkUuid,
1835 @NonNull Collection<String> externalIps,
1836 String vpnId, TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
1837 LOG.debug("handleDisableSnatInternetVpn: Started to process handle disable snat for router {} "
1838 + "with internet vpn {}", routerName, vpnId);
1840 BigInteger naptSwitchDpnId = null;
1841 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
1842 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1843 Optional<RouterToNaptSwitch> rtrToNapt;
1845 rtrToNapt = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1846 LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1847 } catch (ReadFailedException e) {
1848 LOG.error("Failed to read NAPT switch for router {}", routerName, e);
1849 rtrToNapt = Optional.absent();
1851 if (rtrToNapt.isPresent()) {
1852 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1854 LOG.debug("handleDisableSnatInternetVpn : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1856 removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId,
1859 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1860 if (extGwMacAddress != null) {
1861 LOG.debug("handleDisableSnatInternetVpn : External Gateway MAC address {} found for "
1862 + "External Router ID {}", extGwMacAddress, routerId);
1864 LOG.error("handleDisableSnatInternetVpn : No External Gateway MAC address found for "
1865 + "External Router ID {}", routerId);
1868 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId, extGwMacAddress,
1870 } catch (Exception ex) {
1871 LOG.error("handleDisableSnatInternetVpn : Failed to remove fib entries for routerId {} "
1872 + "in naptSwitchDpnId {}", routerId, naptSwitchDpnId, ex);
1874 if (NatUtil.releaseId(idManager, NatConstants.ODL_VNI_POOL_NAME, vpnId) == NatConstants.INVALID_ID) {
1875 LOG.error("handleDisableSnatInternetVpn : Unable to release VNI for vpnId {} ", vpnId);
1877 } catch (InterruptedException | ExecutionException e) {
1878 LOG.error("handleDisableSnatInternetVpn: Exception while handling disableSNATInternetVpn for router {} "
1879 + "with internet vpn {}", routerName, vpnId, e);
1881 LOG.debug("handleDisableSnatInternetVpn: Processed handle disable snat for router {} with internet vpn {}",
1885 // TODO Clean up the exception handling
1886 @SuppressWarnings("checkstyle:IllegalCatch")
1887 public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1888 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
1889 .setPrimarySwitchId(naptSwitchId).build();
1891 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1892 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1893 } catch (Exception ex) {
1894 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
1895 naptSwitchId, routerName);
1897 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
1898 naptSwitchId, routerName);
1901 protected void removeNaptSwitch(String routerName) {
1902 // Remove router and switch from model
1903 InstanceIdentifier<RouterToNaptSwitch> id =
1904 InstanceIdentifier.builder(NaptSwitches.class)
1905 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1906 LOG.debug("removeNaptSwitch : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1907 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1908 //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
1909 NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
1912 public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
1913 BigInteger dpnId, Uuid networkId, String vpnName,
1914 @NonNull Collection<String> externalIps,
1915 Collection<Uuid> externalSubnetList,
1916 TypedReadWriteTransaction<Configuration> confTx,
1917 ProviderTypes extNwProvType)
1918 throws InterruptedException, ExecutionException {
1920 LOG.debug("removeNaptFlowsFromActiveSwitch : Remove NAPT flows from Active switch");
1921 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1923 //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1924 // traffic which comes from the VMs of the NAPT switches)
1925 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1926 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1929 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1930 + "and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
1931 mdsalManager.removeFlow(confTx, preSnatFlowEntity);
1933 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1934 // traffic which comes from the VMs of the non NAPT switches)
1935 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
1936 elanManager, idManager, routerId, routerName);
1937 String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
1938 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1940 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1941 + "and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
1942 mdsalManager.removeFlow(confTx, tsNatFlowEntity);
1944 //Remove the flow table 25->44 from NAPT Switch
1945 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1946 NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, dpnId);
1949 //Remove the Outbound flow entry which forwards the packet to FIB Table
1951 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {}"
1952 + " and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1954 String outboundTcpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1955 NwConstants.IP_PROT_TCP);
1956 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1957 outboundTcpNatFlowRef);
1958 mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
1960 String outboundUdpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1961 NwConstants.IP_PROT_UDP);
1962 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1963 outboundUdpNatFlowRef);
1964 mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
1966 String icmpDropFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1967 NwConstants.IP_PROT_ICMP);
1968 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1970 mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
1971 boolean lastRouterOnExternalNetwork =
1972 !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker, networkId, routerName, dpnId);
1973 if (lastRouterOnExternalNetwork) {
1974 removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps, confTx);
1976 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
1977 // External Subnet Vpn Id.
1978 for (Uuid externalSubnetId : externalSubnetList) {
1979 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
1980 if (subnetVpnId != -1 && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
1981 dataBroker, externalSubnetId, routerName, dpnId)) {
1982 String natPfibSubnetFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
1983 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE,
1984 natPfibSubnetFlowRef);
1985 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
1986 LOG.debug("removeNaptFlowsFromActiveSwitch : Removed the flow in table {} with external subnet "
1987 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
1988 subnetVpnId, dpnId);
1992 //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1993 String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1994 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1997 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1998 + "and router ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
1999 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
2001 if (lastRouterOnExternalNetwork) {
2002 // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
2003 // - This does not work since ext-routers is deleted already - no network info
2004 //Get the VPN ID from the ExternalNetworks model
2006 if (vpnName == null || vpnName.isEmpty()) {
2007 // ie called from router delete cases
2008 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
2009 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnUuid is {}", vpnUuid);
2010 if (vpnUuid != null) {
2011 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2012 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId {} for external network {} router delete "
2013 + "or disableSNAT scenario", vpnId, networkId);
2016 // ie called from disassociate vpn case
2017 LOG.debug("removeNaptFlowsFromActiveSwitch : This is disassociate nw with vpn case with vpnName {}",
2019 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2020 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId for disassociate nw with vpn scenario {}",
2024 if (vpnId != NatConstants.INVALID_ID) {
2025 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2026 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2027 FlowEntity natPfibVpnFlowEntity =
2028 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2029 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in {} for the active switch with the "
2030 + "DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2031 mdsalManager.removeFlow(confTx, natPfibVpnFlowEntity);
2035 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2036 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2037 if (ipPortMapping == null) {
2038 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the IpPortMapping");
2042 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2043 String protocol = intextIpProtocolType.getProtocol().name();
2044 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2045 String ipPortInternal = ipPortMap.getIpPortInternal();
2046 String[] ipPortParts = ipPortInternal.split(":");
2047 if (ipPortParts.length != 2) {
2048 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the Internal IP and port");
2051 String internalIp = ipPortParts[0];
2052 String internalPort = ipPortParts[1];
2054 //Build the flow for the outbound NAPT table
2055 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2056 + NatConstants.COLON_SEPARATOR + internalPort);
2057 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2058 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
2059 FlowEntity outboundNaptFlowEntity =
2060 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2062 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch "
2063 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2064 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
2066 //Build the flow for the inbound NAPT table
2067 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2068 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
2069 FlowEntity inboundNaptFlowEntity =
2070 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2072 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active active switch "
2073 + "with the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2074 mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
2079 protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
2080 @NonNull Collection<String> externalIps,
2081 TypedReadWriteTransaction<Configuration> writeFlowInvTx)
2082 throws ExecutionException, InterruptedException {
2083 long extVpnId = NatConstants.INVALID_ID;
2084 if (networkId != null) {
2085 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
2086 if (vpnUuid != null) {
2087 extVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2089 LOG.debug("removeNaptFibExternalOutputFlows : vpnUuid is null");
2092 LOG.debug("removeNaptFibExternalOutputFlows : networkId is null");
2093 extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2095 if (extVpnId == NatConstants.INVALID_ID) {
2096 LOG.warn("removeNaptFibExternalOutputFlows : extVpnId not found for routerId {}", routerId);
2097 extVpnId = routerId;
2099 for (String ip : externalIps) {
2100 String extIp = removeMaskFromIp(ip);
2101 String naptFlowRef = getFlowRefNaptPreFib(dpnId, NwConstants.NAPT_PFIB_TABLE, extVpnId);
2102 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in table {} for the active switch"
2103 + " with the DPN ID {} and router ID {} and IP {} flowRef {}",
2104 NwConstants.NAPT_PFIB_TABLE, dpnId, routerId, extIp, naptFlowRef);
2105 FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef);
2106 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2110 private String removeMaskFromIp(String ip) {
2111 if (ip != null && !ip.trim().isEmpty()) {
2112 return ip.split("/")[0];
2117 public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
2118 BigInteger dpnId, Uuid networkId, String vpnName,
2119 TypedReadWriteTransaction<Configuration> writeFlowInvTx)
2120 throws ExecutionException, InterruptedException {
2121 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : Remove NAPT flows from Active switch Internet Vpn");
2122 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
2124 //Remove the NAPT PFIB TABLE entry
2126 if (vpnName != null) {
2127 // ie called from disassociate vpn case
2128 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : This is disassociate nw with vpn case "
2129 + "with vpnName {}", vpnName);
2130 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2131 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : vpnId for disassociate nw with vpn scenario {}",
2135 if (vpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker,
2136 networkId, routerName, dpnId)) {
2137 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2138 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2139 FlowEntity natPfibVpnFlowEntity =
2140 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2141 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the active switch "
2142 + "with the DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2143 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2145 // Remove IP-PORT active NAPT entries and release port from IdManager
2146 // For the router ID get the internal IP , internal port and the corresponding
2147 // external IP and external Port.
2148 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2149 if (ipPortMapping == null) {
2150 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the IpPortMapping");
2153 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2154 String protocol = intextIpProtocolType.getProtocol().name();
2155 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2156 String ipPortInternal = ipPortMap.getIpPortInternal();
2157 String[] ipPortParts = ipPortInternal.split(":");
2158 if (ipPortParts.length != 2) {
2159 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the Internal IP "
2163 String internalIp = ipPortParts[0];
2164 String internalPort = ipPortParts[1];
2166 //Build the flow for the outbound NAPT table
2167 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2168 + NatConstants.COLON_SEPARATOR + internalPort);
2169 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2170 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
2171 FlowEntity outboundNaptFlowEntity =
2172 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2174 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2175 + "active switch with the DPN ID {} and router ID {}",
2176 NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2177 mdsalManager.removeFlow(writeFlowInvTx, outboundNaptFlowEntity);
2179 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2180 final String externalIp = ipPortExternal.getIpAddress();
2182 //Build the flow for the inbound NAPT table
2183 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2184 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
2185 FlowEntity inboundNaptFlowEntity =
2186 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2188 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2189 + "active active switch with the DPN ID {} and router ID {}",
2190 NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2191 mdsalManager.removeFlow(writeFlowInvTx, inboundNaptFlowEntity);
2193 // Finally release port from idmanager
2194 String internalIpPort = internalIp + ":" + internalPort;
2195 naptManager.removePortFromPool(internalIpPort, externalIp);
2197 //Remove sessions from models
2198 naptManager.removeIpPortMappingForRouterID(routerId);
2199 naptManager.removeIntIpPortMappingForRouterID(routerId);
2203 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Invalid vpnId {}", vpnId);
2207 public void removeFlowsFromNonActiveSwitches(long routerId, String routerName,
2208 BigInteger naptSwitchDpnId, TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2209 throws ExecutionException, InterruptedException {
2210 LOG.debug("removeFlowsFromNonActiveSwitches : Remove NAPT related flows from non active switches");
2212 // Remove the flows from the other switches which points to the primary and secondary switches
2213 // for the flows related the router ID.
2214 List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
2215 if (allSwitchList.isEmpty()) {
2216 LOG.error("removeFlowsFromNonActiveSwitches : Unable to get the swithces for the router {}", routerName);
2219 for (BigInteger dpnId : allSwitchList) {
2220 if (!naptSwitchDpnId.equals(dpnId)) {
2221 LOG.info("removeFlowsFromNonActiveSwitches : Handle Ordinary switch");
2223 //Remove the PSNAT entry which forwards the packet to Terminating Service table
2224 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
2225 FlowEntity preSnatFlowEntity =
2226 NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
2228 LOG.info("removeFlowsFromNonActiveSwitches : Remove the flow in the {} for the non active switch "
2229 + "with the DPN ID {} and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
2230 mdsalManager.removeFlow(removeFlowInvTx, preSnatFlowEntity);
2232 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
2233 long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
2234 NatUtil.getGroupIdKey(routerName));
2235 if (groupId != NatConstants.INVALID_ID) {
2237 "removeFlowsFromNonActiveSwitches : Remove the group {} for the non active switch with "
2238 + "the DPN ID {} and router ID {}", groupId, dpnId, routerId);
2239 mdsalManager.removeGroup(removeFlowInvTx, dpnId, groupId);
2241 LOG.error("removeFlowsFromNonActiveSwitches: Unable to obtained groupID for router:{}", routerName);
2247 public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, @Nullable Uuid networkUuid,
2248 @NonNull Collection<String> externalIps, @Nullable String vpnName,
2249 String extGwMacAddress, TypedReadWriteTransaction<Configuration> confTx)
2250 throws ExecutionException, InterruptedException {
2251 //Withdraw the corresponding routes from the BGP.
2252 //Get the network ID using the router ID.
2253 LOG.debug("clrRtsFromBgpAndDelFibTs : Advertise to BGP and remove routes for externalIps {} with routerId {},"
2254 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2255 if (networkUuid == null) {
2256 LOG.error("clrRtsFromBgpAndDelFibTs : networkId is null");
2260 if (externalIps.isEmpty()) {
2261 LOG.error("clrRtsFromBgpAndDelFibTs : externalIps is empty");
2265 if (vpnName == null) {
2266 //Get the VPN Name using the network ID
2267 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2268 if (vpnName == null) {
2269 LOG.error("clrRtsFromBgpAndDelFibTs : No VPN associated with ext nw {} for the router {}",
2270 networkUuid, routerId);
2274 LOG.debug("clrRtsFromBgpAndDelFibTs : Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2276 //Remove custom FIB routes
2277 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2278 for (String extIp : externalIps) {
2279 clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, confTx);
2283 protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2284 final Uuid networkUuid, String extGwMacAddress,
2285 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2286 throws ExecutionException, InterruptedException {
2287 clearBgpRoutes(extIp, vpnName);
2288 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2292 protected void delFibTsAndReverseTraffic(final BigInteger dpnId, String routerName, long routerId, String extIp,
2293 String vpnName, Uuid extNetworkId, long tempLabel,
2294 String gwMacAddress, boolean switchOver,
2295 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2296 throws ExecutionException, InterruptedException {
2297 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2298 //String routerName = NatUtil.getRouterName(dataBroker,routerId);
2299 if (routerName == null) {
2300 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2303 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
2304 if (extNwProvType == null) {
2305 LOG.error("delFibTsAndReverseTraffic : External Network Provider Type Missing");
2308 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2309 * external network provided type is VxLAN
2311 if (extNwProvType == ProviderTypes.VXLAN) {
2312 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, gwMacAddress
2316 if (tempLabel < 0) {
2317 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2321 final long label = tempLabel;
2322 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2323 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
2324 LOG.debug("delFibTsAndReverseTraffic : Using extSubnetId as vpnName for FLAT/VLAN use-cases");
2325 Routers extRouter = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
2326 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp,
2329 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
2332 if (externalSubnet.isPresent()) {
2333 vpnName = externalSubnetId.getValue();
2336 final String externalVpn = vpnName;
2337 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(externalVpn)
2338 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label)
2339 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
2340 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2342 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2343 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2344 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2345 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2346 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2349 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2350 Futures.transformAsync(future, result -> {
2352 if (result.isSuccessful()) {
2353 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2354 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2355 .setVpnName(externalVpn).setIpPrefix(externalIp).build();
2356 return vpnService.removeVpnLabel(labelInput);
2359 String.format("RPC call to remove custom FIB entries on dpn %s for "
2360 + "prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
2362 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2364 }, MoreExecutors.directExecutor());
2366 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2369 public void onFailure(@NonNull Throwable error) {
2370 LOG.error("delFibTsAndReverseTraffic : Error in removing the label:{} or custom fib entries"
2371 + "got external ip {}", label, extIp, error);
2375 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
2376 if (result.isSuccessful()) {
2377 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2378 + "from VPN {}", externalIp, externalVpn);
2380 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2381 + " from VPN {}, {}", externalIp, externalVpn, result.getErrors());
2384 }, MoreExecutors.directExecutor());
2386 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2387 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2391 private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2392 final Uuid networkUuid, String extGwMacAddress, boolean switchOver,
2393 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2394 throws ExecutionException, InterruptedException {
2395 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2396 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2397 if (routerName == null) {
2398 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2401 //Get the external network provider type from networkId
2402 ProviderTypes extNwProvType = NatUtil.getProviderTypefromNetworkId(dataBroker, networkUuid);
2403 if (extNwProvType == null) {
2404 LOG.error("delFibTsAndReverseTraffic : Could not retrieve provider type for external network {} ",
2408 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2409 * external network provided type is VxLAN
2411 if (extNwProvType == ProviderTypes.VXLAN) {
2412 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, extGwMacAddress);
2415 //Get IPMaps from the DB for the router ID
2416 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
2417 if (dbIpMaps.isEmpty()) {
2418 LOG.error("delFibTsAndReverseTraffic : IPMaps not found for router {}", routerId);
2422 long tempLabel = NatConstants.INVALID_ID;
2423 for (IpMap dbIpMap : dbIpMaps) {
2424 String dbExternalIp = dbIpMap.getExternalIp();
2425 LOG.debug("delFibTsAndReverseTraffic : Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
2426 //Select the IPMap, whose external IP is the IP for which FIB is installed
2427 if (extIp.equals(dbExternalIp)) {
2428 tempLabel = dbIpMap.getLabel();
2429 LOG.debug("delFibTsAndReverseTraffic : Retrieved label {} for dbExternalIp {} with router id {}",
2430 tempLabel, dbExternalIp, routerId);
2434 if (tempLabel == NatConstants.INVALID_ID) {
2435 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2440 final long label = tempLabel;
2441 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2442 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
2443 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp)
2444 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).setServiceId(label).build();
2445 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2447 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2448 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2449 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2450 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2451 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2454 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2455 Futures.transformAsync(future, result -> {
2457 if (result.isSuccessful()) {
2458 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2459 .setVpnName(vpnName).setIpPrefix(externalIp).build();
2460 return vpnService.removeVpnLabel(labelInput);
2463 String.format("RPC call to remove custom FIB entries on dpn %s for "
2464 + "prefix %s Failed - %s",
2465 dpnId, externalIp, result.getErrors());
2467 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2469 }, MoreExecutors.directExecutor());
2471 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2474 public void onFailure(@NonNull Throwable error) {
2475 LOG.error("delFibTsAndReverseTraffic : Error in removing the label or custom fib entries", error);
2479 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
2480 if (result.isSuccessful()) {
2481 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2482 + "from VPN {}", externalIp, vpnName);
2484 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2485 + " from VPN {}, {}", externalIp, vpnName, result.getErrors());
2488 }, MoreExecutors.directExecutor());
2490 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2491 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2495 protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2496 List<String> externalIps, @Nullable String vpnName, String extGwMacAddress,
2497 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2498 //Withdraw the corresponding routes from the BGP.
2499 //Get the network ID using the router ID.
2500 LOG.debug("clearFibTsAndReverseTraffic : for externalIps {} with routerId {},"
2501 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2502 if (networkUuid == null) {
2503 LOG.error("clearFibTsAndReverseTraffic : networkId is null");
2507 if (externalIps == null || externalIps.isEmpty()) {
2508 LOG.error("clearFibTsAndReverseTraffic : externalIps is null");
2512 if (vpnName == null) {
2513 //Get the VPN Name using the network ID
2514 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2515 if (vpnName == null) {
2516 LOG.error("clearFibTsAndReverseTraffic : No VPN associated with ext nw {} for the router {}",
2517 networkUuid, routerId);
2521 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2523 //Remove custom FIB routes
2524 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2525 for (String extIp : externalIps) {
2526 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2531 protected void clearBgpRoutes(String externalIp, final String vpnName) {
2532 //Inform BGP about the route removal
2533 LOG.info("clearBgpRoutes : Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
2534 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
2535 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
2538 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId,
2539 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2540 LOG.info("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
2541 mdsalManager.removeFlow(writeFlowInvTx, dpnId,
2542 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), NwConstants.INTERNAL_TUNNEL_TABLE);
2543 LOG.debug("removeTunnelTableEntry : dpID {} : label : {} removed successfully", dpnId, serviceId);
2546 private void removeLFibTableEntry(BigInteger dpnId, long serviceId,
2547 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2548 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2549 LOG.debug("removeLFibTableEntry : with flow ref {}", flowRef);
2550 mdsalManager.removeFlow(writeFlowInvTx, dpnId, flowRef, NwConstants.L3_LFIB_TABLE);
2551 LOG.debug("removeLFibTableEntry : dpID : {} label : {} removed successfully", dpnId, serviceId);
2555 * router association to vpn.
2557 * @param routerName - Name of router
2558 * @param routerId - router id
2559 * @param bgpVpnName BGP VPN name
2561 public void changeLocalVpnIdToBgpVpnId(String routerName, long routerId, String bgpVpnName,
2562 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2563 LOG.debug("changeLocalVpnIdToBgpVpnId : Router associated to BGP VPN");
2564 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2565 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2567 LOG.debug("changeLocalVpnIdToBgpVpnId : BGP VPN ID value {} ", bgpVpnId);
2569 if (bgpVpnId != NatConstants.INVALID_ID) {
2570 LOG.debug("changeLocalVpnIdToBgpVpnId : Populate the router-id-name container with the "
2571 + "mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
2572 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
2573 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2574 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2575 getRoutersIdentifier(bgpVpnId), rtrs);
2577 // Get the allocated Primary NAPT Switch for this router
2578 LOG.debug("changeLocalVpnIdToBgpVpnId : Update the Router ID {} to the BGP VPN ID {} ",
2579 routerId, bgpVpnId);
2580 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, writeFlowInvTx);
2583 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2584 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true, writeFlowInvTx,
2591 * router disassociation from vpn.
2593 * @param routerName - Name of router
2594 * @param routerId - router id
2595 * @param bgpVpnName BGP VPN name
2597 public void changeBgpVpnIdToLocalVpnId(String routerName, long routerId, String bgpVpnName,
2598 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2599 LOG.debug("changeBgpVpnIdToLocalVpnId : Router dissociated from BGP VPN");
2600 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2601 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2602 LOG.debug("changeBgpVpnIdToLocalVpnId : BGP VPN ID value {} ", bgpVpnId);
2604 // Get the allocated Primary NAPT Switch for this router
2605 LOG.debug("changeBgpVpnIdToLocalVpnId : Router ID value {} ", routerId);
2607 LOG.debug("changeBgpVpnIdToLocalVpnId : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2608 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, NatConstants.INVALID_ID, writeFlowInvTx);
2611 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2612 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true,
2613 writeFlowInvTx, extNwProvType);
2617 boolean chkExtRtrAndSnatEnbl(Uuid routerUuid) {
2618 InstanceIdentifier<Routers> routerInstanceIndentifier =
2619 InstanceIdentifier.builder(ExtRouters.class)
2620 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
2622 Optional<Routers> routerData = SingleTransactionDataBroker
2623 .syncReadOptional(dataBroker,
2624 LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2625 return routerData.isPresent() && routerData.get().isEnableSnat();
2626 } catch (ReadFailedException e) {
2627 LOG.error("Failed to read data for router id {}", routerUuid, e);
2632 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2633 long routerId, boolean isSnatCfgd, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2635 long changedVpnId = bgpVpnId;
2636 String idType = "BGP VPN";
2637 if (bgpVpnId == NatConstants.INVALID_ID) {
2638 changedVpnId = routerId;
2642 List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2643 if (switches.isEmpty()) {
2644 LOG.error("installFlowsWithUpdatedVpnId : No switches found for router {}", routerName);
2647 for (BigInteger dpnId : switches) {
2648 // Update the BGP VPN ID in the SNAT miss entry to group
2649 if (!dpnId.equals(primarySwitchId)) {
2650 LOG.debug("installFlowsWithUpdatedVpnId : Install group in non NAPT switch {}", dpnId);
2651 List<BucketInfo> bucketInfoForNonNaptSwitches =
2652 getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName, routerId);
2653 long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
2654 NatUtil.getGroupIdKey(routerName));
2655 if (groupId != NatConstants.INVALID_ID) {
2657 installGroup(dpnId, routerName, groupId, bucketInfoForNonNaptSwitches);
2660 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2661 + "{} in the non NAPT switch {}", idType, changedVpnId, groupId, dpnId);
2662 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName,
2663 groupId, changedVpnId);
2664 mdsalManager.addFlow(confTx, flowEntity);
2666 LOG.error("installFlowsWithUpdatedVpnId: Unable to get groupId for router:{}", routerName);
2670 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2671 + "in the primary switch {}", idType, changedVpnId, primarySwitchId);
2672 FlowEntity flowEntity =
2673 buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2674 mdsalManager.addFlow(confTx, flowEntity);
2677 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Terminating Service table (table "
2678 + "ID 36) which forwards the packet to the table 46 in the Primary switch {}",
2679 idType, changedVpnId, primarySwitchId);
2680 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, routerId,
2681 changedVpnId, confTx, extNwProvType);
2684 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Outbound NAPT table (table ID 46) "
2685 + "which punts the packet to the controller in the Primary switch {}",
2686 idType, changedVpnId, primarySwitchId);
2687 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2690 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT PFIB TABLE which forwards the"
2691 + " outgoing packet to FIB Table in the Primary switch {}",
2692 idType, changedVpnId, primarySwitchId);
2693 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2696 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT flows for the Outbound NAPT "
2697 + "table (table ID 46) and the INBOUND NAPT table (table ID 44) in the Primary switch"
2698 + " {}", idType, changedVpnId, primarySwitchId);
2699 updateNaptFlowsWithVpnId(primarySwitchId, routerName, routerId, bgpVpnId);
2701 LOG.debug("installFlowsWithUpdatedVpnId : Installing SNAT PFIB flow in the primary switch {}",
2703 Long vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2704 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2705 if (vpnId != NatConstants.INVALID_ID) {
2706 installNaptPfibEntry(primarySwitchId, vpnId, confTx);
2712 public void updateNaptFlowsWithVpnId(BigInteger dpnId, String routerName, long routerId, long bgpVpnId) {
2713 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2714 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2715 if (ipPortMapping == null) {
2716 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the IpPortMapping");
2719 // Get the External Gateway MAC Address
2720 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
2721 if (extGwMacAddress != null) {
2722 LOG.debug("updateNaptFlowsWithVpnId : External Gateway MAC address {} found for External Router ID {}",
2723 extGwMacAddress, routerId);
2725 LOG.error("updateNaptFlowsWithVpnId : No External Gateway MAC address found for External Router ID {}",
2729 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2730 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2731 String ipPortInternal = ipPortMap.getIpPortInternal();
2732 String[] ipPortParts = ipPortInternal.split(":");
2733 if (ipPortParts.length != 2) {
2734 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the Internal IP and port");
2737 String internalIp = ipPortParts[0];
2738 String internalPort = ipPortParts[1];
2739 LOG.debug("updateNaptFlowsWithVpnId : Found Internal IP {} and Internal Port {}",
2740 internalIp, internalPort);
2741 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2742 NAPTEntryEvent.Protocol protocol;
2743 switch (protocolTypes) {
2745 protocol = NAPTEntryEvent.Protocol.TCP;
2748 protocol = NAPTEntryEvent.Protocol.UDP;
2751 protocol = NAPTEntryEvent.Protocol.TCP;
2753 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.parseInt(internalPort));
2754 SessionAddress externalAddress =
2755 naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2756 long internetVpnid = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2757 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
2758 routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
2759 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
2760 routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
2765 public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
2766 long changedVpnId) {
2768 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : called for dpId {}, routerName {} groupId {} "
2769 + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
2770 List<MatchInfo> matches = new ArrayList<>();
2771 matches.add(MatchEthernetType.IPV4);
2772 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2774 List<ActionInfo> actionsInfo = new ArrayList<>();
2775 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
2776 elanManager, idManager, changedVpnId, routerName);
2777 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
2778 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Setting the tunnel to the list of action infos {}",
2780 actionsInfo.add(new ActionGroup(groupId));
2781 List<InstructionInfo> instructions = new ArrayList<>();
2782 instructions.add(new InstructionApplyActions(actionsInfo));
2783 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2784 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2785 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2786 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2788 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Returning SNAT Flow Entity {}", flowEntity);
2792 public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
2793 long changedVpnId) {
2795 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : called for dpId {}, routerName {} "
2796 + "changed VPN ID {}", dpId, routerName, changedVpnId);
2797 List<MatchInfo> matches = new ArrayList<>();
2798 matches.add(MatchEthernetType.IPV4);
2799 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2801 List<InstructionInfo> instructions = new ArrayList<>();
2802 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2804 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2805 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2806 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2807 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2809 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : Returning SNAT Flow Entity {}", flowEntity);
2813 // TODO : Replace this with ITM Rpc once its available with full functionality
2814 protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
2815 long routerId, long changedVpnId, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2817 LOG.debug("installTerminatingServiceTblEntryWithUpdatedVpnId : called for switch {}, "
2818 + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2819 FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, routerId, changedVpnId,
2821 mdsalManager.addFlow(confTx, flowEntity);
2824 private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName,
2825 long routerIdLongVal, long changedVpnId, ProviderTypes extNwProvType) {
2826 LOG.debug("buildTsFlowEntityWithUpdatedVpnId : called for switch {}, routerName {}, BGP VPN ID {}",
2827 dpId, routerName, changedVpnId);
2828 List<MatchInfo> matches = new ArrayList<>();
2829 matches.add(MatchEthernetType.IPV4);
2831 BigInteger tunnelId = BigInteger.valueOf(changedVpnId);
2832 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2833 tunnelId = natOverVxlanUtil.getRouterVni(routerName, changedVpnId);
2835 matches.add(new MatchTunnelId(tunnelId));
2837 List<InstructionInfo> instructions = new ArrayList<>();
2838 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2839 MetaDataUtil.METADATA_MASK_VRFID));
2840 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2841 BigInteger routerId = BigInteger.valueOf(routerIdLongVal);
2842 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2843 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2844 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2845 NwConstants.COOKIE_TS_TABLE, matches, instructions);
2849 public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId,
2850 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2851 LOG.debug("createOutboundTblEntryWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2852 dpnId, routerId, changedVpnId);
2853 FlowEntity tcpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2854 NwConstants.IP_PROT_TCP);
2855 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing tcp flow {}", tcpFlowEntity);
2856 mdsalManager.addFlow(writeFlowInvTx, tcpFlowEntity);
2858 FlowEntity udpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2859 NwConstants.IP_PROT_UDP);
2860 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing udp flow {}", udpFlowEntity);
2861 mdsalManager.addFlow(writeFlowInvTx, udpFlowEntity);
2863 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, changedVpnId);
2864 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
2865 mdsalManager.addFlow(writeFlowInvTx, icmpDropFlow);
2868 protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId,
2869 long changedVpnId, int protocol) {
2870 LOG.debug("buildOutboundFlowEntityWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2871 dpId, routerId, changedVpnId);
2872 BigInteger cookie = getCookieOutboundFlow(routerId);
2873 List<MatchInfo> matches = new ArrayList<>();
2874 matches.add(MatchEthernetType.IPV4);
2875 matches.add(new MatchIpProtocol((short)protocol));
2876 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2878 List<InstructionInfo> instructions = new ArrayList<>();
2879 List<ActionInfo> actionsInfos = new ArrayList<>();
2880 actionsInfos.add(new ActionPuntToController());
2881 if (snatPuntTimeout != 0) {
2882 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
2884 instructions.add(new InstructionApplyActions(actionsInfos));
2886 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
2887 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
2888 flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
2889 LOG.debug("createOutboundTblEntryWithBgpVpn : returning flowEntity {}", flowEntity);
2893 public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId,
2894 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2895 LOG.debug("installNaptPfibEntryWithBgpVpn : called for dpnId {} and segmentId {} ,BGP VPN ID {}",
2896 dpnId, segmentId, changedVpnId);
2897 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2898 mdsalManager.addFlow(writeFlowInvTx, naptPfibFlowEntity);
2901 public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2903 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : called for dpId {}, "
2904 + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2905 List<MatchInfo> matches = new ArrayList<>();
2906 matches.add(MatchEthernetType.IPV4);
2907 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2909 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2910 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2911 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
2912 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2913 instructionInfo.add(new InstructionApplyActions(listActionInfo));
2915 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2916 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2917 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2918 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2919 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : Returning NaptPFib Flow Entity {}", flowEntity);
2924 protected ExternalRoutersListener getDataTreeChangeListener() {
2925 return ExternalRoutersListener.this;
2928 protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId,
2929 @Nullable TypedWriteTransaction<Configuration> writeFlowInvTx) {
2930 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
2932 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
2933 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
2934 if (subnetVpnId != -1) {
2935 LOG.debug("installNaptPfibEntriesForExternalSubnets : called for dpnId {} "
2936 + "and vpnId {}", dpnId, subnetVpnId);
2937 installNaptPfibEntry(dpnId, subnetVpnId, writeFlowInvTx);