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 // Allocated an id from VNI pool for the Router.
348 natOverVxlanUtil.getRouterVni(routerName, NatConstants.INVALID_ID);
349 primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
350 LOG.debug("getPrimaryNaptSwitch : Primary NAPT switch DPN ID {}", primarySwitchId);
352 return primarySwitchId;
355 protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId,
356 TypedWriteTransaction<Configuration> confTx) {
357 Long extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
358 if (extVpnId == NatConstants.INVALID_ID) {
359 LOG.error("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
362 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
363 if (externalIps.isEmpty()) {
364 LOG.error("installNaptPfibExternalOutputFlow - empty external Ips list for dpnId {} extVpnId {}",
368 for (String ip : externalIps) {
369 Uuid subnetId = getSubnetIdForFixedIp(ip);
370 if (subnetId != null) {
371 long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
372 if (subnetVpnId != NatConstants.INVALID_ID) {
373 extVpnId = subnetVpnId;
375 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
376 dpnId, extVpnId, subnetId);
377 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
378 if (postNaptFlowEntity != null) {
379 mdsalManager.addFlow(confTx, postNaptFlowEntity);
386 private Uuid getSubnetIdForFixedIp(String ip) {
388 IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
389 Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
390 return NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
392 LOG.error("getSubnetIdForFixedIp : ip is null");
396 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
397 LOG.debug("subnetRegisterMapping : Fetching values from extRouters model");
398 List<String> externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
400 int extIpCounter = externalIps.size();
401 LOG.debug("subnetRegisterMapping : counter values before looping counter {} and extIpCounter {}",
402 counter, extIpCounter);
403 @Nullable List<Uuid> subnetIds = routerEntry.getSubnetIds();
404 if (subnetIds == null) {
407 for (Uuid subnet : subnetIds) {
408 LOG.debug("subnetRegisterMapping : Looping internal subnets for subnet {}", subnet);
409 InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
410 .builder(Subnetmaps.class)
411 .child(Subnetmap.class, new SubnetmapKey(subnet))
413 Optional<Subnetmap> sn;
415 sn = SingleTransactionDataBroker.syncReadOptional(dataBroker,
416 LogicalDatastoreType.CONFIGURATION, subnetmapId);
417 } catch (ReadFailedException e) {
418 LOG.error("Failed to read SubnetMap for subnetmap Id {}", subnetmapId, e);
419 sn = Optional.absent();
421 if (sn.isPresent()) {
423 Subnetmap subnetmapEntry = sn.get();
424 String subnetString = subnetmapEntry.getSubnetIp();
425 String[] subnetSplit = subnetString.split("/");
426 String subnetIp = subnetSplit[0];
428 InetAddress address = InetAddress.getByName(subnetIp);
429 if (address instanceof Inet6Address) {
430 LOG.debug("subnetRegisterMapping : Skipping ipv6 subnet {} for the router {} with ipv6 address "
431 + "{} ", subnet, routerEntry.getRouterName(), address);
434 } catch (UnknownHostException e) {
435 LOG.error("subnetRegisterMapping : Invalid ip address {}", subnetIp, e);
438 String subnetPrefix = "0";
439 if (subnetSplit.length == 2) {
440 subnetPrefix = subnetSplit[1];
442 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
443 LOG.debug("subnetRegisterMapping : subnetAddr is {} and subnetPrefix is {}",
444 subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
446 LOG.debug("subnetRegisterMapping : counter values counter {} and extIpCounter {}",
447 counter, extIpCounter);
448 if (extIpCounter != 0) {
449 if (counter < extIpCounter) {
450 String[] ipSplit = externalIps.get(counter).split("/");
451 String externalIp = ipSplit[0];
452 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
453 if (ipSplit.length == 2) {
454 extPrefix = ipSplit[1];
456 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
457 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
458 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
459 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
460 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
461 + "externalIp {}. prefix {}", subnetIp, subnetPrefix, externalIp, extPrefix);
463 counter = 0; //Reset the counter which runs on externalIps for round-robbin effect
464 LOG.debug("subnetRegisterMapping : Counter on externalIps got reset");
465 String[] ipSplit = externalIps.get(counter).split("/");
466 String externalIp = ipSplit[0];
467 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
468 if (ipSplit.length == 2) {
469 extPrefix = ipSplit[1];
471 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
472 LOG.debug("subnetRegisterMapping : externalIp is {} and extPrefix is {}",
473 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
474 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
475 LOG.debug("subnetRegisterMapping : Called registerMapping for subnetIp {}, prefix {}, "
476 + "externalIp {}. prefix {}", subnetIp, subnetPrefix,
477 externalIp, extPrefix);
481 LOG.debug("subnetRegisterMapping : Counter on externalIps incremented to {}", counter);
483 LOG.warn("subnetRegisterMapping : No internal subnets present in extRouters Model");
488 private void addOrDelDefFibRouteToSNAT(String routerName, long routerId, long bgpVpnId,
489 Uuid bgpVpnUuid, boolean create, TypedReadWriteTransaction<Configuration> confTx)
490 throws ExecutionException, InterruptedException {
491 //Check if BGP VPN exists. If exists then invoke the new method.
492 if (bgpVpnId != NatConstants.INVALID_ID) {
493 if (bgpVpnUuid != null) {
494 String bgpVpnName = bgpVpnUuid.getValue();
495 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
496 bgpVpnId, bgpVpnName);
497 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
498 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
499 confTx.put(getRoutersIdentifier(bgpVpnId), rtrs, CREATE_MISSING_PARENTS);
502 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
504 removeDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
509 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
510 addOrDelDefaultFibRouteForSNAT(routerName, routerId, create, confTx);
513 private void addOrDelDefaultFibRouteForSNAT(String routerName, long routerId, boolean create,
514 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
515 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
516 if (switches.isEmpty()) {
517 LOG.info("addOrDelDefaultFibRouteForSNAT : No switches found for router {}", routerName);
520 if (routerId == NatConstants.INVALID_ID) {
521 LOG.error("addOrDelDefaultFibRouteForSNAT : Could not retrieve router Id for {} to program "
522 + "default NAT route in FIB", routerName);
525 for (BigInteger dpnId : switches) {
527 LOG.debug("addOrDelDefaultFibRouteForSNAT : installing default NAT route for router {} in dpn {} "
528 + "for the internal vpn-id {}", routerId, dpnId, routerId);
529 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
531 LOG.debug("addOrDelDefaultFibRouteForSNAT : removing default NAT route for router {} in dpn {} "
532 + "for the internal vpn-id {}", routerId, dpnId, routerId);
533 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
538 private void addDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
539 long bgpVpnId, TypedWriteTransaction<Configuration> confTx) {
540 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
541 if (dpnIds.isEmpty()) {
542 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
543 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
546 for (BigInteger dpnId : dpnIds) {
547 if (bgpVpnId != NatConstants.INVALID_ID) {
548 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
549 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
550 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
552 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
553 + "in dpn {} for the internal vpn", routerId, dpnId);
554 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
559 private void removeDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
560 long bgpVpnId, TypedReadWriteTransaction<Configuration> confTx)
561 throws ExecutionException, InterruptedException {
562 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
563 if (dpnIds.isEmpty()) {
564 LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
565 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
568 for (BigInteger dpnId : dpnIds) {
569 if (bgpVpnId != NatConstants.INVALID_ID) {
570 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
571 + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
572 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
574 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
575 + "in dpn {} for the internal vpn", routerId, dpnId);
576 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
581 protected void installOutboundMissEntry(String routerName, long routerId, BigInteger primarySwitchId,
582 TypedWriteTransaction<Configuration> confTx) {
583 LOG.debug("installOutboundMissEntry : Router ID from getVpnId {}", routerId);
584 if (routerId != NatConstants.INVALID_ID) {
585 LOG.debug("installOutboundMissEntry : Creating miss entry on primary {}, for router {}",
586 primarySwitchId, routerId);
587 createOutboundTblEntry(primarySwitchId, routerId, confTx);
589 LOG.error("installOutboundMissEntry : Unable to fetch Router Id for RouterName {}, failed to "
590 + "createAndInstallMissEntry", routerName);
594 public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID, int protocol) {
595 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
596 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + protocol;
599 private String getFlowRefNaptPreFib(BigInteger dpnId, short tableId, long vpnId) {
600 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
601 .FLOWID_SEPARATOR + vpnId;
604 public BigInteger getCookieOutboundFlow(long routerId) {
605 return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
606 BigInteger.valueOf(routerId));
609 private ActionLearn getLearnActionForPunt(int protocol, int hardTimeout, BigInteger cookie) {
612 int l4portFieldLen = NxmOfFieldType.NXM_OF_TCP_SRC.getFlowModHeaderLenInt();
614 if (protocol == NwConstants.IP_PROT_TCP) {
615 l4SrcPortField = NxmOfFieldType.NXM_OF_TCP_SRC.getType();
616 l4DstPortField = NxmOfFieldType.NXM_OF_TCP_DST.getType();
618 l4SrcPortField = NxmOfFieldType.NXM_OF_UDP_SRC.getType();
619 l4DstPortField = NxmOfFieldType.NXM_OF_UDP_DST.getType();
621 List<ActionLearn.FlowMod> flowMods = Arrays.asList(
622 new MatchFromValue(NwConstants.ETHTYPE_IPV4, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
623 NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
624 new MatchFromValue(protocol, NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
625 NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
626 new MatchFromField(NxmOfFieldType.NXM_OF_IP_SRC.getType(), NxmOfFieldType.NXM_OF_IP_SRC.getType(),
627 NxmOfFieldType.NXM_OF_IP_SRC.getFlowModHeaderLenInt()),
628 new MatchFromField(NxmOfFieldType.NXM_OF_IP_DST.getType(), NxmOfFieldType.NXM_OF_IP_DST.getType(),
629 NxmOfFieldType.NXM_OF_IP_DST.getFlowModHeaderLenInt()),
630 new MatchFromField(l4SrcPortField, l4SrcPortField, l4portFieldLen),
631 new MatchFromField(l4DstPortField, l4DstPortField, l4portFieldLen),
632 new MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
633 MetaDataUtil.METADATA_VPN_ID_OFFSET,
634 NxmOfFieldType.OXM_OF_METADATA.getType(), MetaDataUtil.METADATA_VPN_ID_OFFSET,
635 MetaDataUtil.METADATA_VPN_ID_BITLEN));
637 return new ActionLearn(0, hardTimeout, 7, cookie, 0,
638 NwConstants.OUTBOUND_NAPT_TABLE, 0, 0, flowMods);
641 private FlowEntity buildIcmpDropFlow(BigInteger dpnId, long routerId, long vpnId) {
642 List<MatchInfo> matches = new ArrayList<>();
643 matches.add(MatchEthernetType.IPV4);
644 matches.add(MatchIpProtocol.ICMP);
645 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
647 List<ActionInfo> actionInfos = new ArrayList<>();
648 actionInfos.add(new ActionDrop());
650 List<InstructionInfo> instructions = new ArrayList<>();
651 instructions.add(new InstructionApplyActions(actionInfos));
653 String flowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
654 NwConstants.IP_PROT_ICMP);
655 FlowEntity flow = MDSALUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
656 NwConstants.TABLE_MISS_PRIORITY, "icmp drop flow", 0, 0,
657 NwConstants.COOKIE_OUTBOUND_NAPT_TABLE, matches, instructions);
661 protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId, int protocol) {
662 LOG.debug("buildOutboundFlowEntity : called for dpId {} and routerId{}", dpId, routerId);
663 BigInteger cookie = getCookieOutboundFlow(routerId);
664 List<MatchInfo> matches = new ArrayList<>();
665 matches.add(MatchEthernetType.IPV4);
666 matches.add(new MatchIpProtocol((short)protocol));
667 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
669 List<InstructionInfo> instructions = new ArrayList<>();
670 List<ActionInfo> actionsInfos = new ArrayList<>();
671 actionsInfos.add(new ActionPuntToController());
672 if (snatPuntTimeout != 0) {
673 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
675 instructions.add(new InstructionApplyActions(actionsInfos));
677 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
678 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
680 cookie, matches, instructions);
681 LOG.debug("installOutboundMissEntry : returning flowEntity {}", flowEntity);
685 public void createOutboundTblEntry(BigInteger dpnId, long routerId, TypedWriteTransaction<Configuration> confTx) {
686 LOG.debug("createOutboundTblEntry : called for dpId {} and routerId {}", dpnId, routerId);
687 FlowEntity tcpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_TCP);
688 LOG.debug("createOutboundTblEntry : Installing tcp flow {}", tcpflowEntity);
689 mdsalManager.addFlow(confTx, tcpflowEntity);
691 FlowEntity udpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_UDP);
692 LOG.debug("createOutboundTblEntry : Installing udp flow {}", udpflowEntity);
693 mdsalManager.addFlow(confTx, udpflowEntity);
695 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, routerId);
696 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
697 mdsalManager.addFlow(confTx, icmpDropFlow);
701 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
702 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
703 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
705 Future<RpcResult<GetTunnelInterfaceNameOutput>> result =
706 itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
707 .setSourceDpid(srcDpId)
708 .setDestinationDpid(dstDpId)
709 .setTunnelType(tunType)
711 rpcResult = result.get();
712 if (!rpcResult.isSuccessful()) {
713 tunType = TunnelTypeGre.class;
714 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
715 .setSourceDpid(srcDpId)
716 .setDestinationDpid(dstDpId)
717 .setTunnelType(tunType)
719 rpcResult = result.get();
720 if (!rpcResult.isSuccessful()) {
721 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
722 rpcResult.getErrors());
724 return rpcResult.getResult().getInterfaceName();
726 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
727 rpcResult.getErrors());
729 return rpcResult.getResult().getInterfaceName();
731 } catch (InterruptedException | ExecutionException | NullPointerException e) {
732 LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
733 + "between {} and {}", srcDpId, dstDpId, e);
739 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName, long routerId,
740 TypedWriteTransaction<Configuration> confTx) {
742 LOG.debug("installSnatMissEntry : called for for the primary NAPT switch dpnId {} ", dpnId);
743 // Install miss entry pointing to group
744 FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName, routerId);
745 mdsalManager.addFlow(confTx, flowEntity);
748 protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo,
749 String routerName, long routerId) {
750 LOG.debug("installSnatMissEntry : called for dpnId {} with primaryBucket {} ",
751 dpnId, bucketInfo.get(0));
752 // Install the select group
753 long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
754 NatUtil.getGroupIdKey(routerName));
755 if (groupId == NatConstants.INVALID_ID) {
756 LOG.error("installSnatMissEntry: Unable to obtain group ID for Key: {}", routerName);
759 GroupEntity groupEntity =
760 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
761 LOG.debug("installSnatMissEntry : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
762 mdsalManager.syncInstallGroup(groupEntity);
763 // Install miss entry pointing to group
764 FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, routerId, groupId);
765 if (flowEntity == null) {
766 LOG.error("installSnatMissEntry : Flow entity received as NULL. "
767 + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
768 + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
771 mdsalManager.installFlow(flowEntity);
774 void installGroup(BigInteger dpnId, String routerName, long groupId, List<BucketInfo> bucketInfo) {
775 GroupEntity groupEntity =
776 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
777 LOG.debug("installGroup : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
778 mdsalManager.syncInstallGroup(groupEntity);
781 private FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long routerId, long groupId) {
782 LOG.debug("buildSnatFlowEntity : called for dpId {}, routerName {} and groupId {}",
783 dpId, routerName, groupId);
784 List<MatchInfo> matches = new ArrayList<>();
785 matches.add(MatchEthernetType.IPV4);
786 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
788 List<ActionInfo> actionsInfo = new ArrayList<>();
789 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager, idManager,
790 routerId, routerName);
791 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
792 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
793 actionsInfo.add(new ActionGroup(groupId));
794 List<InstructionInfo> instructions = new ArrayList<>();
795 instructions.add(new InstructionApplyActions(actionsInfo));
796 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
797 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
798 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
799 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
801 LOG.debug("buildSnatFlowEntity : Returning SNAT Flow Entity {}", flowEntity);
805 private FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName, long routerId) {
807 LOG.debug("buildSnatFlowEntityForPrmrySwtch : called for primary NAPT switch dpId {}, routerName {}", dpId,
809 List<MatchInfo> matches = new ArrayList<>();
810 matches.add(MatchEthernetType.IPV4);
811 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
813 List<InstructionInfo> instructions = new ArrayList<>();
814 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
816 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
817 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
818 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
819 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
821 LOG.debug("buildSnatFlowEntityForPrmrySwtch : Returning SNAT Flow Entity {}", flowEntity);
825 // TODO : Replace this with ITM Rpc once its available with full functionality
826 protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName, long routerId,
827 TypedWriteTransaction<Configuration> confTx) {
829 LOG.debug("installTerminatingServiceTblEntry : for switch {}, routerName {}",
831 FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName, routerId);
832 if (flowEntity == null) {
833 LOG.error("installTerminatingServiceTblEntry : Flow entity received as NULL. "
834 + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
835 + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
839 mdsalManager.addFlow(confTx, flowEntity);
843 private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName, long routerId) {
844 List<MatchInfo> matches = new ArrayList<>();
845 matches.add(MatchEthernetType.IPV4);
846 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
847 idManager, routerId, routerName);
848 matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
849 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
850 List<InstructionInfo> instructions = new ArrayList<>();
851 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
852 MetaDataUtil.METADATA_MASK_VRFID));
853 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
854 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
855 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
860 public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
861 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
862 .FLOWID_SEPARATOR + routerID;
865 public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
866 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
867 .FLOWID_SEPARATOR + routerID;
870 protected void handleSwitches(BigInteger dpnId, String routerName, long routerId, BigInteger primarySwitchId) {
871 LOG.debug("handleSwitches : Installing SNAT miss entry in switch {}", dpnId);
872 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
873 String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
874 List<BucketInfo> listBucketInfo = new ArrayList<>();
876 if (ifNamePrimary != null) {
877 LOG.debug("handleSwitches : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
878 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
879 interfaceManager, ifNamePrimary, routerId, true);
880 if (listActionInfoPrimary.isEmpty()) {
881 LOG.error("handleSwitches : Unable to retrieve output actions on Non-NAPT switch {} for router {}"
882 + " towards Napt-switch {} via tunnel interface {}", dpnId, routerName, primarySwitchId,
886 LOG.error("handleSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} from "
887 + "Non-Napt switch {} for router {}", primarySwitchId, dpnId, routerName);
889 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
891 listBucketInfo.add(0, bucketPrimary);
892 installSnatMissEntry(dpnId, listBucketInfo, routerName, routerId);
895 List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
896 BigInteger primarySwitchId, String routerName, long routerId) {
897 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
898 String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
899 List<BucketInfo> listBucketInfo = new ArrayList<>();
901 if (ifNamePrimary != null) {
902 LOG.debug("getBucketInfoForNonNaptSwitches : On Non- Napt switch , Primary Tunnel interface is {}",
904 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
905 interfaceManager, ifNamePrimary, routerId, true);
906 if (listActionInfoPrimary.isEmpty()) {
907 LOG.error("getBucketInfoForNonNaptSwitches : Unable to retrieve output actions on Non-NAPT switch {} "
908 + "for router {} towards Napt-switch {} via tunnel interface {}",
909 nonNaptSwitchId, routerName, primarySwitchId, ifNamePrimary);
912 LOG.error("getBucketInfoForNonNaptSwitches : Unable to obtain primary tunnel interface to Napt-Switch {} "
913 + "from Non-Napt switch {} for router {}", primarySwitchId, nonNaptSwitchId, routerName);
915 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
917 listBucketInfo.add(0, bucketPrimary);
918 return listBucketInfo;
921 protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName, long routerId,
922 TypedWriteTransaction<Configuration> confTx) {
925 * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
928 LOG.debug("handlePrimaryNaptSwitch : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
931 List<BucketInfo> listBucketInfo = new ArrayList<>();
932 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
933 listActionInfoPrimary.add(new ActionNxResubmit(NatConstants.TERMINATING_SERVICE_TABLE));
934 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
935 listBucketInfo.add(0, bucketPrimary);
938 installSnatMissEntryForPrimrySwch(dpnId, routerName, routerId, confTx);
939 installTerminatingServiceTblEntry(dpnId, routerName, routerId, confTx);
940 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
941 installNaptPfibEntry(dpnId, routerId, confTx);
942 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
943 if (networkId != null) {
944 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
945 if (vpnUuid != null) {
946 long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
947 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
948 installNaptPfibEntriesForExternalSubnets(routerName, dpnId, null);
949 //Install the NAPT PFIB TABLE which forwards outgoing packet to FIB Table matching on the VPN ID.
950 if (vpnId != NatConstants.INVALID_ID) {
951 installNaptPfibEntry(dpnId, vpnId, null);
953 return Collections.emptyList();
956 LOG.warn("handlePrimaryNaptSwitch : External Vpn ID missing for Ext-Network : {}", networkId);
959 LOG.warn("handlePrimaryNaptSwitch : External Network not available for router : {}", routerName);
963 public void installNaptPfibEntry(BigInteger dpnId, long segmentId,
964 @Nullable TypedWriteTransaction<Configuration> confTx) {
965 LOG.debug("installNaptPfibEntry : called for dpnId {} and segmentId {} ", dpnId, segmentId);
966 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
967 if (confTx != null) {
968 mdsalManager.addFlow(confTx, naptPfibFlowEntity);
970 mdsalManager.installFlow(naptPfibFlowEntity);
974 public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
976 LOG.debug("buildNaptPfibFlowEntity : called for dpId {}, segmentId {}", dpId, segmentId);
977 List<MatchInfo> matches = new ArrayList<>();
978 matches.add(MatchEthernetType.IPV4);
979 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
981 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
982 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
983 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
984 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
985 instructionInfo.add(new InstructionApplyActions(listActionInfo));
987 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
988 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
989 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
990 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
991 LOG.debug("buildNaptPfibFlowEntity : Returning NaptPFib Flow Entity {}", flowEntity);
995 public void handleSnatReverseTraffic(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, Routers router,
996 long routerId, String routerName, String externalIp) {
997 LOG.debug("handleSnatReverseTraffic : entry for DPN ID {}, routerId {}, externalIp: {}",
998 dpnId, routerId, externalIp);
999 Uuid networkId = router.getNetworkId();
1000 if (networkId == null) {
1001 LOG.error("handleSnatReverseTraffic : networkId is null for the router ID {}", routerId);
1004 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1005 if (vpnName == null) {
1006 LOG.error("handleSnatReverseTraffic : No VPN associated with ext nw {} to handle add external ip "
1007 + "configuration {} in router {}", networkId, externalIp, routerId);
1010 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1011 externalIp, networkId, router, confTx);
1012 LOG.debug("handleSnatReverseTraffic : exit for DPN ID {}, routerId {}, externalIp : {}",
1013 dpnId, routerId, externalIp);
1016 public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
1017 final long routerId, final String routerName, final String externalIp,
1018 final Uuid extNetworkId, @Nullable final Routers router,
1019 final TypedWriteTransaction<Configuration> confTx) {
1020 LOG.debug("advToBgpAndInstallFibAndTsFlows : entry for DPN ID {}, tableId {}, vpnname {} "
1021 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
1022 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
1023 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1024 if (rd == null || rd.isEmpty()) {
1025 LOG.error("advToBgpAndInstallFibAndTsFlows : Unable to get RD for VPN Name {}", vpnName);
1028 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
1029 if (extNwProvType == null) {
1030 LOG.error("advToBgpAndInstallFibAndTsFlows : External Network Provider Type missing");
1033 if (extNwProvType == ProviderTypes.VXLAN) {
1034 evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
1035 nextHopIp, routerId, routerName, extNetworkId, confTx);
1038 //Generate VPN label for the external IP
1039 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
1040 .setIpPrefix(externalIp).build();
1041 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
1043 //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
1044 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
1045 if (result.isSuccessful()) {
1046 LOG.debug("advToBgpAndInstallFibAndTsFlows : inside apply with result success");
1047 GenerateVpnLabelOutput output = result.getResult();
1048 final long label = output.getLabel();
1050 int externalIpInDsFlag = 0;
1051 //Get IPMaps from the DB for the router ID
1052 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
1053 for (IpMap dbIpMap : dbIpMaps) {
1054 String dbExternalIp = dbIpMap.getExternalIp();
1055 //Select the IPMap, whose external IP is the IP for which FIB is installed
1056 if (dbExternalIp.contains(externalIp)) {
1057 String dbInternalIp = dbIpMap.getInternalIp();
1058 IpMapKey dbIpMapKey = dbIpMap.key();
1059 LOG.debug("advToBgpAndInstallFibAndTsFlows : Setting label {} for internalIp {} "
1060 + "and externalIp {}", label, dbInternalIp, externalIp);
1061 IpMap newIpm = new IpMapBuilder().withKey(dbIpMapKey).setInternalIp(dbInternalIp)
1062 .setExternalIp(dbExternalIp).setLabel(label).build();
1063 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1064 naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
1065 externalIpInDsFlag++;
1068 if (externalIpInDsFlag <= 0) {
1069 LOG.debug("advToBgpAndInstallFibAndTsFlows : External Ip {} not found in DS, "
1070 + "Failed to update label {} for routerId {} in DS",
1071 externalIp, label, routerId);
1072 String errMsg = String.format("Failed to update label %s due to external Ip %s not"
1073 + " found in DS for router %s", label, externalIp, routerId);
1074 return Futures.immediateFailedFuture(new Exception(errMsg));
1078 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1079 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni).longValue();
1081 Routers extRouter = router != null ? router :
1082 NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1083 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
1084 externalIp, nextHopIp, extRouter.getNetworkId().getValue(), null, label, l3vni,
1085 RouteOrigin.STATIC, dpnId);
1087 //Install custom FIB routes
1088 List<Instruction> tunnelTableCustomInstructions = new ArrayList<>();
1089 tunnelTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
1090 makeTunnelTableEntry(dpnId, label, l3vni, tunnelTableCustomInstructions, confTx,
1092 makeLFibTableEntry(dpnId, label, tableId, confTx);
1094 //Install custom FIB routes - FIB table.
1095 List<Instruction> fibTableCustomInstructions = createFibTableCustomInstructions(tableId,
1096 routerName, externalIp);
1097 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1098 //Install the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
1099 NatUtil.makePreDnatToSnatTableEntry(mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, confTx);
1101 String externalVpn = vpnName;
1102 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp, extRouter);
1103 if (extNwProvType == ProviderTypes.VLAN || extNwProvType == ProviderTypes.FLAT) {
1104 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
1106 if (externalSubnet.isPresent()) {
1107 externalVpn = externalSubnetId.getValue();
1110 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1111 CreateFibEntryInput input = new CreateFibEntryInputBuilder()
1112 .setVpnName(externalVpn)
1113 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
1114 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
1115 .setInstruction(fibTableCustomInstructions).build();
1116 return fibService.createFibEntry(input);
1118 LOG.error("advToBgpAndInstallFibAndTsFlows : inside apply with result failed");
1119 String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
1120 externalIp, vpnName, result.getErrors());
1121 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1123 }, MoreExecutors.directExecutor());
1125 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
1128 public void onFailure(@NonNull Throwable error) {
1129 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in generate label or fib install process", error);
1133 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
1134 if (result.isSuccessful()) {
1135 LOG.info("advToBgpAndInstallFibAndTsFlows : Successfully installed custom FIB routes for prefix {}",
1138 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in rpc call to create custom Fib entries "
1139 + "for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
1142 }, MoreExecutors.directExecutor());
1145 private List<Instruction> createFibTableCustomInstructions(short tableId, String routerName,
1146 String externalIp) {
1147 List<Instruction> fibTableCustomInstructions = new ArrayList<>();
1148 Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1149 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
1150 externalIp, router);
1151 int instructionIndex = 0;
1152 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
1153 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
1154 fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
1155 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
1159 fibTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(instructionIndex));
1160 return fibTableCustomInstructions;
1163 private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId,
1164 TypedWriteTransaction<Configuration> confTx) {
1165 List<MatchInfo> matches = new ArrayList<>();
1166 matches.add(MatchEthernetType.MPLS_UNICAST);
1167 matches.add(new MatchMplsLabel(serviceId));
1169 List<Instruction> instructions = new ArrayList<>();
1170 List<ActionInfo> actionsInfos = new ArrayList<>();
1171 //NAT is required for IPv4 only. Hence always etherType will be IPv4
1172 actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
1173 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
1174 instructions.add(writeInstruction);
1175 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
1177 // Install the flow entry in L3_LFIB_TABLE
1178 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1180 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1182 COOKIE_VM_LFIB_TABLE, matches, instructions);
1184 mdsalManager.addFlow(confTx, dpId, flowEntity);
1186 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
1189 private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, long l3Vni,
1190 List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx,
1191 ProviderTypes extNwProvType) {
1193 List<MatchInfo> mkMatches = new ArrayList<>();
1195 LOG.debug("makeTunnelTableEntry : DpnId = {} and serviceId = {} and actions = {}",
1196 dpnId, serviceId, customInstructions);
1198 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1199 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
1201 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
1204 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1205 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
1206 NatConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY,
1207 String.format("%s:%d", "TST Flow Entry ", serviceId), 0, 0,
1208 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1210 mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
1213 protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1214 return InstanceIdentifier.builder(RouterIdName.class).child(RouterIds.class,
1215 new RouterIdsKey(routerId)).build();
1218 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1219 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
1220 .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
1224 protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1225 String routerName = original.getRouterName();
1226 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1227 if (routerId == NatConstants.INVALID_ID) {
1228 LOG.error("update : external router event - Invalid routerId for routerName {}", routerName);
1231 // Check if its update on SNAT flag
1232 boolean originalSNATEnabled = original.isEnableSnat();
1233 boolean updatedSNATEnabled = update.isEnableSnat();
1234 LOG.debug("update :called with originalFlag and updatedFlag for SNAT enabled "
1235 + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
1236 /* Get Primary Napt Switch for existing router from "router-to-napt-switch" DS.
1237 * if dpnId value is null or zero then go for electing new Napt switch for existing router.
1239 long bgpVpnId = NatConstants.INVALID_ID;
1240 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1241 if (bgpVpnUuid != null) {
1242 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1244 BigInteger dpnId = getPrimaryNaptSwitch(routerName);
1245 final long finalBgpVpnId = bgpVpnId;
1246 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + update.key(), () -> {
1247 List<ListenableFuture<Void>> futures = new ArrayList<>();
1248 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeFlowInvTx -> {
1249 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, removeFlowInvTx -> {
1250 Uuid networkId = original.getNetworkId();
1251 if (originalSNATEnabled != updatedSNATEnabled) {
1252 if (originalSNATEnabled) {
1253 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1254 // Router has no interface attached
1257 //SNAT disabled for the router
1258 Uuid networkUuid = original.getNetworkId();
1259 LOG.info("update : SNAT disabled for Router {}", routerName);
1260 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1261 handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId, routerId,
1264 LOG.info("update : SNAT enabled for Router {}", original.getRouterName());
1265 addOrDelDefFibRouteToSNAT(routerName, routerId, finalBgpVpnId, bgpVpnUuid,
1266 true, writeFlowInvTx);
1267 handleEnableSnat(update, routerId, dpnId, finalBgpVpnId, writeFlowInvTx);
1270 if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1271 NatUtil.installRouterGwFlows(txRunner, vpnManager, original, dpnId, NwConstants.DEL_FLOW);
1272 NatUtil.installRouterGwFlows(txRunner, vpnManager, update, dpnId, NwConstants.ADD_FLOW);
1275 if (updatedSNATEnabled != originalSNATEnabled) {
1276 LOG.info("update : no need to process external/subnet changes as it's will taken care in "
1277 + "handleDisableSnat/handleEnableSnat");
1280 //Check if the Update is on External IPs
1281 LOG.debug("update : Checking if this is update on External IPs");
1282 List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
1283 List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
1285 //Check if the External IPs are removed during the update.
1286 Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
1287 removedExternalIps.removeAll(updatedExternalIps);
1288 if (removedExternalIps.size() > 0) {
1289 LOG.debug("update : Start processing of the External IPs removal during the update "
1291 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
1292 removedExternalIps, original.getExtGwMacAddress(),
1295 for (String removedExternalIp : removedExternalIps) {
1297 1) Remove the mappings in the IntExt IP model which has external IP.
1298 2) Remove the external IP in the ExternalCounter model.
1299 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the
1300 least loaded external IP.
1301 Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1302 4) Increase the count of the allocated external IP by one.
1303 5) Advertise to the BGP if external IP is allocated for the first time for the router
1304 i.e. the route for the external IP is absent.
1305 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for
1306 the removed external IPs and also from the model.
1307 7) Advertise to the BGP for removing the route for the removed external IPs.
1310 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1311 String externalIp = externalIpParts[0];
1312 String externalIpPrefix = externalIpParts[1];
1313 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1315 LOG.debug("update : Clear the routes from the BGP and remove the FIB and TS "
1316 + "entries for removed external IP {}", externalIpAddrStr);
1317 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1318 String vpnName = "";
1319 if (vpnUuId != null) {
1320 vpnName = vpnUuId.getValue();
1322 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName, networkId,
1323 update.getExtGwMacAddress(), removeFlowInvTx);
1325 LOG.debug("update : Remove the mappings in the IntExtIP model which has external IP.");
1326 //Get the internal IPs which are associated to the removed external IPs
1327 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1328 List<String> removedInternalIps = new ArrayList<>();
1329 for (IpMap ipMap : ipMaps) {
1330 if (ipMap.getExternalIp().equals(externalIpAddrStr)) {
1331 removedInternalIps.add(ipMap.getInternalIp());
1335 LOG.debug("update : Remove the mappings of the internal IPs from the IntExtIP model.");
1336 for (String removedInternalIp : removedInternalIps) {
1337 LOG.debug("update : Remove the IP mapping of the internal IP {} for the "
1338 + "router ID {} from the IntExtIP model",
1339 removedInternalIp, routerId);
1340 naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1343 LOG.debug("update : Remove the count mapping of the external IP {} for the "
1344 + "router ID {} from the ExternalIpsCounter model.",
1345 externalIpAddrStr, routerId);
1346 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1348 LOG.debug("update : Allocate the least loaded external IPs to the subnets "
1349 + "whose external IPs were removed.");
1350 for (String removedInternalIp : removedInternalIps) {
1351 allocateExternalIp(dpnId, update, routerId, routerName, networkId,
1352 removedInternalIp, writeFlowInvTx);
1354 LOG.debug("update : Remove the NAPT translation entries from "
1355 + "Inbound and Outbound NAPT tables for the removed external IPs.");
1356 //Get the internalIP and internal Port which were associated to the removed external IP.
1357 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1358 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier
1359 .builder(IntextIpPortMap.class)
1360 .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1361 Optional<IpPortMapping> ipPortMapping;
1363 ipPortMapping = SingleTransactionDataBroker
1364 .syncReadOptional(dataBroker,
1365 LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1366 } catch (ReadFailedException e) {
1367 LOG.error("Failed to read ipPortMapping for router id {}", routerId, e);
1368 ipPortMapping = Optional.absent();
1371 if (ipPortMapping.isPresent()) {
1372 for (IntextIpProtocolType intextIpProtocolType :
1373 ipPortMapping.get().nonnullIntextIpProtocolType()) {
1374 ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1375 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
1376 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1377 if (ipPortExternal.getIpAddress().equals(externalIp)) {
1378 List<String> removedInternalIpPorts =
1379 protoTypesIntIpPortsMap.get(protoType);
1380 if (removedInternalIpPorts != null) {
1381 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1382 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1384 removedInternalIpPorts = new ArrayList<>();
1385 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1386 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1393 //Remove the IP port map from the intext-ip-port-map model, which were containing
1394 // the removed external IP.
1395 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts =
1396 protoTypesIntIpPortsMap.entrySet();
1397 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1398 for (Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts) {
1399 ProtocolTypes protocolType = (ProtocolTypes) protoTypesIntIpPort.getKey();
1400 List<String> removedInternalIpPorts = (List<String>) protoTypesIntIpPort.getValue();
1401 for (String removedInternalIpPort : removedInternalIpPorts) {
1402 // Remove the IP port map from the intext-ip-port-map model,
1403 // which were containing the removed external IP
1404 naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort,
1406 //Remove the IP port incomint packer map.
1407 naptPacketInHandler.removeIncomingPacketMap(
1408 routerId + NatConstants.COLON_SEPARATOR + removedInternalIpPort);
1409 String[] removedInternalIpPortParts = removedInternalIpPort
1410 .split(NatConstants.COLON_SEPARATOR);
1411 if (removedInternalIpPortParts.length == 2) {
1412 String removedInternalIp = removedInternalIpPortParts[0];
1413 String removedInternalPort = removedInternalIpPortParts[1];
1414 List<String> removedInternalPortsList =
1415 internalIpPortMap.get(removedInternalPort);
1416 if (removedInternalPortsList != null) {
1417 removedInternalPortsList.add(removedInternalPort);
1418 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1419 naptPacketInHandler.removeIncomingPacketMap(routerId
1420 + NatConstants.COLON_SEPARATOR + removedInternalIp
1421 + NatConstants.COLON_SEPARATOR + removedInternalPort);
1422 //Remove the NAPT translation entries from Outbound NAPT table
1423 naptEventHandler.removeNatFlows(dpnId,
1424 NwConstants.OUTBOUND_NAPT_TABLE,
1425 routerId, removedInternalIp,
1426 Integer.parseInt(removedInternalPort),
1427 protocolType.getName());
1428 naptEventHandler.removeNatFlows(dpnId,
1429 NwConstants.INBOUND_NAPT_TABLE,
1430 routerId, removedInternalIp,
1431 Integer.parseInt(removedInternalPort),
1432 protocolType.getName());
1434 removedInternalPortsList = new ArrayList<>();
1435 removedInternalPortsList.add(removedInternalPort);
1436 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1437 naptPacketInHandler.removeIncomingPacketMap(routerId
1438 + NatConstants.COLON_SEPARATOR + removedInternalIp
1439 + NatConstants.COLON_SEPARATOR + removedInternalPort);
1440 //Remove the NAPT translation entries from Outbound NAPT table
1441 naptEventHandler.removeNatFlows(dpnId,
1442 NwConstants.OUTBOUND_NAPT_TABLE,
1443 routerId, removedInternalIp,
1444 Integer.parseInt(removedInternalPort),
1445 protocolType.getName());
1446 naptEventHandler.removeNatFlows(dpnId,
1447 NwConstants.INBOUND_NAPT_TABLE, routerId, removedInternalIp,
1448 Integer.parseInt(removedInternalPort),
1449 protocolType.getName());
1455 // Delete the entry from SnatIntIpPortMap DS
1456 Set<String> internalIps = internalIpPortMap.keySet();
1457 for (String internalIp : internalIps) {
1458 LOG.debug("update : Removing IpPort having the internal IP {} from the "
1459 + "model SnatIntIpPortMap", internalIp);
1460 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1463 naptManager.removeNaptPortPool(externalIp);
1466 "update : End processing of the External IPs removal during the update operation");
1469 //Check if the External IPs are added during the update.
1470 Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
1471 addedExternalIps.removeAll(originalExternalIps);
1472 if (addedExternalIps.size() != 0) {
1473 LOG.debug("update : Start processing of the External IPs addition during the update "
1475 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
1476 update.getExtGwMacAddress(), dpnId,
1477 update.getNetworkId());
1479 for (String addedExternalIp : addedExternalIps) {
1481 1) Do nothing in the IntExtIp model.
1482 2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1484 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1485 String externalIp = externalIpParts[0];
1486 String externalIpPrefix = externalIpParts[1];
1487 String externalpStr = externalIp + "/" + externalIpPrefix;
1488 LOG.debug("update : Initialise the count mapping of the external IP {} for the "
1489 + "router ID {} in the ExternalIpsCounter model.",
1490 externalpStr, routerId);
1491 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1492 subnetRegisterMapping(update, routerId);
1493 LOG.info("update : Installing fib flow fo newly added Ips");
1494 handleSnatReverseTraffic(writeFlowInvTx, dpnId, update, routerId, routerName, externalpStr);
1497 "update : End processing of the External IPs addition during the update operation");
1500 //Check if its Update on subnets
1501 LOG.debug("update : Checking if this is update on subnets");
1502 List<Uuid> originalSubnetIds = original.getSubnetIds();
1503 List<Uuid> updatedSubnetIds = update.getSubnetIds();
1504 Set<Uuid> addedSubnetIds =
1505 updatedSubnetIds != null ? new HashSet<>(updatedSubnetIds) : new HashSet<>();
1506 if (originalSubnetIds != null) {
1507 addedSubnetIds.removeAll(originalSubnetIds);
1510 //Check if the Subnet IDs are added during the update.
1511 if (addedSubnetIds.size() != 0) {
1513 "update : Start processing of the Subnet IDs addition during the update operation");
1514 for (Uuid addedSubnetId : addedSubnetIds) {
1516 1) Select the least loaded external IP for the subnet and store the mapping of the
1517 subnet IP and the external IP in the IntExtIp model.
1518 2) Increase the count of the selected external IP by one.
1519 3) Advertise to the BGP if external IP is allocated for the first time for the
1520 router i.e. the route for the external IP is absent.
1522 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1523 if (subnetIp != null) {
1524 allocateExternalIp(dpnId, update, routerId, routerName, networkId, subnetIp,
1528 LOG.debug("update : End processing of the Subnet IDs addition during the update operation");
1531 //Check if the Subnet IDs are removed during the update.
1532 Set<Uuid> removedSubnetIds = new HashSet<>(originalSubnetIds);
1533 removedSubnetIds.removeAll(updatedSubnetIds);
1534 if (removedSubnetIds.size() != 0) {
1536 "update : Start processing of the Subnet IDs removal during the update operation");
1537 for (Uuid removedSubnetId : removedSubnetIds) {
1538 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1539 if (subnetAddr != null) {
1541 1) Remove the subnet IP and the external IP in the IntExtIp map
1542 2) Decrease the count of the coresponding external IP by one.
1543 3) Advertise to the BGP for removing the routes of the corresponding external
1544 IP if its not allocated to any other internal IP.
1547 String externalIp = naptManager.getExternalIpAllocatedForSubnet(routerId,
1548 subnetAddr[0] + "/" + subnetAddr[1]);
1549 if (externalIp == null) {
1550 LOG.error("update : No mapping found for router ID {} and internal IP {}",
1551 routerId, subnetAddr[0]);
1555 naptManager.updateCounter(routerId, externalIp, false);
1556 // Traverse entire model of external-ip counter whether external ip is not
1557 // used by any other internal ip in any router
1558 if (!isExternalIpAllocated(externalIp)) {
1559 LOG.debug("update : external ip is not allocated to any other "
1560 + "internal IP so proceeding to remove routes");
1561 clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId,
1562 Collections.singleton(externalIp), null, update.getExtGwMacAddress(),
1564 LOG.debug("update : Successfully removed fib entries in switch {} for "
1565 + "router {} with networkId {} and externalIp {}",
1566 dpnId, routerId, networkId, externalIp);
1569 LOG.debug("update : Remove the IP mapping for the router ID {} and "
1570 + "internal IP {} external IP {}", routerId, subnetAddr[0], externalIp);
1571 naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1574 LOG.debug("update : End processing of the Subnet IDs removal during the update operation");
1579 }, NatConstants.NAT_DJC_MAX_RETRIES);
1582 private boolean isExternalIpAllocated(String externalIp) {
1583 InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1584 Optional<ExternalIpsCounter> externalCountersData;
1586 externalCountersData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1587 LogicalDatastoreType.OPERATIONAL, id);
1588 } catch (ReadFailedException e) {
1589 LOG.error("Failed to read external counters data for ExternalIp {}", externalIp, e);
1590 externalCountersData = Optional.absent();
1592 if (externalCountersData.isPresent()) {
1593 ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1594 for (ExternalCounters ext : externalIpsCounters.nonnullExternalCounters()) {
1595 for (ExternalIpCounter externalIpCount : ext.nonnullExternalIpCounter()) {
1596 if (externalIpCount.getExternalIp().equals(externalIp)) {
1597 if (externalIpCount.getCounter() != 0) {
1608 private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
1609 Uuid networkId, String subnetIp, TypedWriteTransaction<Configuration> writeFlowInvTx) {
1610 String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1612 InetAddress address = InetAddress.getByName(subnetIpParts[0]);
1613 if (address instanceof Inet6Address) {
1614 LOG.debug("allocateExternalIp : Skipping ipv6 address {} for the router {}.", address, routerName);
1617 } catch (UnknownHostException e) {
1618 LOG.error("allocateExternalIp : Invalid ip address {}", subnetIpParts[0], e);
1621 String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1622 if (leastLoadedExtIpAddr != null) {
1623 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1624 String leastLoadedExtIp = externalIpParts[0];
1625 String leastLoadedExtIpPrefix = externalIpParts[1];
1626 IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1627 subnetIp = subnetIpParts[0];
1628 String subnetIpPrefix = subnetIpParts[1];
1629 IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1630 LOG.debug("allocateExternalIp : Add the IP mapping for the router ID {} and internal "
1631 + "IP {} and prefix {} -> external IP {} and prefix {}",
1632 routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1633 naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1636 // Check if external IP is already assigned a route. (i.e. External IP is previously
1637 // allocated to any of the subnets)
1638 // If external IP is already assigned a route, (, do not re-advertise to the BGP
1639 String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1640 Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1641 if (label != null) {
1643 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1644 IpMapKey ipMapKey = new IpMapKey(internalIp);
1645 LOG.debug("allocateExternalIp : Setting label {} for internalIp {} and externalIp {}",
1646 label, internalIp, leastLoadedExtIpAddrStr);
1647 IpMap newIpm = new IpMapBuilder().withKey(ipMapKey).setInternalIp(internalIp)
1648 .setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1649 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1650 naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1654 // Re-advertise to the BGP for the external IP, which is allocated to the subnet
1655 // for the first time and hence not having a route.
1656 //Get the VPN Name using the network ID
1657 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
1658 if (vpnName != null) {
1659 LOG.debug("allocateExternalIp : Retrieved vpnName {} for networkId {}", vpnName, networkId);
1660 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1661 LOG.debug("allocateExternalIp : Best effort for getting primary napt switch when router i/f are"
1662 + "added after gateway-set");
1663 dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1664 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1665 LOG.error("allocateExternalIp : dpnId is null or Zero for the router {}", routerName);
1669 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1670 leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, networkId, router,
1677 protected Long checkExternalIpLabel(long routerId, String externalIp) {
1678 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1679 for (IpMap ipMap : ipMaps) {
1680 if (ipMap.getExternalIp().equals(externalIp)) {
1681 if (ipMap.getLabel() != null) {
1682 return ipMap.getLabel();
1686 LOG.error("checkExternalIpLabel : no ipMaps found for routerID:{} and externalIP:{}", routerId, externalIp);
1691 protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1692 LOG.trace("remove : Router delete method");
1694 ROUTER DELETE SCENARIO
1695 1) Get the router ID from the event.
1696 2) Build the cookie information from the router ID.
1697 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1698 4) Build the flow with the cookie value.
1699 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1700 6) Remove the flows from the other switches which points to the primary and secondary
1701 switches for the flows related the router ID.
1702 7) Get the list of external IP address maintained for the router ID.
1703 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1704 9) Withdraw the corresponding routes from the BGP.
1707 if (identifier == null || router == null) {
1708 LOG.error("remove : returning without processing since routers is null");
1712 String routerName = router.getRouterName();
1713 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.key(),
1714 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
1715 LOG.info("remove : Removing default NAT route from FIB on all dpns part of router {} ",
1717 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1718 if (routerId == NatConstants.INVALID_ID) {
1719 LOG.error("remove : Remove external router event - Invalid routerId for routerName {}",
1723 long bgpVpnId = NatConstants.INVALID_ID;
1724 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1725 if (bgpVpnUuid != null) {
1726 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1728 addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, false,
1730 Uuid networkUuid = router.getNetworkId();
1732 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1733 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
1734 // No NAPT switch for external router, probably because the router is not attached to
1736 // internal networks
1738 "No NAPT switch for router {}, check if router is attached to any internal "
1743 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1744 handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId,
1747 if (NatUtil.releaseId(idManager, NatConstants.ODL_VNI_POOL_NAME, routerName)
1748 == NatConstants.INVALID_ID) {
1749 LOG.error("remove: Unable to release VNI for router - {}", routerName);
1751 })), NatConstants.NAT_DJC_MAX_RETRIES);
1754 public void handleDisableSnat(Routers router, Uuid networkUuid, @NonNull Collection<String> externalIps,
1755 boolean routerFlag, @Nullable String vpnName, BigInteger naptSwitchDpnId,
1756 long routerId, TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
1757 LOG.info("handleDisableSnat : Entry");
1758 String routerName = router.getRouterName();
1761 removeNaptSwitch(routerName);
1763 updateNaptSwitch(routerName, BigInteger.ZERO);
1766 LOG.debug("handleDisableSnat : Remove the ExternalCounter model for the router ID {}", routerId);
1767 naptManager.removeExternalCounter(routerId);
1769 LOG.debug("handleDisableSnat : got primarySwitch as dpnId {}", naptSwitchDpnId);
1770 if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
1771 LOG.error("handleDisableSnat : Unable to retrieve the primary NAPT switch for the "
1772 + "router ID {} from RouterNaptSwitch model", routerId);
1775 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
1777 if (extNwProvType == null) {
1778 LOG.error("handleDisableSnat : External Network Provider Type missing");
1781 Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps());
1782 removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnName, externalIps,
1783 externalSubnetList, removeFlowInvTx, extNwProvType);
1784 removeFlowsFromNonActiveSwitches(routerId, routerName, naptSwitchDpnId, removeFlowInvTx);
1785 String externalSubnetVpn = null;
1786 for (Uuid externalSubnetId : externalSubnetList) {
1787 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, externalSubnetId);
1788 // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
1789 if (externalSubnet.isPresent()) {
1790 externalSubnetVpn = externalSubnetId.getValue();
1791 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, externalSubnetVpn,
1792 router.getExtGwMacAddress(), removeFlowInvTx);
1795 if (externalSubnetVpn == null) {
1796 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnName,
1797 router.getExtGwMacAddress(), removeFlowInvTx);
1799 // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
1800 // for the router ID.
1801 LOG.debug("handleDisableSnat : Remove the Internal to external IP address maintained for the "
1802 + "router ID {} in the DS", routerId);
1803 naptManager.removeMapping(routerId);
1804 } catch (InterruptedException | ExecutionException e) {
1805 LOG.error("handleDisableSnat : Exception while handling disableSNAT for router :{}", routerName, e);
1807 LOG.info("handleDisableSnat : Exit");
1810 // TODO Clean up the exception handling
1811 @SuppressWarnings("checkstyle:IllegalCatch")
1812 public void handleDisableSnatInternetVpn(String routerName, long routerId, Uuid networkUuid,
1813 @NonNull Collection<String> externalIps,
1814 String vpnId, TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
1815 LOG.debug("handleDisableSnatInternetVpn: Started to process handle disable snat for router {} "
1816 + "with internet vpn {}", routerName, vpnId);
1818 BigInteger naptSwitchDpnId = null;
1819 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
1820 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1821 Optional<RouterToNaptSwitch> rtrToNapt;
1823 rtrToNapt = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1824 LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1825 } catch (ReadFailedException e) {
1826 LOG.error("Failed to read NAPT switch for router {}", routerName, e);
1827 rtrToNapt = Optional.absent();
1829 if (rtrToNapt.isPresent()) {
1830 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1832 LOG.debug("handleDisableSnatInternetVpn : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1834 removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId,
1837 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1838 if (extGwMacAddress != null) {
1839 LOG.debug("handleDisableSnatInternetVpn : External Gateway MAC address {} found for "
1840 + "External Router ID {}", extGwMacAddress, routerId);
1842 LOG.error("handleDisableSnatInternetVpn : No External Gateway MAC address found for "
1843 + "External Router ID {}", routerId);
1846 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId, extGwMacAddress,
1848 } catch (Exception ex) {
1849 LOG.error("handleDisableSnatInternetVpn : Failed to remove fib entries for routerId {} "
1850 + "in naptSwitchDpnId {}", routerId, naptSwitchDpnId, ex);
1852 if (NatUtil.releaseId(idManager, NatConstants.ODL_VNI_POOL_NAME, vpnId) == NatConstants.INVALID_ID) {
1853 LOG.error("handleDisableSnatInternetVpn : Unable to release VNI for vpnId {} ", vpnId);
1855 } catch (InterruptedException | ExecutionException e) {
1856 LOG.error("handleDisableSnatInternetVpn: Exception while handling disableSNATInternetVpn for router {} "
1857 + "with internet vpn {}", routerName, vpnId, e);
1859 LOG.debug("handleDisableSnatInternetVpn: Processed handle disable snat for router {} with internet vpn {}",
1863 // TODO Clean up the exception handling
1864 @SuppressWarnings("checkstyle:IllegalCatch")
1865 public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1866 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
1867 .setPrimarySwitchId(naptSwitchId).build();
1869 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1870 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1871 } catch (Exception ex) {
1872 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
1873 naptSwitchId, routerName);
1875 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
1876 naptSwitchId, routerName);
1879 protected void removeNaptSwitch(String routerName) {
1880 // Remove router and switch from model
1881 InstanceIdentifier<RouterToNaptSwitch> id =
1882 InstanceIdentifier.builder(NaptSwitches.class)
1883 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1884 LOG.debug("removeNaptSwitch : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1885 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1886 //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
1887 NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
1890 public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
1891 BigInteger dpnId, Uuid networkId, String vpnName,
1892 @NonNull Collection<String> externalIps,
1893 Collection<Uuid> externalSubnetList,
1894 TypedReadWriteTransaction<Configuration> confTx,
1895 ProviderTypes extNwProvType)
1896 throws InterruptedException, ExecutionException {
1898 LOG.debug("removeNaptFlowsFromActiveSwitch : Remove NAPT flows from Active switch");
1899 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1901 //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1902 // traffic which comes from the VMs of the NAPT switches)
1903 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1904 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1907 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1908 + "and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
1909 mdsalManager.removeFlow(confTx, preSnatFlowEntity);
1911 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1912 // traffic which comes from the VMs of the non NAPT switches)
1913 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
1914 elanManager, idManager, routerId, routerName);
1915 String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
1916 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1918 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1919 + "and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
1920 mdsalManager.removeFlow(confTx, tsNatFlowEntity);
1922 //Remove the flow table 25->44 from NAPT Switch
1923 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
1924 NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, dpnId);
1927 //Remove the Outbound flow entry which forwards the packet to FIB Table
1929 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {}"
1930 + " and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1932 String outboundTcpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1933 NwConstants.IP_PROT_TCP);
1934 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1935 outboundTcpNatFlowRef);
1936 mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
1938 String outboundUdpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1939 NwConstants.IP_PROT_UDP);
1940 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1941 outboundUdpNatFlowRef);
1942 mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
1944 String icmpDropFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
1945 NwConstants.IP_PROT_ICMP);
1946 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1948 mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
1949 boolean lastRouterOnExternalNetwork =
1950 !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker, networkId, routerName, dpnId);
1951 if (lastRouterOnExternalNetwork) {
1952 removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps, confTx);
1954 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
1955 // External Subnet Vpn Id.
1956 for (Uuid externalSubnetId : externalSubnetList) {
1957 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
1958 if (subnetVpnId != -1 && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
1959 dataBroker, externalSubnetId, routerName, dpnId)) {
1960 String natPfibSubnetFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
1961 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE,
1962 natPfibSubnetFlowRef);
1963 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
1964 LOG.debug("removeNaptFlowsFromActiveSwitch : Removed the flow in table {} with external subnet "
1965 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
1966 subnetVpnId, dpnId);
1970 //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1971 String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1972 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1975 "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
1976 + "and router ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
1977 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
1979 if (lastRouterOnExternalNetwork) {
1980 // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
1981 // - This does not work since ext-routers is deleted already - no network info
1982 //Get the VPN ID from the ExternalNetworks model
1984 if (vpnName == null || vpnName.isEmpty()) {
1985 // ie called from router delete cases
1986 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1987 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnUuid is {}", vpnUuid);
1988 if (vpnUuid != null) {
1989 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1990 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId {} for external network {} router delete "
1991 + "or disableSNAT scenario", vpnId, networkId);
1994 // ie called from disassociate vpn case
1995 LOG.debug("removeNaptFlowsFromActiveSwitch : This is disassociate nw with vpn case with vpnName {}",
1997 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1998 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId for disassociate nw with vpn scenario {}",
2002 if (vpnId != NatConstants.INVALID_ID) {
2003 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2004 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2005 FlowEntity natPfibVpnFlowEntity =
2006 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2007 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in {} for the active switch with the "
2008 + "DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2009 mdsalManager.removeFlow(confTx, natPfibVpnFlowEntity);
2013 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2014 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2015 if (ipPortMapping == null) {
2016 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the IpPortMapping");
2020 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2021 String protocol = intextIpProtocolType.getProtocol().name();
2022 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2023 String ipPortInternal = ipPortMap.getIpPortInternal();
2024 String[] ipPortParts = ipPortInternal.split(":");
2025 if (ipPortParts.length != 2) {
2026 LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the Internal IP and port");
2029 String internalIp = ipPortParts[0];
2030 String internalPort = ipPortParts[1];
2032 //Build the flow for the outbound NAPT table
2033 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2034 + NatConstants.COLON_SEPARATOR + internalPort);
2035 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2036 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
2037 FlowEntity outboundNaptFlowEntity =
2038 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2040 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch "
2041 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2042 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
2044 //Build the flow for the inbound NAPT table
2045 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2046 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
2047 FlowEntity inboundNaptFlowEntity =
2048 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2050 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active active switch "
2051 + "with the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2052 mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
2057 protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
2058 @NonNull Collection<String> externalIps,
2059 TypedReadWriteTransaction<Configuration> writeFlowInvTx)
2060 throws ExecutionException, InterruptedException {
2061 long extVpnId = NatConstants.INVALID_ID;
2062 if (networkId != null) {
2063 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
2064 if (vpnUuid != null) {
2065 extVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
2067 LOG.debug("removeNaptFibExternalOutputFlows : vpnUuid is null");
2070 LOG.debug("removeNaptFibExternalOutputFlows : networkId is null");
2071 extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2073 if (extVpnId == NatConstants.INVALID_ID) {
2074 LOG.warn("removeNaptFibExternalOutputFlows : extVpnId not found for routerId {}", routerId);
2075 extVpnId = routerId;
2077 for (String ip : externalIps) {
2078 String extIp = removeMaskFromIp(ip);
2079 String naptFlowRef = getFlowRefNaptPreFib(dpnId, NwConstants.NAPT_PFIB_TABLE, extVpnId);
2080 LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in table {} for the active switch"
2081 + " with the DPN ID {} and router ID {} and IP {} flowRef {}",
2082 NwConstants.NAPT_PFIB_TABLE, dpnId, routerId, extIp, naptFlowRef);
2083 FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef);
2084 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2088 private String removeMaskFromIp(String ip) {
2089 if (ip != null && !ip.trim().isEmpty()) {
2090 return ip.split("/")[0];
2095 public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
2096 BigInteger dpnId, Uuid networkId, String vpnName,
2097 TypedReadWriteTransaction<Configuration> writeFlowInvTx)
2098 throws ExecutionException, InterruptedException {
2099 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : Remove NAPT flows from Active switch Internet Vpn");
2100 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
2102 //Remove the NAPT PFIB TABLE entry
2104 if (vpnName != null) {
2105 // ie called from disassociate vpn case
2106 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : This is disassociate nw with vpn case "
2107 + "with vpnName {}", vpnName);
2108 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
2109 LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : vpnId for disassociate nw with vpn scenario {}",
2113 if (vpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker,
2114 networkId, routerName, dpnId)) {
2115 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2116 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
2117 FlowEntity natPfibVpnFlowEntity =
2118 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
2119 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the active switch "
2120 + "with the DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
2121 mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
2123 // Remove IP-PORT active NAPT entries and release port from IdManager
2124 // For the router ID get the internal IP , internal port and the corresponding
2125 // external IP and external Port.
2126 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2127 if (ipPortMapping == null) {
2128 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the IpPortMapping");
2131 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2132 String protocol = intextIpProtocolType.getProtocol().name();
2133 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2134 String ipPortInternal = ipPortMap.getIpPortInternal();
2135 String[] ipPortParts = ipPortInternal.split(":");
2136 if (ipPortParts.length != 2) {
2137 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the Internal IP "
2141 String internalIp = ipPortParts[0];
2142 String internalPort = ipPortParts[1];
2144 //Build the flow for the outbound NAPT table
2145 naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
2146 + NatConstants.COLON_SEPARATOR + internalPort);
2147 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
2148 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
2149 FlowEntity outboundNaptFlowEntity =
2150 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2152 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2153 + "active switch with the DPN ID {} and router ID {}",
2154 NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
2155 mdsalManager.removeFlow(writeFlowInvTx, outboundNaptFlowEntity);
2157 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
2158 final String externalIp = ipPortExternal.getIpAddress();
2160 //Build the flow for the inbound NAPT table
2161 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
2162 String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
2163 FlowEntity inboundNaptFlowEntity =
2164 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
2166 LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
2167 + "active active switch with the DPN ID {} and router ID {}",
2168 NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
2169 mdsalManager.removeFlow(writeFlowInvTx, inboundNaptFlowEntity);
2171 // Finally release port from idmanager
2172 String internalIpPort = internalIp + ":" + internalPort;
2173 naptManager.removePortFromPool(internalIpPort, externalIp);
2175 //Remove sessions from models
2176 naptManager.removeIpPortMappingForRouterID(routerId);
2177 naptManager.removeIntIpPortMappingForRouterID(routerId);
2181 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Invalid vpnId {}", vpnId);
2185 public void removeFlowsFromNonActiveSwitches(long routerId, String routerName,
2186 BigInteger naptSwitchDpnId, TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2187 throws ExecutionException, InterruptedException {
2188 LOG.debug("removeFlowsFromNonActiveSwitches : Remove NAPT related flows from non active switches");
2190 // Remove the flows from the other switches which points to the primary and secondary switches
2191 // for the flows related the router ID.
2192 List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
2193 if (allSwitchList.isEmpty()) {
2194 LOG.error("removeFlowsFromNonActiveSwitches : Unable to get the swithces for the router {}", routerName);
2197 for (BigInteger dpnId : allSwitchList) {
2198 if (!naptSwitchDpnId.equals(dpnId)) {
2199 LOG.info("removeFlowsFromNonActiveSwitches : Handle Ordinary switch");
2201 //Remove the PSNAT entry which forwards the packet to Terminating Service table
2202 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
2203 FlowEntity preSnatFlowEntity =
2204 NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
2206 LOG.info("removeFlowsFromNonActiveSwitches : Remove the flow in the {} for the non active switch "
2207 + "with the DPN ID {} and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
2208 mdsalManager.removeFlow(removeFlowInvTx, preSnatFlowEntity);
2210 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
2211 long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
2212 NatUtil.getGroupIdKey(routerName));
2213 if (groupId != NatConstants.INVALID_ID) {
2215 "removeFlowsFromNonActiveSwitches : Remove the group {} for the non active switch with "
2216 + "the DPN ID {} and router ID {}", groupId, dpnId, routerId);
2217 mdsalManager.removeGroup(removeFlowInvTx, dpnId, groupId);
2219 LOG.error("removeFlowsFromNonActiveSwitches: Unable to obtained groupID for router:{}", routerName);
2225 public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, @Nullable Uuid networkUuid,
2226 @NonNull Collection<String> externalIps, @Nullable String vpnName,
2227 String extGwMacAddress, TypedReadWriteTransaction<Configuration> confTx)
2228 throws ExecutionException, InterruptedException {
2229 //Withdraw the corresponding routes from the BGP.
2230 //Get the network ID using the router ID.
2231 LOG.debug("clrRtsFromBgpAndDelFibTs : Advertise to BGP and remove routes for externalIps {} with routerId {},"
2232 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2233 if (networkUuid == null) {
2234 LOG.error("clrRtsFromBgpAndDelFibTs : networkId is null");
2238 if (externalIps.isEmpty()) {
2239 LOG.error("clrRtsFromBgpAndDelFibTs : externalIps is empty");
2243 if (vpnName == null) {
2244 //Get the VPN Name using the network ID
2245 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2246 if (vpnName == null) {
2247 LOG.error("clrRtsFromBgpAndDelFibTs : No VPN associated with ext nw {} for the router {}",
2248 networkUuid, routerId);
2252 LOG.debug("clrRtsFromBgpAndDelFibTs : Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2254 //Remove custom FIB routes
2255 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2256 for (String extIp : externalIps) {
2257 clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, confTx);
2261 protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2262 final Uuid networkUuid, String extGwMacAddress,
2263 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2264 throws ExecutionException, InterruptedException {
2265 clearBgpRoutes(extIp, vpnName);
2266 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2270 protected void delFibTsAndReverseTraffic(final BigInteger dpnId, String routerName, long routerId, String extIp,
2271 String vpnName, Uuid extNetworkId, long tempLabel,
2272 String gwMacAddress, boolean switchOver,
2273 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2274 throws ExecutionException, InterruptedException {
2275 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2276 //String routerName = NatUtil.getRouterName(dataBroker,routerId);
2277 if (routerName == null) {
2278 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2281 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
2282 if (extNwProvType == null) {
2283 LOG.error("delFibTsAndReverseTraffic : External Network Provider Type Missing");
2286 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2287 * external network provided type is VxLAN
2289 if (extNwProvType == ProviderTypes.VXLAN) {
2290 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, gwMacAddress
2294 if (tempLabel < 0) {
2295 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2299 final long label = tempLabel;
2300 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2301 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
2302 LOG.debug("delFibTsAndReverseTraffic : Using extSubnetId as vpnName for FLAT/VLAN use-cases");
2303 Routers extRouter = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
2304 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp,
2307 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
2310 if (externalSubnet.isPresent()) {
2311 vpnName = externalSubnetId.getValue();
2314 final String externalVpn = vpnName;
2315 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(externalVpn)
2316 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label)
2317 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
2318 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2320 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2321 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2322 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2323 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2324 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2327 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2328 Futures.transformAsync(future, result -> {
2330 if (result.isSuccessful()) {
2331 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2332 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2333 .setVpnName(externalVpn).setIpPrefix(externalIp).build();
2334 return vpnService.removeVpnLabel(labelInput);
2337 String.format("RPC call to remove custom FIB entries on dpn %s for "
2338 + "prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
2340 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2342 }, MoreExecutors.directExecutor());
2344 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2347 public void onFailure(@NonNull Throwable error) {
2348 LOG.error("delFibTsAndReverseTraffic : Error in removing the label:{} or custom fib entries"
2349 + "got external ip {}", label, extIp, error);
2353 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
2354 if (result.isSuccessful()) {
2355 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2356 + "from VPN {}", externalIp, externalVpn);
2358 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2359 + " from VPN {}, {}", externalIp, externalVpn, result.getErrors());
2362 }, MoreExecutors.directExecutor());
2364 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2365 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2369 private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
2370 final Uuid networkUuid, String extGwMacAddress, boolean switchOver,
2371 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
2372 throws ExecutionException, InterruptedException {
2373 LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2374 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2375 if (routerName == null) {
2376 LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
2379 //Get the external network provider type from networkId
2380 ProviderTypes extNwProvType = NatUtil.getProviderTypefromNetworkId(dataBroker, networkUuid);
2381 if (extNwProvType == null) {
2382 LOG.error("delFibTsAndReverseTraffic : Could not retrieve provider type for external network {} ",
2386 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2387 * external network provided type is VxLAN
2389 if (extNwProvType == ProviderTypes.VXLAN) {
2390 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, extGwMacAddress);
2393 //Get IPMaps from the DB for the router ID
2394 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
2395 if (dbIpMaps.isEmpty()) {
2396 LOG.error("delFibTsAndReverseTraffic : IPMaps not found for router {}", routerId);
2400 long tempLabel = NatConstants.INVALID_ID;
2401 for (IpMap dbIpMap : dbIpMaps) {
2402 String dbExternalIp = dbIpMap.getExternalIp();
2403 LOG.debug("delFibTsAndReverseTraffic : Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
2404 //Select the IPMap, whose external IP is the IP for which FIB is installed
2405 if (extIp.equals(dbExternalIp)) {
2406 tempLabel = dbIpMap.getLabel();
2407 LOG.debug("delFibTsAndReverseTraffic : Retrieved label {} for dbExternalIp {} with router id {}",
2408 tempLabel, dbExternalIp, routerId);
2412 if (tempLabel == NatConstants.INVALID_ID) {
2413 LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
2418 final long label = tempLabel;
2419 final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
2420 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
2421 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp)
2422 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).setServiceId(label).build();
2423 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
2425 removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
2426 removeLFibTableEntry(dpnId, label, removeFlowInvTx);
2427 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2428 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
2429 NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
2432 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
2433 Futures.transformAsync(future, result -> {
2435 if (result.isSuccessful()) {
2436 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
2437 .setVpnName(vpnName).setIpPrefix(externalIp).build();
2438 return vpnService.removeVpnLabel(labelInput);
2441 String.format("RPC call to remove custom FIB entries on dpn %s for "
2442 + "prefix %s Failed - %s",
2443 dpnId, externalIp, result.getErrors());
2445 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2447 }, MoreExecutors.directExecutor());
2449 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
2452 public void onFailure(@NonNull Throwable error) {
2453 LOG.error("delFibTsAndReverseTraffic : Error in removing the label or custom fib entries", error);
2457 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
2458 if (result.isSuccessful()) {
2459 LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
2460 + "from VPN {}", externalIp, vpnName);
2462 LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
2463 + " from VPN {}, {}", externalIp, vpnName, result.getErrors());
2466 }, MoreExecutors.directExecutor());
2468 LOG.debug("delFibTsAndReverseTraffic: switch-over is happened on DpnId {}. No need to release allocated "
2469 + "label {} for external fixed ip {} for router {}", dpnId, label, externalIp, routerId);
2473 protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2474 List<String> externalIps, @Nullable String vpnName, String extGwMacAddress,
2475 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2476 //Withdraw the corresponding routes from the BGP.
2477 //Get the network ID using the router ID.
2478 LOG.debug("clearFibTsAndReverseTraffic : for externalIps {} with routerId {},"
2479 + "network Id {} and vpnName {}", externalIps, routerId, networkUuid, vpnName);
2480 if (networkUuid == null) {
2481 LOG.error("clearFibTsAndReverseTraffic : networkId is null");
2485 if (externalIps == null || externalIps.isEmpty()) {
2486 LOG.error("clearFibTsAndReverseTraffic : externalIps is null");
2490 if (vpnName == null) {
2491 //Get the VPN Name using the network ID
2492 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
2493 if (vpnName == null) {
2494 LOG.error("clearFibTsAndReverseTraffic : No VPN associated with ext nw {} for the router {}",
2495 networkUuid, routerId);
2499 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2501 //Remove custom FIB routes
2502 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2503 for (String extIp : externalIps) {
2504 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
2509 protected void clearBgpRoutes(String externalIp, final String vpnName) {
2510 //Inform BGP about the route removal
2511 LOG.info("clearBgpRoutes : Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
2512 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
2513 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
2516 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId,
2517 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2518 LOG.info("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
2519 mdsalManager.removeFlow(writeFlowInvTx, dpnId,
2520 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), NwConstants.INTERNAL_TUNNEL_TABLE);
2521 LOG.debug("removeTunnelTableEntry : dpID {} : label : {} removed successfully", dpnId, serviceId);
2524 private void removeLFibTableEntry(BigInteger dpnId, long serviceId,
2525 TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
2526 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2527 LOG.debug("removeLFibTableEntry : with flow ref {}", flowRef);
2528 mdsalManager.removeFlow(writeFlowInvTx, dpnId, flowRef, NwConstants.L3_LFIB_TABLE);
2529 LOG.debug("removeLFibTableEntry : dpID : {} label : {} removed successfully", dpnId, serviceId);
2533 * router association to vpn.
2535 * @param routerName - Name of router
2536 * @param routerId - router id
2537 * @param bgpVpnName BGP VPN name
2539 public void changeLocalVpnIdToBgpVpnId(String routerName, long routerId, String bgpVpnName,
2540 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2541 LOG.debug("changeLocalVpnIdToBgpVpnId : Router associated to BGP VPN");
2542 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2543 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2545 LOG.debug("changeLocalVpnIdToBgpVpnId : BGP VPN ID value {} ", bgpVpnId);
2547 if (bgpVpnId != NatConstants.INVALID_ID) {
2548 LOG.debug("changeLocalVpnIdToBgpVpnId : Populate the router-id-name container with the "
2549 + "mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
2550 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
2551 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2552 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2553 getRoutersIdentifier(bgpVpnId), rtrs);
2555 // Get the allocated Primary NAPT Switch for this router
2556 LOG.debug("changeLocalVpnIdToBgpVpnId : Update the Router ID {} to the BGP VPN ID {} ",
2557 routerId, bgpVpnId);
2558 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, writeFlowInvTx);
2561 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2562 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true, writeFlowInvTx,
2569 * router disassociation from vpn.
2571 * @param routerName - Name of router
2572 * @param routerId - router id
2573 * @param bgpVpnName BGP VPN name
2575 public void changeBgpVpnIdToLocalVpnId(String routerName, long routerId, String bgpVpnName,
2576 TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
2577 LOG.debug("changeBgpVpnIdToLocalVpnId : Router dissociated from BGP VPN");
2578 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2579 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2580 LOG.debug("changeBgpVpnIdToLocalVpnId : BGP VPN ID value {} ", bgpVpnId);
2582 // Get the allocated Primary NAPT Switch for this router
2583 LOG.debug("changeBgpVpnIdToLocalVpnId : Router ID value {} ", routerId);
2585 LOG.debug("changeBgpVpnIdToLocalVpnId : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2586 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, NatConstants.INVALID_ID, writeFlowInvTx);
2589 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2590 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true,
2591 writeFlowInvTx, extNwProvType);
2595 boolean chkExtRtrAndSnatEnbl(Uuid routerUuid) {
2596 InstanceIdentifier<Routers> routerInstanceIndentifier =
2597 InstanceIdentifier.builder(ExtRouters.class)
2598 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
2600 Optional<Routers> routerData = SingleTransactionDataBroker
2601 .syncReadOptional(dataBroker,
2602 LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2603 return routerData.isPresent() && routerData.get().isEnableSnat();
2604 } catch (ReadFailedException e) {
2605 LOG.error("Failed to read data for router id {}", routerUuid, e);
2610 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2611 long routerId, boolean isSnatCfgd, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2613 long changedVpnId = bgpVpnId;
2614 String idType = "BGP VPN";
2615 if (bgpVpnId == NatConstants.INVALID_ID) {
2616 changedVpnId = routerId;
2620 List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2621 if (switches.isEmpty()) {
2622 LOG.error("installFlowsWithUpdatedVpnId : No switches found for router {}", routerName);
2625 for (BigInteger dpnId : switches) {
2626 // Update the BGP VPN ID in the SNAT miss entry to group
2627 if (!dpnId.equals(primarySwitchId)) {
2628 LOG.debug("installFlowsWithUpdatedVpnId : Install group in non NAPT switch {}", dpnId);
2629 List<BucketInfo> bucketInfoForNonNaptSwitches =
2630 getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName, routerId);
2631 long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
2632 NatUtil.getGroupIdKey(routerName));
2633 if (groupId != NatConstants.INVALID_ID) {
2635 installGroup(dpnId, routerName, groupId, bucketInfoForNonNaptSwitches);
2638 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2639 + "{} in the non NAPT switch {}", idType, changedVpnId, groupId, dpnId);
2640 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName,
2641 groupId, changedVpnId);
2642 mdsalManager.addFlow(confTx, flowEntity);
2644 LOG.error("installFlowsWithUpdatedVpnId: Unable to get groupId for router:{}", routerName);
2648 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
2649 + "in the primary switch {}", idType, changedVpnId, primarySwitchId);
2650 FlowEntity flowEntity =
2651 buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2652 mdsalManager.addFlow(confTx, flowEntity);
2655 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Terminating Service table (table "
2656 + "ID 36) which forwards the packet to the table 46 in the Primary switch {}",
2657 idType, changedVpnId, primarySwitchId);
2658 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, routerId,
2659 changedVpnId, confTx, extNwProvType);
2662 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the Outbound NAPT table (table ID 46) "
2663 + "which punts the packet to the controller in the Primary switch {}",
2664 idType, changedVpnId, primarySwitchId);
2665 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2668 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT PFIB TABLE which forwards the"
2669 + " outgoing packet to FIB Table in the Primary switch {}",
2670 idType, changedVpnId, primarySwitchId);
2671 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId, confTx);
2674 "installFlowsWithUpdatedVpnId : Update the {} ID {} in the NAPT flows for the Outbound NAPT "
2675 + "table (table ID 46) and the INBOUND NAPT table (table ID 44) in the Primary switch"
2676 + " {}", idType, changedVpnId, primarySwitchId);
2677 updateNaptFlowsWithVpnId(primarySwitchId, routerName, routerId, bgpVpnId);
2679 LOG.debug("installFlowsWithUpdatedVpnId : Installing SNAT PFIB flow in the primary switch {}",
2681 Long vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2682 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2683 if (vpnId != NatConstants.INVALID_ID) {
2684 installNaptPfibEntry(primarySwitchId, vpnId, confTx);
2690 public void updateNaptFlowsWithVpnId(BigInteger dpnId, String routerName, long routerId, long bgpVpnId) {
2691 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2692 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2693 if (ipPortMapping == null) {
2694 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the IpPortMapping");
2697 // Get the External Gateway MAC Address
2698 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
2699 if (extGwMacAddress != null) {
2700 LOG.debug("updateNaptFlowsWithVpnId : External Gateway MAC address {} found for External Router ID {}",
2701 extGwMacAddress, routerId);
2703 LOG.error("updateNaptFlowsWithVpnId : No External Gateway MAC address found for External Router ID {}",
2707 for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
2708 for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
2709 String ipPortInternal = ipPortMap.getIpPortInternal();
2710 String[] ipPortParts = ipPortInternal.split(":");
2711 if (ipPortParts.length != 2) {
2712 LOG.error("updateNaptFlowsWithVpnId : Unable to retrieve the Internal IP and port");
2715 String internalIp = ipPortParts[0];
2716 String internalPort = ipPortParts[1];
2717 LOG.debug("updateNaptFlowsWithVpnId : Found Internal IP {} and Internal Port {}",
2718 internalIp, internalPort);
2719 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2720 NAPTEntryEvent.Protocol protocol;
2721 switch (protocolTypes) {
2723 protocol = NAPTEntryEvent.Protocol.TCP;
2726 protocol = NAPTEntryEvent.Protocol.UDP;
2729 protocol = NAPTEntryEvent.Protocol.TCP;
2731 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.parseInt(internalPort));
2732 SessionAddress externalAddress =
2733 naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2734 long internetVpnid = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
2735 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
2736 routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
2737 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
2738 routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
2743 public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
2744 long changedVpnId) {
2746 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : called for dpId {}, routerName {} groupId {} "
2747 + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
2748 List<MatchInfo> matches = new ArrayList<>();
2749 matches.add(MatchEthernetType.IPV4);
2750 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2752 List<ActionInfo> actionsInfo = new ArrayList<>();
2753 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
2754 elanManager, idManager, changedVpnId, routerName);
2755 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
2756 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Setting the tunnel to the list of action infos {}",
2758 actionsInfo.add(new ActionGroup(groupId));
2759 List<InstructionInfo> instructions = new ArrayList<>();
2760 instructions.add(new InstructionApplyActions(actionsInfo));
2761 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2762 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2763 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2764 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2766 LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Returning SNAT Flow Entity {}", flowEntity);
2770 public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
2771 long changedVpnId) {
2773 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : called for dpId {}, routerName {} "
2774 + "changed VPN ID {}", dpId, routerName, changedVpnId);
2775 List<MatchInfo> matches = new ArrayList<>();
2776 matches.add(MatchEthernetType.IPV4);
2777 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2779 List<InstructionInfo> instructions = new ArrayList<>();
2780 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2782 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2783 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2784 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2785 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2787 LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : Returning SNAT Flow Entity {}", flowEntity);
2791 // TODO : Replace this with ITM Rpc once its available with full functionality
2792 protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
2793 long routerId, long changedVpnId, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
2795 LOG.debug("installTerminatingServiceTblEntryWithUpdatedVpnId : called for switch {}, "
2796 + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2797 FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, routerId, changedVpnId,
2799 mdsalManager.addFlow(confTx, flowEntity);
2802 private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName,
2803 long routerIdLongVal, long changedVpnId, ProviderTypes extNwProvType) {
2804 LOG.debug("buildTsFlowEntityWithUpdatedVpnId : called for switch {}, routerName {}, BGP VPN ID {}",
2805 dpId, routerName, changedVpnId);
2806 List<MatchInfo> matches = new ArrayList<>();
2807 matches.add(MatchEthernetType.IPV4);
2809 BigInteger tunnelId = BigInteger.valueOf(changedVpnId);
2810 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
2811 tunnelId = natOverVxlanUtil.getRouterVni(routerName, changedVpnId);
2813 matches.add(new MatchTunnelId(tunnelId));
2815 List<InstructionInfo> instructions = new ArrayList<>();
2816 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2817 MetaDataUtil.METADATA_MASK_VRFID));
2818 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2819 BigInteger routerId = BigInteger.valueOf(routerIdLongVal);
2820 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2821 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2822 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2823 NwConstants.COOKIE_TS_TABLE, matches, instructions);
2827 public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId,
2828 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2829 LOG.debug("createOutboundTblEntryWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2830 dpnId, routerId, changedVpnId);
2831 FlowEntity tcpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2832 NwConstants.IP_PROT_TCP);
2833 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing tcp flow {}", tcpFlowEntity);
2834 mdsalManager.addFlow(writeFlowInvTx, tcpFlowEntity);
2836 FlowEntity udpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
2837 NwConstants.IP_PROT_UDP);
2838 LOG.debug("createOutboundTblEntryWithBgpVpn : Installing udp flow {}", udpFlowEntity);
2839 mdsalManager.addFlow(writeFlowInvTx, udpFlowEntity);
2841 FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, changedVpnId);
2842 LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
2843 mdsalManager.addFlow(writeFlowInvTx, icmpDropFlow);
2846 protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId,
2847 long changedVpnId, int protocol) {
2848 LOG.debug("buildOutboundFlowEntityWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
2849 dpId, routerId, changedVpnId);
2850 BigInteger cookie = getCookieOutboundFlow(routerId);
2851 List<MatchInfo> matches = new ArrayList<>();
2852 matches.add(MatchEthernetType.IPV4);
2853 matches.add(new MatchIpProtocol((short)protocol));
2854 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2856 List<InstructionInfo> instructions = new ArrayList<>();
2857 List<ActionInfo> actionsInfos = new ArrayList<>();
2858 actionsInfos.add(new ActionPuntToController());
2859 if (snatPuntTimeout != 0) {
2860 actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
2862 instructions.add(new InstructionApplyActions(actionsInfos));
2864 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
2865 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
2866 flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
2867 LOG.debug("createOutboundTblEntryWithBgpVpn : returning flowEntity {}", flowEntity);
2871 public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId,
2872 TypedWriteTransaction<Configuration> writeFlowInvTx) {
2873 LOG.debug("installNaptPfibEntryWithBgpVpn : called for dpnId {} and segmentId {} ,BGP VPN ID {}",
2874 dpnId, segmentId, changedVpnId);
2875 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2876 mdsalManager.addFlow(writeFlowInvTx, naptPfibFlowEntity);
2879 public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2881 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : called for dpId {}, "
2882 + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2883 List<MatchInfo> matches = new ArrayList<>();
2884 matches.add(MatchEthernetType.IPV4);
2885 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2887 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2888 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2889 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
2890 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2891 instructionInfo.add(new InstructionApplyActions(listActionInfo));
2893 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2894 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2895 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2896 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2897 LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : Returning NaptPFib Flow Entity {}", flowEntity);
2902 protected ExternalRoutersListener getDataTreeChangeListener() {
2903 return ExternalRoutersListener.this;
2906 protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId,
2907 @Nullable TypedWriteTransaction<Configuration> writeFlowInvTx) {
2908 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
2910 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
2911 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
2912 if (subnetVpnId != -1) {
2913 LOG.debug("installNaptPfibEntriesForExternalSubnets : called for dpnId {} "
2914 + "and vpnId {}", dpnId, subnetVpnId);
2915 installNaptPfibEntry(dpnId, subnetVpnId, writeFlowInvTx);