2 * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.natservice.internal;
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.AsyncFunction;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.JdkFutureAdapters;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
17 import java.net.Inet6Address;
18 import java.net.InetAddress;
19 import java.net.UnknownHostException;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
25 import java.util.Objects;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Future;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
31 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
32 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
35 import org.opendaylight.genius.mdsalutil.ActionInfo;
36 import org.opendaylight.genius.mdsalutil.BucketInfo;
37 import org.opendaylight.genius.mdsalutil.FlowEntity;
38 import org.opendaylight.genius.mdsalutil.GroupEntity;
39 import org.opendaylight.genius.mdsalutil.InstructionInfo;
40 import org.opendaylight.genius.mdsalutil.MDSALUtil;
41 import org.opendaylight.genius.mdsalutil.MatchInfo;
42 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
43 import org.opendaylight.genius.mdsalutil.NwConstants;
44 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
45 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
46 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
47 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
48 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
49 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
50 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
51 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
52 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
53 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
54 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
55 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
56 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
57 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
58 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
59 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
60 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
61 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
104 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;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIds;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsBuilder;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsKey;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
121 import org.opendaylight.yangtools.concepts.ListenerRegistration;
122 import org.opendaylight.yangtools.yang.binding.DataObject;
123 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
124 import org.opendaylight.yangtools.yang.common.RpcResult;
125 import org.slf4j.Logger;
126 import org.slf4j.LoggerFactory;
128 public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener> {
129 private static final Logger LOG = LoggerFactory.getLogger(ExternalRoutersListener.class);
130 private ListenerRegistration<DataChangeListener> listenerRegistration;
131 private final DataBroker dataBroker;
132 private final IMdsalApiManager mdsalManager;
133 private final ItmRpcService itmManager;
134 private final OdlInterfaceRpcService interfaceManager;
135 private final IdManagerService idManager;
136 private final NaptManager naptManager;
137 private final NAPTSwitchSelector naptSwitchSelector;
138 private final IBgpManager bgpManager;
139 private final VpnRpcService vpnService;
140 private final FibRpcService fibService;
141 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
142 private final NaptEventHandler naptEventHandler;
143 private final NaptPacketInHandler naptPacketInHandler;
144 private final IFibManager fibManager;
145 private final IVpnManager vpnManager;
146 private final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer;
147 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
148 static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
150 public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
151 final ItmRpcService itmManager,
152 final OdlInterfaceRpcService interfaceManager,
153 final IdManagerService idManager,
154 final NaptManager naptManager,
155 final NAPTSwitchSelector naptSwitchSelector,
156 final IBgpManager bgpManager,
157 final VpnRpcService vpnService,
158 final FibRpcService fibService,
159 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
160 final NaptEventHandler naptEventHandler,
161 final NaptPacketInHandler naptPacketInHandler,
162 final IFibManager fibManager,
163 final IVpnManager vpnManager,
164 final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer) {
165 super(Routers.class, ExternalRoutersListener.class);
166 this.dataBroker = dataBroker;
167 this.mdsalManager = mdsalManager;
168 this.itmManager = itmManager;
169 this.interfaceManager = interfaceManager;
170 this.idManager = idManager;
171 this.naptManager = naptManager;
172 this.naptSwitchSelector = naptSwitchSelector;
173 this.bgpManager = bgpManager;
174 this.vpnService = vpnService;
175 this.fibService = fibService;
176 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
177 this.naptEventHandler = naptEventHandler;
178 this.naptPacketInHandler = naptPacketInHandler;
179 this.fibManager = fibManager;
180 this.vpnManager = vpnManager;
181 this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
186 LOG.info("{} init", getClass().getSimpleName());
187 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
192 protected InstanceIdentifier<Routers> getWildCardPath() {
193 return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
197 // TODO Clean up the exception handling
198 @SuppressWarnings("checkstyle:IllegalCatch")
199 protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
200 // Populate the router-id-name container
201 String routerName = routers.getRouterName();
202 LOG.info("NAT Service : Add external router event for {}", routerName);
203 NatUtil.createRouterIdsConfigDS(dataBroker, routerName);
205 LOG.info("NAT Service : Installing NAT default route on all dpns part of router {}", routerName);
207 addOrDelDefFibRouteToSNAT(routerName, true);
208 } catch (Exception ex) {
209 LOG.debug("NAT Service : Exception {} while Installing NAT default route on all dpns part of router {}",
213 long segmentId = NatUtil.getVpnId(dataBroker, routerName);
214 // Allocate Primary Napt Switch for this router
215 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName, segmentId);
216 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
218 "NAT Service: Failed to get or allocate NAPT switch for router {}. NAPT flow installation will be"
219 + "delayed", routerName);
223 handleRouterGwFlows(routers, primarySwitchId, NwConstants.ADD_FLOW);
224 if (!routers.isEnableSnat()) {
225 LOG.info("NAT Service : SNAT is disabled for external router {} ", routerName);
229 handleEnableSnat(routers, segmentId, primarySwitchId);
232 public void handleEnableSnat(Routers routers, long segmentId, BigInteger primarySwitchId) {
233 String routerName = routers.getRouterName();
234 LOG.info("NAT Service : Handling SNAT for router {}", routerName);
236 naptManager.initialiseExternalCounter(routers, segmentId);
237 subnetRegisterMapping(routers, segmentId);
239 LOG.debug("NAT Service : About to create and install outbound miss entry in Primary Switch {} for router {}",
240 primarySwitchId, routerName);
242 long bgpVpnId = NatConstants.INVALID_ID;
243 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
244 if (bgpVpnUuid != null) {
245 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
247 if (bgpVpnId != NatConstants.INVALID_ID) {
248 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, segmentId, false);
250 // write metadata and punt
251 installOutboundMissEntry(routerName, primarySwitchId);
252 // Now install entries in SNAT tables to point to Primary for each router
253 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
254 if (switches != null) {
255 for (BigInteger dpnId : switches) {
256 // Handle switches and NAPT switches separately
257 if (!dpnId.equals(primarySwitchId)) {
258 LOG.debug("NAT Service : Handle Ordinary switch");
259 handleSwitches(dpnId, routerName, primarySwitchId);
261 LOG.debug("NAT Service : Handle NAPT switch");
262 handlePrimaryNaptSwitch(dpnId, routerName);
268 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, segmentId);
269 if (externalIps == null || externalIps.isEmpty()) {
270 LOG.debug("NAT Service : Internal External mapping found for router {}", routerName);
273 for (String externalIpAddrPrefix : externalIps) {
274 LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, "
275 + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
276 handleSnatReverseTraffic(primarySwitchId, routers, segmentId, routerName, externalIpAddrPrefix);
279 LOG.info("NAT Service : handleEnableSnat() Exit");
282 private BigInteger getPrimaryNaptSwitch(String routerName, long segmentId) {
283 // Allocate Primary Napt Switch for this router
284 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
285 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
286 LOG.debug("NAT Service : Primary NAPT switch with DPN ID {} is already elected for router",
287 primarySwitchId, routerName);
288 return primarySwitchId;
291 primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
292 LOG.debug("NAT Service : Primary NAPT switch DPN ID {}", primarySwitchId);
293 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
294 LOG.info("NAT Service : Unable to to select the primary NAPT switch for router {}", routerName);
297 return primarySwitchId;
300 protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId) {
301 Long extVpnId = NatUtil.getVpnId(dataBroker, routerId);
302 if (extVpnId == null || extVpnId == NatConstants.INVALID_ID) {
303 LOG.debug("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
306 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
307 if (externalIps == null || externalIps.isEmpty()) {
308 LOG.debug("installNaptPfibExternalOutputFlow - empty external Ips list for dpnId {} extVpnId {}",
312 for (String ip : externalIps) {
313 Uuid subnetId = getSubnetIdForFixedIp(ip);
314 if (subnetId != null) {
315 long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
316 if (subnetVpnId != NatConstants.INVALID_ID) {
317 extVpnId = subnetVpnId;
319 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
320 dpnId, extVpnId, subnetId);
321 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
322 mdsalManager.installFlow(postNaptFlowEntity);
327 private Uuid getSubnetIdForFixedIp(String ip) {
329 IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
330 Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
331 Uuid subnetId = NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
337 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
338 List<Uuid> subnetList = null;
339 List<String> externalIps = null;
340 LOG.debug("NAT Service : Fetching values from extRouters model");
341 subnetList = routerEntry.getSubnetIds();
342 externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
344 int extIpCounter = externalIps.size();
345 LOG.debug("NAT Service : counter values before looping counter {} and extIpCounter {}", counter, extIpCounter);
346 for (Uuid subnet : subnetList) {
347 LOG.debug("NAT Service : Looping internal subnets for subnet {}", subnet);
348 InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
349 .builder(Subnetmaps.class)
350 .child(Subnetmap.class, new SubnetmapKey(subnet))
352 Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
353 if (sn.isPresent()) {
355 Subnetmap subnetmapEntry = sn.get();
356 String subnetString = subnetmapEntry.getSubnetIp();
357 String[] subnetSplit = subnetString.split("/");
358 String subnetIp = subnetSplit[0];
360 InetAddress address = InetAddress.getByName(subnetIp);
361 if (address instanceof Inet6Address) {
362 // TODO: Revisit when IPv6 external connectivity support is added.
363 LOG.debug("Skipping ipv6 address {}.", address);
366 } catch (UnknownHostException e) {
367 LOG.warn("Invalid ip address {}", subnetIp, e);
370 String subnetPrefix = "0";
371 if (subnetSplit.length == 2) {
372 subnetPrefix = subnetSplit[1];
374 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
375 LOG.debug("NAT Service : subnetAddr is {} and subnetPrefix is {}",
376 subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
378 LOG.debug("NAT Service : counter values counter {} and extIpCounter {}", counter, extIpCounter);
379 if (extIpCounter != 0) {
380 if (counter < extIpCounter) {
381 String[] ipSplit = externalIps.get(counter).split("/");
382 String externalIp = ipSplit[0];
383 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
384 if (ipSplit.length == 2) {
385 extPrefix = ipSplit[1];
387 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
388 LOG.debug("NAT Service : externalIp is {} and extPrefix is {}",
389 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
390 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
391 LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. "
392 + "prefix {}", subnetIp, subnetPrefix, externalIp, extPrefix);
394 counter = 0; //Reset the counter which runs on externalIps for round-robbin effect
395 LOG.debug("NAT Service : Counter on externalIps got reset");
396 String[] ipSplit = externalIps.get(counter).split("/");
397 String externalIp = ipSplit[0];
398 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
399 if (ipSplit.length == 2) {
400 extPrefix = ipSplit[1];
402 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
403 LOG.debug("NAT Service : externalIp is {} and extPrefix is {}",
404 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
405 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
406 LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. "
407 + "prefix {}", subnetIp, subnetPrefix,
408 externalIp, extPrefix);
412 LOG.debug("NAT Service : Counter on externalIps incremented to {}", counter);
414 LOG.warn("NAT Service : No internal subnets present in extRouters Model");
419 private void addOrDelDefFibRouteToSNAT(String routerName, boolean create) {
420 //Check if BGP VPN exists. If exists then invoke the new method.
421 long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
422 if (bgpVpnId != NatConstants.INVALID_ID) {
423 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
424 if (bgpVpnUuid != null) {
425 String bgpVpnName = bgpVpnUuid.getValue();
426 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
427 bgpVpnId, bgpVpnName);
428 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId))
429 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
430 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
431 getRoutersIdentifier(bgpVpnId), rtrs);
433 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, bgpVpnId, create);
437 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
438 addOrDelDefaultFibRouteForSNAT(routerName, create);
441 private void addOrDelDefaultFibRouteForSNAT(String routerName, boolean create) {
442 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
443 if (switches == null || switches.isEmpty()) {
444 LOG.debug("No switches found for router {}", routerName);
447 long routerId = NatUtil.readVpnId(dataBroker, routerName);
448 if (routerId == NatConstants.INVALID_ID) {
449 LOG.error("Could not retrieve router Id for {} to program default NAT route in FIB", routerName);
452 for (BigInteger dpnId : switches) {
454 LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} for the internal vpn",
456 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
458 LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} for the internal vpn",
460 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
465 private void addOrDelDefaultFibRouteForSnatWithBgpVpn(String routerName, long bgpVpnId, boolean create) {
466 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
467 if (dpnIds == null || dpnIds.isEmpty()) {
468 LOG.debug("NAT Service : Current no dpns part of router {} to program default NAT route", routerName);
471 long routerId = NatUtil.getVpnId(dataBroker, routerName);
472 for (BigInteger dpnId : dpnIds) {
474 if (bgpVpnId != NatConstants.INVALID_ID) {
475 LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} "
476 + "for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
477 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
479 LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} "
480 + "for the internal vpn", routerId, dpnId);
481 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
484 if (bgpVpnId != NatConstants.INVALID_ID) {
485 LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} "
486 + "for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
487 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
489 LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} "
490 + "for the internal vpn", routerId, dpnId);
491 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
497 // TODO Clean up the exception handling
498 @SuppressWarnings("checkstyle:IllegalCatch")
499 public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
500 InstanceIdentifier<T> path) {
501 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
504 return tx.read(datastoreType, path).get();
505 } catch (Exception e) {
506 throw new RuntimeException(e);
510 // TODO Clean up the exception handling
511 @SuppressWarnings("checkstyle:IllegalCatch")
513 public void close() {
514 if (listenerRegistration != null) {
516 listenerRegistration.close();
517 } catch (final Exception e) {
518 LOG.error("Error when cleaning up ExternalRoutersListener.", e);
521 listenerRegistration = null;
523 LOG.debug("ExternalRoutersListener Closed");
526 protected void installOutboundMissEntry(String routerName, BigInteger primarySwitchId) {
527 long routerId = NatUtil.getVpnId(dataBroker, routerName);
528 LOG.debug("NAT Service : Router ID from getVpnId {}", routerId);
529 if (routerId != NatConstants.INVALID_ID) {
530 LOG.debug("NAT Service : Creating miss entry on primary {}, for router {}", primarySwitchId, routerId);
531 createOutboundTblEntry(primarySwitchId, routerId);
533 LOG.error("NAT Service : Unable to fetch Router Id for RouterName {}, failed to "
534 + "createAndInstallMissEntry", routerName);
538 public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID) {
539 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
540 .FLOWID_SEPARATOR + routerID;
543 private String getFlowRefNaptFib(BigInteger dpnId, short tableId, long routerID, String externalIp) {
544 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
545 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + externalIp;
548 public BigInteger getCookieOutboundFlow(long routerId) {
549 return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
550 BigInteger.valueOf(routerId));
553 protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId) {
554 LOG.debug("NAT Service : buildOutboundFlowEntity called for dpId {} and routerId{}", dpId, routerId);
555 List<MatchInfo> matches = new ArrayList<>();
556 matches.add(MatchEthernetType.IPV4);
557 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
559 List<InstructionInfo> instructions = new ArrayList<>();
560 List<ActionInfo> actionsInfos = new ArrayList<>();
561 actionsInfos.add(new ActionPuntToController());
562 instructions.add(new InstructionApplyActions(actionsInfos));
563 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
564 MetaDataUtil.METADATA_MASK_VRFID));
566 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
567 BigInteger cookie = getCookieOutboundFlow(routerId);
568 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
570 cookie, matches, instructions);
571 LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
575 public void createOutboundTblEntry(BigInteger dpnId, long routerId) {
576 LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}", dpnId, routerId);
577 FlowEntity flowEntity = buildOutboundFlowEntity(dpnId, routerId);
578 LOG.debug("NAT Service : Installing flow {}", flowEntity);
579 mdsalManager.installFlow(flowEntity);
582 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
583 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
584 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
586 Future<RpcResult<GetTunnelInterfaceNameOutput>> result =
587 itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
588 .setSourceDpid(srcDpId)
589 .setDestinationDpid(dstDpId)
590 .setTunnelType(tunType)
592 rpcResult = result.get();
593 if (!rpcResult.isSuccessful()) {
594 tunType = TunnelTypeGre.class;
595 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
596 .setSourceDpid(srcDpId)
597 .setDestinationDpid(dstDpId)
598 .setTunnelType(tunType)
600 rpcResult = result.get();
601 if (!rpcResult.isSuccessful()) {
602 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
604 return rpcResult.getResult().getInterfaceName();
606 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
608 return rpcResult.getResult().getInterfaceName();
610 } catch (InterruptedException | ExecutionException | NullPointerException e) {
611 LOG.warn("NAT Service : Exception when getting tunnel interface Id for tunnel between {} and {}",
618 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName) {
619 LOG.debug("NAT Service : installSnatMissEntry called for for the primary NAPT switch dpnId {} ", dpnId);
620 // Install miss entry pointing to group
621 FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName);
622 mdsalManager.installFlow(flowEntity);
625 protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
626 LOG.debug("NAT Service : installSnatMissEntry called for dpnId {} with primaryBucket {} ",
627 dpnId, bucketInfo.get(0));
628 // Install the select group
629 long groupId = createGroupId(getGroupIdKey(routerName));
630 GroupEntity groupEntity =
631 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
632 LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
633 mdsalManager.syncInstallGroup(groupEntity, 0);
634 // Install miss entry pointing to group
635 FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, groupId);
636 if (flowEntity == null) {
637 LOG.error("NAT Service : Flow entity received as NULL. "
638 + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
639 + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
642 mdsalManager.installFlow(flowEntity);
645 long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo) {
646 long groupId = createGroupId(getGroupIdKey(routerName));
647 GroupEntity groupEntity =
648 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
649 LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
650 mdsalManager.syncInstallGroup(groupEntity, 0);
654 public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId) {
655 LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
656 dpId, routerName, groupId);
657 long routerId = NatUtil.getVpnId(dataBroker, routerName);
658 List<MatchInfo> matches = new ArrayList<>();
659 matches.add(MatchEthernetType.IPV4);
660 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
662 List<ActionInfo> actionsInfo = new ArrayList<>();
663 long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
664 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
665 LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
666 actionsInfo.add(new ActionGroup(groupId));
667 List<InstructionInfo> instructions = new ArrayList<>();
668 instructions.add(new InstructionApplyActions(actionsInfo));
669 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
670 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
671 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
672 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
674 LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
678 public FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName) {
680 LOG.debug("NAT Service : buildSnatFlowEntity is called for primary NAPT switch dpId {}, routerName {}", dpId,
682 long routerId = NatUtil.getVpnId(dataBroker, routerName);
683 List<MatchInfo> matches = new ArrayList<>();
684 matches.add(MatchEthernetType.IPV4);
685 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
687 List<InstructionInfo> instructions = new ArrayList<>();
688 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
690 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
691 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
692 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
693 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
695 LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
699 // TODO : Replace this with ITM Rpc once its available with full functionality
700 protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName) {
701 LOG.debug("NAT Service : creating entry for Terminating Service Table for switch {}, routerName {}",
703 FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName);
704 if (flowEntity == null) {
705 LOG.error("NAT Service : Flow entity received as NULL. "
706 + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
707 + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
711 mdsalManager.installFlow(flowEntity);
715 private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName) {
716 long routerId = NatUtil.getVpnId(dataBroker, routerName);
717 List<MatchInfo> matches = new ArrayList<>();
718 matches.add(MatchEthernetType.IPV4);
719 long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
720 matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
721 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
723 List<InstructionInfo> instructions = new ArrayList<>();
724 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
725 MetaDataUtil.METADATA_MASK_VRFID));
726 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
727 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
728 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
733 public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
734 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
735 .FLOWID_SEPARATOR + routerID;
738 public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
739 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
740 .FLOWID_SEPARATOR + routerID;
743 private String getGroupIdKey(String routerName) {
744 return "snatmiss." + routerName;
747 protected long createGroupId(String groupIdKey) {
748 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
749 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
752 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
753 RpcResult<AllocateIdOutput> rpcResult = result.get();
754 return rpcResult.getResult().getIdValue();
755 } catch (NullPointerException | InterruptedException | ExecutionException e) {
761 protected void createGroupIdPool() {
762 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
763 .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
764 .setLow(NatConstants.SNAT_ID_LOW_VALUE)
765 .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
768 Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
769 if ((result != null) && (result.get().isSuccessful())) {
770 LOG.debug("NAT Service : Created GroupIdPool");
772 LOG.error("NAT Service : Unable to create GroupIdPool");
774 } catch (InterruptedException | ExecutionException e) {
775 LOG.error("Failed to create PortPool for NAPT Service", e);
779 protected void handleSwitches(BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
780 LOG.debug("NAT Service : Installing SNAT miss entry in switch {}", dpnId);
781 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
782 String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
783 List<BucketInfo> listBucketInfo = new ArrayList<>();
784 long routerId = NatUtil.getVpnId(dataBroker, routerName);
786 if (ifNamePrimary != null) {
787 LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
788 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(interfaceManager, ifNamePrimary, routerId);
790 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
792 listBucketInfo.add(0, bucketPrimary);
793 installSnatMissEntry(dpnId, listBucketInfo, routerName);
796 List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
797 BigInteger primarySwitchId, String routerName) {
798 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
799 String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
800 List<BucketInfo> listBucketInfo = new ArrayList<>();
801 long routerId = NatUtil.getVpnId(dataBroker, routerName);
803 if (ifNamePrimary != null) {
804 LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
805 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(interfaceManager, ifNamePrimary, routerId);
807 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
809 listBucketInfo.add(0, bucketPrimary);
810 return listBucketInfo;
813 protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName) {
815 * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
818 LOG.debug("NAT Service : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
821 List<BucketInfo> listBucketInfo = new ArrayList<>();
822 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
823 listActionInfoPrimary.add(new ActionNxResubmit(NatConstants.TERMINATING_SERVICE_TABLE));
824 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
825 listBucketInfo.add(0, bucketPrimary);
828 long routerId = NatUtil.getVpnId(dataBroker, routerName);
830 installSnatMissEntryForPrimrySwch(dpnId, routerName);
831 installTerminatingServiceTblEntry(dpnId, routerName);
832 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
833 installNaptPfibEntry(dpnId, routerId);
834 Long vpnId = NatUtil.getVpnId(dataBroker, routerName);
835 installNaptPfibEntriesForExternalSubnets(routerName, dpnId);
836 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
837 if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
838 installNaptPfibEntry(dpnId, vpnId);
842 List<BucketInfo> getBucketInfoForPrimaryNaptSwitch() {
843 List<BucketInfo> listBucketInfo = new ArrayList<>();
844 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
845 listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
846 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
847 listBucketInfo.add(0, bucketPrimary);
848 return listBucketInfo;
851 public void installNaptPfibEntry(BigInteger dpnId, long segmentId) {
852 LOG.debug("NAT Service : installNaptPfibEntry called for dpnId {} and segmentId {} ", dpnId, segmentId);
853 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
854 mdsalManager.installFlow(naptPfibFlowEntity);
857 public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
859 LOG.debug("NAT Service : buildNaptPfibFlowEntity is called for dpId {}, segmentId {}", dpId, segmentId);
860 List<MatchInfo> matches = new ArrayList<>();
861 matches.add(MatchEthernetType.IPV4);
862 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
864 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
865 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
866 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
867 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
868 instructionInfo.add(new InstructionApplyActions(listActionInfo));
870 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
871 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
872 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
873 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
874 LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
878 private void handleSnatReverseTraffic(BigInteger dpnId, Routers router, long routerId, String routerName,
880 LOG.debug("NAT Service : handleSnatReverseTraffic() entry for DPN ID, routerId, externalIp: {}",
881 dpnId, routerId, externalIp);
882 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
883 if (networkId == null) {
884 LOG.error("NAT Service : networkId is null for the router ID {}", routerId);
887 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
888 if (vpnName == null) {
889 LOG.error("NAT Service : No VPN associated with ext nw {} to handle add external ip "
890 + "configuration {} in router {}",
891 networkId, externalIp, routerId);
894 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
895 externalIp, router, vpnService, fibService, bgpManager, dataBroker, LOG);
896 LOG.debug("NAT Service : handleSnatReverseTraffic() exit for DPN ID, routerId, externalIp : {}",
897 dpnId, routerId, externalIp);
900 public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
901 final long routerId, final String routerName, final String externalIp,
902 final Routers router, VpnRpcService vpnService,
903 final FibRpcService fibService, final IBgpManager bgpManager,
904 final DataBroker dataBroker, final Logger log) {
905 LOG.debug("NAT Service : advToBgpAndInstallFibAndTsFlows() entry for DPN ID {}, tableId {}, vpnname {} "
906 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
907 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
908 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
909 if (rd == null || rd.isEmpty()) {
910 LOG.error("NAT Service : Unable to get RD for VPN Name {}", vpnName);
913 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName);
914 if (extNwProvType == null) {
917 if (extNwProvType == ProviderTypes.VXLAN) {
918 WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
919 evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
920 nextHopIp, writeTx, routerId);
923 //Generate VPN label for the external IP
924 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
925 .setIpPrefix(externalIp).build();
926 Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
928 //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
929 ListenableFuture<RpcResult<Void>> future =
930 Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture),
931 (AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>) result -> {
932 if (result.isSuccessful()) {
933 LOG.debug("NAT Service : inside apply with result success");
934 GenerateVpnLabelOutput output = result.getResult();
935 final long label = output.getLabel();
937 int externalIpInDsFlag = 0;
938 //Get IPMaps from the DB for the router ID
939 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
940 if (dbIpMaps != null) {
941 for (IpMap dbIpMap : dbIpMaps) {
942 String dbExternalIp = dbIpMap.getExternalIp();
943 //Select the IPMap, whose external IP is the IP for which FIB is installed
944 if (dbExternalIp.contains(externalIp)) {
945 String dbInternalIp = dbIpMap.getInternalIp();
946 IpMapKey dbIpMapKey = dbIpMap.getKey();
947 LOG.debug("Setting label {} for internalIp {} and externalIp {}",
948 label, dbInternalIp, externalIp);
949 IpMap newIpm = new IpMapBuilder().setKey(dbIpMapKey).setInternalIp(dbInternalIp)
950 .setExternalIp(dbExternalIp).setLabel(label).build();
951 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
952 naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
953 externalIpInDsFlag++;
956 if (externalIpInDsFlag <= 0) {
957 LOG.debug("NAT Service : External Ip {} not found in DS, Failed to update label {} "
958 + "for routerId {} in DS", externalIp, label, routerId);
959 String errMsg = String.format("Failed to update label %s due to external Ip %s not"
960 + " found in DS for router %s", label, externalIp, routerId);
961 return Futures.immediateFailedFuture(new Exception(errMsg));
964 LOG.error("NAT Service : Failed to write label {} for externalIp {} for "
965 + "routerId {} in DS", label, externalIp, routerId);
968 Routers extRouter = router != null ? router :
969 NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
970 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(dataBroker, externalIp,
972 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, externalSubnetId,
973 externalIp, nextHopIp, router.getNetworkId().getValue(), null, label, log,
974 RouteOrigin.STATIC, dpnId);
976 //Install custom FIB routes
977 List<Instruction> tunnelTableCustomInstructions = new ArrayList<>();
978 tunnelTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
979 makeTunnelTableEntry(dpnId, label, tunnelTableCustomInstructions);
980 makeLFibTableEntry(dpnId, label, tableId);
982 //Install custom FIB routes - FIB table.
983 List<Instruction> fibTableCustomInstructions = createFibTableCustomInstructions(dataBroker,
984 tableId, routerName, externalIp);
985 String fibExternalIp = externalIp.contains("/32") ? externalIp : (externalIp + "/32");
986 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
987 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
988 .setInstruction(fibTableCustomInstructions).build();
989 Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
990 return JdkFutureAdapters.listenInPoolThread(future1);
992 LOG.error("NAT Service : inside apply with result failed");
993 String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
994 externalIp, vpnName, result.getErrors());
995 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
999 Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
1002 public void onFailure(Throwable error) {
1003 log.error("NAT Service : Error in generate label or fib install process", error);
1007 public void onSuccess(RpcResult<Void> result) {
1008 if (result.isSuccessful()) {
1009 log.info("NAT Service : Successfully installed custom FIB routes for prefix {}", externalIp);
1011 log.error("NAT Service : Error in rpc call to create custom Fib entries for prefix {} in "
1012 + "DPN {}, {}", externalIp, dpnId, result.getErrors());
1018 private List<Instruction> createFibTableCustomInstructions(DataBroker dataBroker, short tableId,
1019 String routerName, String externalIp) {
1020 List<Instruction> fibTableCustomInstructions = new ArrayList<>();
1021 Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1022 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
1023 externalIp, router);
1024 int instructionIndex = 0;
1025 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
1026 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
1027 fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
1028 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
1032 fibTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(instructionIndex));
1033 return fibTableCustomInstructions;
1036 private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId) {
1037 List<MatchInfo> matches = new ArrayList<>();
1038 matches.add(MatchEthernetType.MPLS_UNICAST);
1039 matches.add(new MatchMplsLabel(serviceId));
1041 List<Instruction> instructions = new ArrayList<>();
1042 List<ActionInfo> actionsInfos = new ArrayList<>();
1043 actionsInfos.add(new ActionPopMpls());
1044 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
1045 instructions.add(writeInstruction);
1046 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
1048 // Install the flow entry in L3_LFIB_TABLE
1049 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1051 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1053 COOKIE_VM_LFIB_TABLE, matches, instructions);
1055 mdsalManager.installFlow(dpId, flowEntity);
1057 LOG.debug("NAT Service : LFIB Entry for dpID {} : label : {} modified successfully {}", dpId, serviceId);
1060 private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
1061 List<MatchInfo> mkMatches = new ArrayList<>();
1063 LOG.debug("NAT Service : Create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
1066 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
1068 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1069 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5,
1070 String.format("%s:%d", "TST Flow Entry ", serviceId),
1071 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1073 mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
1076 protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1077 InstanceIdentifier<RouterIds> id = InstanceIdentifier.builder(
1078 RouterIdName.class).child(RouterIds.class, new RouterIdsKey(routerId)).build();
1082 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1083 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
1084 .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
1088 protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1089 String routerName = original.getRouterName();
1090 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1091 if (routerId == NatConstants.INVALID_ID) {
1092 LOG.error("NAT Service : Update external router event - Invalid routerId for routerName {}", routerName);
1095 BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1096 Uuid networkId = original.getNetworkId();
1098 // Check if its update on SNAT flag
1099 boolean originalSNATEnabled = original.isEnableSnat();
1100 boolean updatedSNATEnabled = update.isEnableSnat();
1101 LOG.debug("NAT Service : update of externalRoutersListener called with originalFlag and updatedFlag "
1102 + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
1103 if (originalSNATEnabled != updatedSNATEnabled) {
1104 if (originalSNATEnabled) {
1105 //SNAT disabled for the router
1106 Uuid networkUuid = original.getNetworkId();
1107 LOG.info("NAT Service : SNAT disabled for Router {}", routerName);
1108 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1109 handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId);
1111 // Allocate Primary Napt Switch for existing router
1112 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName, routerId);
1113 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
1114 LOG.error("NAT Service: Failed to get or allocated NAPT switch in ExternalRouterListener.Update()");
1117 LOG.info("NAT Service : SNAT enabled for Router {}", original.getRouterName());
1118 handleEnableSnat(original, routerId, primarySwitchId);
1122 if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1123 handleRouterGwFlows(original, dpnId, NwConstants.DEL_FLOW);
1124 handleRouterGwFlows(update, dpnId, NwConstants.ADD_FLOW);
1127 //Check if the Update is on External IPs
1128 LOG.debug("NAT Service : Checking if this is update on External IPs");
1129 List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
1130 List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
1132 //Check if the External IPs are added during the update.
1133 Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
1134 addedExternalIps.removeAll(originalExternalIps);
1135 if (addedExternalIps.size() != 0) {
1136 LOG.debug("NAT Service : Start processing of the External IPs addition during the update operation");
1137 vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
1138 update.getExtGwMacAddress(), dpnId,
1139 update.getNetworkId(), null, NwConstants.ADD_FLOW);
1141 for (String addedExternalIp : addedExternalIps) {
1143 1) Do nothing in the IntExtIp model.
1144 2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1146 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1147 String externalIp = externalIpParts[0];
1148 String externalIpPrefix = externalIpParts[1];
1149 String externalpStr = externalIp + "/" + externalIpPrefix;
1150 LOG.debug("NAT Service : Initialise the count mapping of the external IP {} for the "
1151 + "router ID {} in the ExternalIpsCounter model.",
1152 externalpStr, routerId);
1153 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1155 LOG.debug("NAT Service : End processing of the External IPs addition during the update operation");
1158 //Check if the External IPs are removed during the update.
1159 Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
1160 removedExternalIps.removeAll(updatedExternalIps);
1161 if (removedExternalIps.size() > 0) {
1162 LOG.debug("NAT Service : Start processing of the External IPs removal during the update operation");
1163 vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerName,
1164 removedExternalIps, original.getExtGwMacAddress(),
1165 dpnId, networkId, null, NwConstants.DEL_FLOW);
1167 for (String removedExternalIp : removedExternalIps) {
1169 1) Remove the mappings in the IntExt IP model which has external IP.
1170 2) Remove the external IP in the ExternalCounter model.
1171 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the least
1173 Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1174 4) Increase the count of the allocated external IP by one.
1175 5) Advertise to the BGP if external IP is allocated for the first time for the router
1176 i.e. the route for the external IP is absent.
1177 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for
1178 the removed external IPs and also from the model.
1179 7) Advertise to the BGP for removing the route for the removed external IPs.
1182 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1183 String externalIp = externalIpParts[0];
1184 String externalIpPrefix = externalIpParts[1];
1185 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1187 LOG.debug("NAT Service : Clear the routes from the BGP and remove the FIB and TS "
1188 + "entries for removed external IP {}", externalIpAddrStr);
1189 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1190 String vpnName = "";
1191 if (vpnUuId != null) {
1192 vpnName = vpnUuId.getValue();
1194 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName);
1196 LOG.debug("NAT Service : Remove the mappings in the IntExtIP model which has external IP.");
1197 //Get the internal IPs which are associated to the removed external IPs
1198 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1199 List<String> removedInternalIps = new ArrayList<>();
1200 for (IpMap ipMap : ipMaps) {
1201 if (ipMap.getExternalIp().equals(externalIpAddrStr)) {
1202 removedInternalIps.add(ipMap.getInternalIp());
1206 LOG.debug("Remove the mappings of the internal IPs from the IntExtIP model.");
1207 for (String removedInternalIp : removedInternalIps) {
1208 LOG.debug("NAT Service : Remove the IP mapping of the internal IP {} for the "
1209 + "router ID {} from the IntExtIP model",
1210 removedInternalIp, routerId);
1211 naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1214 LOG.debug("NAT Service : Remove the count mapping of the external IP {} for the "
1215 + "router ID {} from the ExternalIpsCounter model.",
1216 externalIpAddrStr, routerId);
1217 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1219 LOG.debug("NAT Service : Allocate the least loaded external IPs to the subnets "
1220 + "whose external IPs were removed.");
1221 for (String removedInternalIp : removedInternalIps) {
1222 allocateExternalIp(dpnId, update, routerId, routerName, networkId, removedInternalIp);
1225 LOG.debug("NAT Service : Remove the NAPT translation entries from "
1226 + "Inbound and Outbound NAPT tables for the removed external IPs.");
1227 //Get the internalIP and internal Port which were associated to the removed external IP.
1228 List<Integer> externalPorts = new ArrayList<>();
1229 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1230 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier.builder(IntextIpPortMap.class)
1231 .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1232 Optional<IpPortMapping> ipPortMapping =
1233 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1234 if (ipPortMapping.isPresent()) {
1235 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get().getIntextIpProtocolType();
1236 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1237 ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1238 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1239 for (IpPortMap ipPortMap : ipPortMaps) {
1240 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1241 if (ipPortExternal.getIpAddress().equals(externalIp)) {
1242 externalPorts.add(ipPortExternal.getPortNum());
1243 List<String> removedInternalIpPorts = protoTypesIntIpPortsMap.get(protoType);
1244 if (removedInternalIpPorts != null) {
1245 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1246 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1248 removedInternalIpPorts = new ArrayList<>();
1249 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1250 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1257 //Remove the IP port map from the intext-ip-port-map model, which were containing
1258 // the removed external IP.
1259 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts = protoTypesIntIpPortsMap.entrySet();
1260 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1261 for (Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts) {
1262 ProtocolTypes protocolType = (ProtocolTypes) protoTypesIntIpPort.getKey();
1263 List<String> removedInternalIpPorts = (List<String>) protoTypesIntIpPort.getValue();
1264 for (String removedInternalIpPort : removedInternalIpPorts) {
1265 // Remove the IP port map from the intext-ip-port-map model,
1266 // which were containing the removed external IP
1267 naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort, protocolType);
1268 //Remove the IP port incomint packer map.
1269 naptPacketInHandler.removeIncomingPacketMap(removedInternalIpPort);
1270 String[] removedInternalIpPortParts = removedInternalIpPort.split(":");
1271 if (removedInternalIpPortParts.length == 2) {
1272 String removedInternalIp = removedInternalIpPortParts[0];
1273 String removedInternalPort = removedInternalIpPortParts[1];
1274 List<String> removedInternalPortsList = internalIpPortMap.get(removedInternalPort);
1275 if (removedInternalPortsList != null) {
1276 removedInternalPortsList.add(removedInternalPort);
1277 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1279 removedInternalPortsList = new ArrayList<>();
1280 removedInternalPortsList.add(removedInternalPort);
1281 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1287 // Delete the entry from SnatIntIpPortMap DS
1288 Set<String> internalIps = internalIpPortMap.keySet();
1289 for (String internalIp : internalIps) {
1290 LOG.debug("NAT Service : Removing IpPort having the internal IP {} from the "
1291 + "model SnatIntIpPortMap", internalIp);
1292 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1295 naptManager.removeNaptPortPool(externalIp);
1297 LOG.debug("Remove the NAPT translation entries from Inbound NAPT tables for the removed "
1298 + "external IP {}", externalIp);
1299 for (Integer externalPort : externalPorts) {
1300 //Remove the NAPT translation entries from Inbound NAPT table
1301 naptEventHandler.removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1302 routerId, externalIp, externalPort);
1305 Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
1306 for (Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
1307 String internalIp = internalIpPort.getKey();
1308 LOG.debug("Remove the NAPT translation entries from Outbound NAPT tables for "
1309 + "the removed internal IP {}", internalIp);
1310 List<String> internalPorts = internalIpPort.getValue();
1311 for (String internalPort : internalPorts) {
1312 //Remove the NAPT translation entries from Outbound NAPT table
1313 naptEventHandler.removeNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1314 routerId, internalIp, Integer.valueOf(internalPort));
1318 LOG.debug("NAT Service : End processing of the External IPs removal during the update operation");
1321 //Check if its Update on subnets
1322 LOG.debug("NAT Service : Checking if this is update on subnets");
1323 List<Uuid> originalSubnetIds = original.getSubnetIds();
1324 List<Uuid> updatedSubnetIds = update.getSubnetIds();
1325 Set<Uuid> addedSubnetIds = new HashSet<>(updatedSubnetIds);
1326 addedSubnetIds.removeAll(originalSubnetIds);
1328 //Check if the Subnet IDs are added during the update.
1329 if (addedSubnetIds.size() != 0) {
1330 LOG.debug("NAT Service : Start processing of the Subnet IDs addition during the update operation");
1331 for (Uuid addedSubnetId : addedSubnetIds) {
1333 1) Select the least loaded external IP for the subnet and store the mapping of the
1334 subnet IP and the external IP in the IntExtIp model.
1335 2) Increase the count of the selected external IP by one.
1336 3) Advertise to the BGP if external IP is allocated for the first time for the
1337 router i.e. the route for the external IP is absent.
1339 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1340 if (subnetIp != null) {
1341 allocateExternalIp(dpnId, update, routerId, routerName, networkId, subnetIp);
1344 LOG.debug("NAT Service : End processing of the Subnet IDs addition during the update operation");
1347 //Check if the Subnet IDs are removed during the update.
1348 Set<Uuid> removedSubnetIds = new HashSet<>(originalSubnetIds);
1349 removedSubnetIds.removeAll(updatedSubnetIds);
1350 if (removedSubnetIds.size() != 0) {
1351 LOG.debug("NAT Service : Start processing of the Subnet IDs removal during the update operation");
1352 for (Uuid removedSubnetId : removedSubnetIds) {
1353 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1354 if (subnetAddr != null) {
1356 1) Remove the subnet IP and the external IP in the IntExtIp map
1357 2) Decrease the count of the coresponding external IP by one.
1358 3) Advertise to the BGP for removing the routes of the corresponding external
1359 IP if its not allocated to any other internal IP.
1363 naptManager.getExternalIpAllocatedForSubnet(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1364 if (externalIp == null) {
1365 LOG.debug("No mapping found for router ID {} and internal IP {}", routerId, subnetAddr[0]);
1369 naptManager.updateCounter(routerId, externalIp, false);
1370 // Traverse entire model of external-ip counter whether external ip is not
1371 // used by any other internal ip in any router
1372 if (!isExternalIpAllocated(externalIp)) {
1373 LOG.debug("NAT Service : external ip is not allocated to any other "
1374 + "internal IP so proceeding to remove routes");
1375 List<String> externalIps = new ArrayList<>();
1376 externalIps.add(externalIp);
1377 clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId, externalIps, null);
1378 LOG.debug("Successfully removed fib entries in switch {} for "
1379 + "router {} with networkId {} and externalIps {}",
1380 dpnId, routerId, networkId, externalIps);
1383 LOG.debug("NAT Service : Remove the IP mapping for the router ID {} and "
1384 + "internal IP {} external IP {}", routerId, subnetAddr[0], externalIp);
1385 naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1388 LOG.debug("NAT Service : End processing of the Subnet IDs removal during the update operation");
1392 private boolean isExternalIpAllocated(String externalIp) {
1393 InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1394 Optional<ExternalIpsCounter> externalCountersData =
1395 MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1396 if (externalCountersData.isPresent()) {
1397 ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1398 List<ExternalCounters> externalCounters = externalIpsCounters.getExternalCounters();
1399 for (ExternalCounters ext : externalCounters) {
1400 for (ExternalIpCounter externalIpCount : ext.getExternalIpCounter()) {
1401 if (externalIpCount.getExternalIp().equals(externalIp)) {
1402 if (externalIpCount.getCounter() != 0) {
1413 private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
1414 Uuid networkId, String subnetIp) {
1415 String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1417 InetAddress address = InetAddress.getByName(subnetIpParts[0]);
1418 if (address instanceof Inet6Address) {
1419 // TODO: Revisit when IPv6 external connectivity support is added.
1420 LOG.debug("Currently skipping ipv6 address {}.", address);
1423 } catch (UnknownHostException e) {
1424 LOG.warn("Invalid ip address {}", subnetIpParts[0], e);
1427 String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1428 if (leastLoadedExtIpAddr != null) {
1429 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1430 String leastLoadedExtIp = externalIpParts[0];
1431 String leastLoadedExtIpPrefix = externalIpParts[1];
1432 IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1433 subnetIp = subnetIpParts[0];
1434 String subnetIpPrefix = subnetIpParts[1];
1435 IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1436 LOG.debug("NAT Service : Add the IP mapping for the router ID {} and internal "
1437 + "IP {} and prefix {} -> external IP {} and prefix {}",
1438 routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1439 naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1442 // Check if external IP is already assigned a route. (i.e. External IP is previously
1443 // allocated to any of the subnets)
1444 // If external IP is already assigned a route, (, do not re-advertise to the BGP
1445 String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1446 Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1447 if (label != null) {
1449 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1450 IpMapKey ipMapKey = new IpMapKey(internalIp);
1451 LOG.debug("Setting label {} for internalIp {} and externalIp {}",
1452 label, internalIp, leastLoadedExtIpAddrStr);
1453 IpMap newIpm = new IpMapBuilder().setKey(ipMapKey).setInternalIp(internalIp)
1454 .setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1455 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1456 naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1460 // Re-advertise to the BGP for the external IP, which is allocated to the subnet
1461 // for the first time and hence not having a route.
1462 //Get the VPN Name using the network ID
1463 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
1464 if (vpnName != null) {
1465 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkId);
1466 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1467 LOG.debug("Best effort for getting primary napt switch when router i/f are"
1468 + "added after gateway-set");
1469 dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1471 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1472 leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, router,
1473 vpnService, fibService, bgpManager, dataBroker, LOG);
1478 protected Long checkExternalIpLabel(long routerId, String externalIp) {
1479 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1480 for (IpMap ipMap : ipMaps) {
1481 if (ipMap.getExternalIp().equals(externalIp)) {
1482 if (ipMap.getLabel() != null) {
1483 return ipMap.getLabel();
1491 protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1492 LOG.trace("NAT Service : Router delete method");
1495 ROUTER DELETE SCENARIO
1496 1) Get the router ID from the event.
1497 2) Build the cookie information from the router ID.
1498 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1499 4) Build the flow with the cookie value.
1500 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1501 6) Remove the flows from the other switches which points to the primary and secondary
1502 switches for the flows related the router ID.
1503 7) Get the list of external IP address maintained for the router ID.
1504 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1505 9) Withdraw the corresponding routes from the BGP.
1508 if (identifier == null || router == null) {
1509 LOG.info("++++++++++++++NAT Service : ExternalRoutersListener:remove:: "
1510 + "returning without processing since routers is null");
1514 String routerName = router.getRouterName();
1515 LOG.info("Removing default NAT route from FIB on all dpns part of router {} ", routerName);
1516 addOrDelDefFibRouteToSNAT(routerName, false);
1517 Uuid networkUuid = router.getNetworkId();
1518 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1519 if (routerId == NatConstants.INVALID_ID) {
1520 LOG.error("NAT Service : Remove external router event - Invalid routerId for routerName {}",
1525 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1526 handleRouterGwFlows(router, primarySwitchId, NwConstants.DEL_FLOW);
1527 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1528 handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId);
1532 private void handleRouterGwFlows(Routers router, BigInteger primarySwitchId, int addOrRemove) {
1533 WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
1534 vpnManager.setupRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
1535 router.getNetworkId(), writeTx, addOrRemove);
1536 vpnManager.setupArpResponderFlowsToExternalNetworkIps(router.getRouterName(),
1537 NatUtil.getIpsListFromExternalIps(router.getExternalIps()),
1538 router.getExtGwMacAddress(), primarySwitchId, router.getNetworkId(), writeTx, addOrRemove);
1542 // TODO Clean up the exception handling
1543 @SuppressWarnings("checkstyle:IllegalCatch")
1544 public void handleDisableSnat(Routers router, Uuid networkUuid, List<String> externalIps, boolean routerFlag,
1545 String vpnId, BigInteger naptSwitchDpnId) {
1546 LOG.info("NAT Service : handleDisableSnat() Entry");
1547 String routerName = router.getRouterName();
1549 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1550 // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
1551 // for the router ID.
1552 LOG.debug("NAT Service : Remove the Internal to external IP address maintained for the "
1553 + "router ID {} in the DS", routerId);
1554 naptManager.removeMapping(routerId);
1557 removeNaptSwitch(routerName);
1559 updateNaptSwitch(routerName, BigInteger.ZERO);
1562 LOG.debug("NAT Service : Remove the ExternalCounter model for the router ID {}", routerId);
1563 naptManager.removeExternalCounter(routerId);
1565 LOG.debug("NAT Service : got primarySwitch as dpnId {}", naptSwitchDpnId);
1566 if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
1567 LOG.error("NAT Service : Unable to retrieve the primary NAPT switch for the "
1568 + "router ID {} from RouterNaptSwitch model", routerId);
1571 removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId, externalIps);
1572 removeFlowsFromNonActiveSwitches(routerName, naptSwitchDpnId, networkUuid);
1574 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1575 } catch (Exception ex) {
1576 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}",
1577 routerId, naptSwitchDpnId, ex);
1580 } catch (Exception ex) {
1581 LOG.error("Exception while handling disableSNAT : {}", ex);
1583 LOG.info("NAT Service : handleDisableSnat() Exit");
1586 // TODO Clean up the exception handling
1587 @SuppressWarnings("checkstyle:IllegalCatch")
1588 public void handleDisableSnatInternetVpn(String routerName, Uuid networkUuid, List<String> externalIps,
1589 boolean routerFlag, String vpnId) {
1590 LOG.debug("NAT Service : handleDisableSnatInternetVpn() Entry");
1592 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1593 BigInteger naptSwitchDpnId = null;
1594 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
1595 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1596 Optional<RouterToNaptSwitch> rtrToNapt =
1597 read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1598 if (rtrToNapt.isPresent()) {
1599 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1601 LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1603 removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId);
1605 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1606 } catch (Exception ex) {
1607 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}",
1608 routerId, naptSwitchDpnId, ex);
1610 } catch (Exception ex) {
1611 LOG.error("Exception while handling disableSNATInternetVpn : {}", ex);
1613 LOG.debug("NAT Service : handleDisableSnatInternetVpn() Exit");
1616 // TODO Clean up the exception handling
1617 @SuppressWarnings("checkstyle:IllegalCatch")
1618 public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1619 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
1620 .setPrimarySwitchId(naptSwitchId).build();
1622 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1623 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1624 } catch (Exception ex) {
1625 LOG.error("Failed to write naptSwitch {} for router {} in ds",
1626 naptSwitchId, routerName);
1628 LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
1629 naptSwitchId, routerName);
1632 protected void removeNaptSwitch(String routerName) {
1633 // Remove router and switch from model
1634 InstanceIdentifier<RouterToNaptSwitch> id =
1635 InstanceIdentifier.builder(NaptSwitches.class)
1636 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1637 LOG.debug("NAPT Service : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1638 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1639 //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
1640 NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
1643 public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
1644 BigInteger dpnId, Uuid networkId, String vpnName,
1645 List<String> externalIps) {
1646 LOG.debug("NAT Service : Remove NAPT flows from Active switch");
1647 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1649 //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1650 // traffic which comes from the VMs of the NAPT switches)
1651 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1652 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1654 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1655 NwConstants.PSNAT_TABLE, dpnId, routerId);
1656 mdsalManager.removeFlow(preSnatFlowEntity);
1658 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1659 // traffic which comes from the VMs of the non NAPT switches)
1660 long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
1661 String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
1662 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1663 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1664 NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
1665 mdsalManager.removeFlow(tsNatFlowEntity);
1667 //Remove the Outbound flow entry which forwards the packet to FIB Table
1668 String outboundNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
1669 FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1670 outboundNatFlowRef);
1672 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1673 NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1674 mdsalManager.removeFlow(outboundNatFlowEntity);
1676 removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps);
1678 //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1679 String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1680 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1682 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1683 NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
1684 mdsalManager.removeFlow(natPfibFlowEntity);
1686 // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
1687 // - This does not work since ext-routers is deleted already - no network info
1688 //Get the VPN ID from the ExternalNetworks model
1690 if ((vpnName == null) || (vpnName.isEmpty())) {
1691 // ie called from router delete cases
1692 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1693 LOG.debug("NAT Service : vpnUuid is {}", vpnUuid);
1694 if (vpnUuid != null) {
1695 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1696 LOG.debug("NAT Service : vpnId for routerdelete or disableSNAT scenario {}", vpnId);
1699 // ie called from disassociate vpn case
1700 LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1701 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1702 LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId);
1705 if (vpnId != NatConstants.INVALID_ID) {
1706 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1707 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
1708 FlowEntity natPfibVpnFlowEntity =
1709 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1710 LOG.info("NAT Service : Remove the flow in the for the active switch with the DPN ID {} and VPN ID {}",
1711 NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
1712 mdsalManager.removeFlow(natPfibVpnFlowEntity);
1715 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
1716 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1717 if (ipPortMapping == null) {
1718 LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1722 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1723 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1724 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1725 for (IpPortMap ipPortMap : ipPortMaps) {
1726 String ipPortInternal = ipPortMap.getIpPortInternal();
1727 String[] ipPortParts = ipPortInternal.split(":");
1728 if (ipPortParts.length != 2) {
1729 LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1732 String internalIp = ipPortParts[0];
1733 String internalPort = ipPortParts[1];
1735 //Build the flow for the outbound NAPT table
1736 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1737 String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1738 FlowEntity outboundNaptFlowEntity =
1739 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1741 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and "
1742 + "router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1743 mdsalManager.removeFlow(outboundNaptFlowEntity);
1745 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1746 String externalIp = ipPortExternal.getIpAddress();
1747 int externalPort = ipPortExternal.getPortNum();
1749 //Build the flow for the inbound NAPT table
1750 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1751 String.valueOf(routerId), externalIp, externalPort);
1752 FlowEntity inboundNaptFlowEntity =
1753 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1755 LOG.info("NAT Service : Remove the flow in the {} for the active active switch with the "
1756 + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
1757 mdsalManager.removeFlow(inboundNaptFlowEntity);
1762 protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
1763 List<String> externalIps) {
1764 Long extVpnId = null;
1765 if (networkId != null) {
1766 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1767 if (vpnUuid != null) {
1768 extVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1770 LOG.debug("NAT Service: removeNaptFibExternalOutputFlows - vpnUuid is null");
1773 LOG.debug("NAT Service: removeNaptFibExternalOutputFlows - networkId is null");
1774 extVpnId = NatUtil.getVpnId(dataBroker, routerId);
1776 if (extVpnId == null || extVpnId == NatConstants.INVALID_ID) {
1777 LOG.debug("removeNaptFibExternalOutputFlows - extVpnId not found for routerId {}", routerId);
1778 extVpnId = routerId;
1780 for (String ip : externalIps) {
1781 String extIp = removeMaskFromIp(ip);
1782 String naptFlowRef = getFlowRefNaptFib(dpnId, NwConstants.NAPT_PFIB_TABLE, extVpnId, extIp);
1783 LOG.info("NAT Service: Remove the flow in the " + NwConstants.NAPT_PFIB_TABLE + " for the active switch"
1784 + " with the DPN ID {} and router ID {} and IP {} flowRef {}", dpnId, routerId, extIp, naptFlowRef);
1785 mdsalManager.removeFlow(NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef));
1789 private String removeMaskFromIp(String ip) {
1790 if (ip != null && !ip.trim().isEmpty()) {
1791 return ip.split("/")[0];
1796 public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
1797 BigInteger dpnId, Uuid networkId, String vpnName) {
1798 LOG.debug("NAT Service : Remove NAPT flows from Active switch Internet Vpn");
1799 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1801 //Remove the NAPT PFIB TABLE entry
1803 if (vpnName != null) {
1804 // ie called from disassociate vpn case
1805 LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1806 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1807 LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId);
1810 if (vpnId != NatConstants.INVALID_ID) {
1811 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1812 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
1813 FlowEntity natPfibVpnFlowEntity =
1814 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1815 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} "
1816 + "and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
1817 mdsalManager.removeFlow(natPfibVpnFlowEntity);
1819 // Remove IP-PORT active NAPT entries and release port from IdManager
1820 // For the router ID get the internal IP , internal port and the corresponding
1821 // external IP and external Port.
1822 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1823 if (ipPortMapping == null) {
1824 LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1827 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1828 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1829 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1830 for (IpPortMap ipPortMap : ipPortMaps) {
1831 String ipPortInternal = ipPortMap.getIpPortInternal();
1832 String[] ipPortParts = ipPortInternal.split(":");
1833 if (ipPortParts.length != 2) {
1834 LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1837 String internalIp = ipPortParts[0];
1838 String internalPort = ipPortParts[1];
1840 //Build the flow for the outbound NAPT table
1841 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1842 String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1843 FlowEntity outboundNaptFlowEntity =
1844 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1846 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the "
1847 + "DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1848 mdsalManager.removeFlow(outboundNaptFlowEntity);
1850 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1851 String externalIp = ipPortExternal.getIpAddress();
1852 int externalPort = ipPortExternal.getPortNum();
1854 //Build the flow for the inbound NAPT table
1855 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1856 String.valueOf(routerId), externalIp, externalPort);
1857 FlowEntity inboundNaptFlowEntity =
1858 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1860 LOG.info("NAT Service : Remove the flow in the {} for the active active switch with "
1861 + "the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
1862 mdsalManager.removeFlow(inboundNaptFlowEntity);
1864 // Finally release port from idmanager
1865 String internalIpPort = internalIp + ":" + internalPort;
1866 naptManager.removePortFromPool(internalIpPort, externalIp);
1868 //Remove sessions from models
1869 naptManager.removeIpPortMappingForRouterID(routerId);
1870 naptManager.removeIntIpPortMappingForRouterID(routerId);
1874 LOG.error("NAT Service : Invalid vpnId {}", vpnId);
1878 public void removeFlowsFromNonActiveSwitches(String routerName, BigInteger naptSwitchDpnId, Uuid networkId) {
1879 LOG.debug("NAT Service : Remove NAPT related flows from non active switches");
1881 // Remove the flows from the other switches which points to the primary and secondary switches
1882 // for the flows related the router ID.
1883 List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
1884 if (allSwitchList == null || allSwitchList.isEmpty()) {
1885 LOG.error("NAT Service : Unable to get the swithces for the router {}", routerName);
1888 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1889 for (BigInteger dpnId : allSwitchList) {
1890 if (!naptSwitchDpnId.equals(dpnId)) {
1891 LOG.info("NAT Service : Handle Ordinary switch");
1893 //Remove the PSNAT entry which forwards the packet to Terminating Service table
1894 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
1895 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1897 LOG.info("Remove the flow in the {} for the non active switch with the DPN ID {} and router ID {}",
1898 NwConstants.PSNAT_TABLE, dpnId, routerId);
1899 mdsalManager.removeFlow(preSnatFlowEntity);
1901 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
1902 long groupId = createGroupId(getGroupIdKey(routerName));
1903 List<BucketInfo> listBucketInfo = new ArrayList<>();
1904 GroupEntity preSnatGroupEntity =
1905 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
1907 LOG.info("NAT Service : Remove the group {} for the non active switch with the DPN ID {} "
1908 + "and router ID {}", groupId, dpnId, routerId);
1909 mdsalManager.removeGroup(preSnatGroupEntity);
1915 public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid,
1916 List<String> externalIps, String vpnName) {
1917 //Withdraw the corresponding routes from the BGP.
1918 //Get the network ID using the router ID.
1919 LOG.debug("NAT Service : Advertise to BGP and remove routes for externalIps {} with routerId {},"
1920 + "network Id {} and vpnName {}",
1921 externalIps, routerId, networkUuid, vpnName);
1922 if (networkUuid == null) {
1923 LOG.error("NAT Service : networkId is null");
1927 if (externalIps == null || externalIps.isEmpty()) {
1928 LOG.debug("NAT Service : externalIps is null");
1932 if (vpnName == null) {
1933 //Get the VPN Name using the network ID
1934 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
1935 if (vpnName == null) {
1936 LOG.error("No VPN associated with ext nw {} for the router {}",
1937 networkUuid, routerId);
1941 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
1943 //Remove custom FIB routes
1944 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
1945 for (String extIp : externalIps) {
1946 clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName);
1950 protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
1951 clearBgpRoutes(extIp, vpnName);
1952 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
1955 protected void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp,
1956 final String vpnName, long tempLabel) {
1957 LOG.debug("NAT Service : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
1958 String routerName = NatUtil.getRouterName(dataBroker,routerId);
1959 if (routerName == null) {
1960 LOG.error("NAT Service : Could not retrieve Router Name from Router ID {} ", routerId);
1963 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
1964 if (extNwProvType == null) {
1967 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
1968 * external network provided type is VxLAN
1970 if (extNwProvType == ProviderTypes.VXLAN) {
1971 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
1974 if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
1975 LOG.error("NAT Service : Label not found for externalIp {} with router id {}", extIp, routerId);
1979 final long label = tempLabel;
1980 final String externalIp = extIp;
1982 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
1983 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
1984 Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
1986 ListenableFuture<RpcResult<Void>> labelFuture =
1987 Futures.transform(JdkFutureAdapters.listenInPoolThread(future),
1988 (AsyncFunction<RpcResult<Void>, RpcResult<Void>>) result -> {
1990 if (result.isSuccessful()) {
1991 removeTunnelTableEntry(dpnId, label);
1992 removeLFibTableEntry(dpnId, label);
1993 RemoveVpnLabelInput labelInput =
1994 new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
1995 Future<RpcResult<Void>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
1996 return JdkFutureAdapters.listenInPoolThread(labelFuture1);
1999 String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s "
2000 + "Failed - %s", dpnId, externalIp, result.getErrors());
2002 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2006 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
2009 public void onFailure(Throwable error) {
2010 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
2014 public void onSuccess(RpcResult<Void> result) {
2015 if (result.isSuccessful()) {
2016 LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}",
2017 externalIp, vpnName);
2019 LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}",
2020 externalIp, vpnName, result.getErrors());
2026 private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
2027 LOG.debug("NAT Service : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2028 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2029 if (routerName == null) {
2030 LOG.error("NAT Service : Could not retrieve Router Name from Router ID {} ", routerId);
2033 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
2034 if (extNwProvType == null) {
2037 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2038 * external network provided type is VxLAN
2040 if (extNwProvType == ProviderTypes.VXLAN) {
2041 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
2044 //Get IPMaps from the DB for the router ID
2045 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
2046 if (dbIpMaps == null || dbIpMaps.isEmpty()) {
2047 LOG.error("NAT Service : IPMaps not found for router {}", routerId);
2051 long tempLabel = NatConstants.INVALID_ID;
2052 for (IpMap dbIpMap : dbIpMaps) {
2053 String dbExternalIp = dbIpMap.getExternalIp();
2054 LOG.debug("Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
2055 //Select the IPMap, whose external IP is the IP for which FIB is installed
2056 if (extIp.equals(dbExternalIp)) {
2057 tempLabel = dbIpMap.getLabel();
2058 LOG.debug("Retrieved label {} for dbExternalIp {} with router id {}",
2059 tempLabel, dbExternalIp, routerId);
2063 if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
2064 LOG.error("NAT Service : Label not found for externalIp {} with router id {}", extIp, routerId);
2068 final long label = tempLabel;
2069 final String externalIp = extIp;
2071 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
2072 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
2073 Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
2075 ListenableFuture<RpcResult<Void>> labelFuture =
2076 Futures.transform(JdkFutureAdapters.listenInPoolThread(future),
2077 (AsyncFunction<RpcResult<Void>, RpcResult<Void>>) result -> {
2079 if (result.isSuccessful()) {
2080 removeTunnelTableEntry(dpnId, label);
2081 removeLFibTableEntry(dpnId, label);
2082 RemoveVpnLabelInput labelInput =
2083 new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
2084 Future<RpcResult<Void>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
2085 return JdkFutureAdapters.listenInPoolThread(labelFuture1);
2088 String.format("RPC call to remove custom FIB entries on dpn %s for "
2089 + "prefix %s Failed - %s",
2090 dpnId, externalIp, result.getErrors());
2092 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2096 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
2099 public void onFailure(Throwable error) {
2100 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
2104 public void onSuccess(RpcResult<Void> result) {
2105 if (result.isSuccessful()) {
2106 LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}",
2107 externalIp, vpnName);
2109 LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}",
2110 externalIp, vpnName, result.getErrors());
2116 protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2117 List<String> externalIps, String vpnName) {
2118 //Withdraw the corresponding routes from the BGP.
2119 //Get the network ID using the router ID.
2120 LOG.debug("NAT Service : clearFibTsAndReverseTraffic for externalIps {} with routerId {},"
2121 + "network Id {} and vpnName {}",
2122 externalIps, routerId, networkUuid, vpnName);
2123 if (networkUuid == null) {
2124 LOG.error("NAT Service : networkId is null");
2128 if (externalIps == null || externalIps.isEmpty()) {
2129 LOG.debug("NAT Service : externalIps is null");
2133 if (vpnName == null) {
2134 //Get the VPN Name using the network ID
2135 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
2136 if (vpnName == null) {
2137 LOG.error("No VPN associated with ext nw {} for the router {}",
2138 networkUuid, routerId);
2142 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2144 //Remove custom FIB routes
2145 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2146 for (String extIp : externalIps) {
2147 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
2151 protected void clearBgpRoutes(String externalIp, final String vpnName) {
2152 //Inform BGP about the route removal
2153 LOG.info("Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
2154 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
2155 NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp, vpnName, LOG);
2158 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
2159 LOG.info("NAT Service : remove terminatingServiceActions called with DpnId = {} and label = {}",
2161 List<MatchInfo> mkMatches = new ArrayList<>();
2162 // Matching metadata
2163 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
2164 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
2165 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
2166 5, String.format("%s:%d", "TST Flow Entry ", serviceId), 0, 0,
2167 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
2168 mdsalManager.removeFlow(dpnId, flowEntity);
2169 LOG.debug("NAT Service : Terminating service Entry for dpID {} : label : {} removed successfully {}",
2173 private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
2174 List<MatchInfo> matches = new ArrayList<>();
2175 matches.add(MatchEthernetType.MPLS_UNICAST);
2176 matches.add(new MatchMplsLabel(serviceId));
2178 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2180 LOG.debug("NAT Service : removing LFib entry with flow ref {}", flowRef);
2182 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
2184 COOKIE_VM_LFIB_TABLE, matches, null);
2186 mdsalManager.removeFlow(dpnId, flowEntity);
2188 LOG.debug("NAT Service : LFIB Entry for dpID : {} label : {} removed successfully {}", dpnId, serviceId);
2192 * router association to vpn.
2194 * @param routerName - Name of router
2195 * @param bgpVpnName BGP VPN name
2197 public void changeLocalVpnIdToBgpVpnId(String routerName, String bgpVpnName) {
2198 LOG.debug("NAT Service : Router associated to BGP VPN");
2199 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2200 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2202 LOG.debug("BGP VPN ID value {} ", bgpVpnId);
2204 if (bgpVpnId != NatConstants.INVALID_ID) {
2205 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
2206 bgpVpnId, bgpVpnName);
2207 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId))
2208 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2209 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2210 getRoutersIdentifier(bgpVpnId), rtrs);
2212 // Get the allocated Primary NAPT Switch for this router
2213 long routerId = NatUtil.getVpnId(dataBroker, routerName);
2214 LOG.debug("Router ID value {} ", routerId);
2215 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2217 LOG.debug("NAT Service : Update the Router ID {} to the BGP VPN ID {} ", routerId, bgpVpnId);
2218 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, bgpVpnId, true);
2221 long groupId = createGroupId(getGroupIdKey(routerName));
2222 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true);
2228 * router disassociation from vpn.
2230 * @param routerName - Name of router
2231 * @param bgpVpnName BGP VPN name
2233 public void changeBgpVpnIdToLocalVpnId(String routerName, String bgpVpnName) {
2234 LOG.debug("NAT Service : Router dissociated from BGP VPN");
2235 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2236 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2237 LOG.debug("BGP VPN ID value {} ", bgpVpnId);
2239 // Get the allocated Primary NAPT Switch for this router
2240 long routerId = NatUtil.getVpnId(dataBroker, routerName);
2241 LOG.debug("Router ID value {} ", routerId);
2242 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2244 LOG.debug("NAT Service : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2245 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, NatConstants.INVALID_ID, true);
2248 long groupId = createGroupId(getGroupIdKey(routerName));
2249 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true);
2253 boolean chkExtRtrAndSnatEnbl(Uuid routerUuid) {
2254 InstanceIdentifier<Routers> routerInstanceIndentifier =
2255 InstanceIdentifier.builder(ExtRouters.class)
2256 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
2257 Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2258 return routerData.isPresent() && routerData.get().isEnableSnat();
2261 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2262 long routerId, boolean isSnatCfgd) {
2263 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, isSnatCfgd, null);
2266 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2267 long routerId, boolean isSnatCfgd, Routers router) {
2268 long changedVpnId = bgpVpnId;
2269 String logMsg = "NAT Service : Update the BGP VPN ID {}";
2270 if (bgpVpnId == NatConstants.INVALID_ID) {
2271 changedVpnId = routerId;
2272 logMsg = "NAT Service : Update the router ID {}";
2275 List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2276 if (switches == null || switches.isEmpty()) {
2277 LOG.debug("No switches found for router {}", routerName);
2280 for (BigInteger dpnId : switches) {
2281 // Update the BGP VPN ID in the SNAT miss entry to group
2282 if (!dpnId.equals(primarySwitchId)) {
2283 LOG.debug("NAT Service : Install group in non NAPT switch {}", dpnId);
2284 List<BucketInfo> bucketInfoForNonNaptSwitches =
2285 getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName);
2286 long groupId = createGroupId(getGroupIdKey(routerName));
2288 groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
2291 LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
2292 changedVpnId, groupId, dpnId);
2293 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
2294 mdsalManager.installFlow(flowEntity);
2296 LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the primary switch {}",
2297 changedVpnId, primarySwitchId);
2298 FlowEntity flowEntity =
2299 buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2300 mdsalManager.installFlow(flowEntity);
2302 LOG.debug(logMsg + " in the Terminating Service table (table ID 36) which forwards the packet"
2303 + " to the table 46 in the Primary switch {}", changedVpnId, primarySwitchId);
2304 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, changedVpnId);
2306 LOG.debug(logMsg + " in the Outbound NAPT table (table ID 46) which punts the packet to the"
2307 + " controller in the Primary switch {}", changedVpnId, primarySwitchId);
2308 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2310 LOG.debug(logMsg + " in the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table in the"
2311 + "Primary switch {}",
2312 changedVpnId, primarySwitchId);
2313 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2315 LOG.debug(logMsg + " in the NAPT flows for the Outbound NAPT table (table ID 46) and the "
2316 + "INBOUND NAPT table (table ID 44) in the Primary switch {}",
2317 changedVpnId, primarySwitchId);
2318 updateNaptFlowsWithVpnId(primarySwitchId, routerId, bgpVpnId);
2320 LOG.debug("NAT Service : Installing SNAT PFIB flow in the primary switch {}", primarySwitchId);
2321 Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
2322 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2323 if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
2324 installNaptPfibEntry(primarySwitchId, vpnId);
2330 public void updateNaptFlowsWithVpnId(BigInteger dpnId, long routerId, long bgpVpnId) {
2331 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2332 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2333 if (ipPortMapping == null) {
2334 LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
2337 // Get the External Gateway MAC Address
2338 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
2339 if (extGwMacAddress != null) {
2340 LOG.debug("External Gateway MAC address {} found for External Router ID {}", extGwMacAddress, routerId);
2342 LOG.error("No External Gateway MAC address found for External Router ID {}", routerId);
2345 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2346 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
2347 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2348 for (IpPortMap ipPortMap : ipPortMaps) {
2349 String ipPortInternal = ipPortMap.getIpPortInternal();
2350 String[] ipPortParts = ipPortInternal.split(":");
2351 if (ipPortParts.length != 2) {
2352 LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
2355 String internalIp = ipPortParts[0];
2356 String internalPort = ipPortParts[1];
2357 LOG.debug("NAT Service : Found Internal IP {} and Internal Port {}", internalIp, internalPort);
2358 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2359 NAPTEntryEvent.Protocol protocol;
2360 switch (protocolTypes) {
2362 protocol = NAPTEntryEvent.Protocol.TCP;
2365 protocol = NAPTEntryEvent.Protocol.UDP;
2368 protocol = NAPTEntryEvent.Protocol.TCP;
2370 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.valueOf(internalPort));
2371 SessionAddress externalAddress =
2372 naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2373 long internetVpnid = NatUtil.getVpnId(dataBroker, routerId);
2374 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
2375 routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
2376 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
2377 routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
2382 public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
2383 long changedVpnId) {
2385 LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} groupId {} "
2386 + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
2387 List<MatchInfo> matches = new ArrayList<>();
2388 matches.add(MatchEthernetType.IPV4);
2389 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2391 List<ActionInfo> actionsInfo = new ArrayList<>();
2392 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(changedVpnId)));
2393 LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
2394 actionsInfo.add(new ActionGroup(groupId));
2395 List<InstructionInfo> instructions = new ArrayList<>();
2396 instructions.add(new InstructionApplyActions(actionsInfo));
2397 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2398 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2399 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2400 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2402 LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2406 public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
2407 long changedVpnId) {
2409 LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} changed VPN ID {}",
2410 dpId, routerName, changedVpnId);
2411 List<MatchInfo> matches = new ArrayList<>();
2412 matches.add(MatchEthernetType.IPV4);
2413 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2415 List<InstructionInfo> instructions = new ArrayList<>();
2416 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2418 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2419 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2420 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2421 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2423 LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2427 // TODO : Replace this with ITM Rpc once its available with full functionality
2428 protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
2429 long changedVpnId) {
2430 LOG.debug("NAT Service : installTerminatingServiceTblEntryWithUpdatedVpnId called for switch {}, "
2431 + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2432 FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, changedVpnId);
2433 mdsalManager.installFlow(flowEntity);
2437 private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long changedVpnId) {
2438 LOG.debug("NAT Service : buildTsFlowEntityWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}",
2439 dpId, routerName, changedVpnId);
2440 BigInteger bgpVpnIdAsBigInt = BigInteger.valueOf(changedVpnId);
2441 List<MatchInfo> matches = new ArrayList<>();
2442 matches.add(MatchEthernetType.IPV4);
2443 matches.add(new MatchTunnelId(bgpVpnIdAsBigInt));
2445 List<InstructionInfo> instructions = new ArrayList<>();
2446 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2447 MetaDataUtil.METADATA_MASK_VRFID));
2448 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2449 BigInteger routerId = BigInteger.valueOf(NatUtil.getVpnId(dataBroker, routerName));
2450 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2451 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2452 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2453 NwConstants.COOKIE_TS_TABLE, matches, instructions);
2457 public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId) {
2458 LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}, BGP VPN ID {}",
2459 dpnId, routerId, changedVpnId);
2460 FlowEntity flowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId);
2461 LOG.debug("NAT Service : Installing flow {}", flowEntity);
2462 mdsalManager.installFlow(flowEntity);
2465 protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId, long changedVpnId) {
2466 LOG.debug("NAT Service : buildOutboundFlowEntityWithBgpVpn called for dpId {} and routerId {}, BGP VPN ID {}",
2467 dpId, routerId, changedVpnId);
2468 List<MatchInfo> matches = new ArrayList<>();
2469 matches.add(MatchEthernetType.IPV4);
2470 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2472 List<InstructionInfo> instructions = new ArrayList<>();
2473 List<ActionInfo> actionsInfos = new ArrayList<>();
2474 actionsInfos.add(new ActionPuntToController());
2475 instructions.add(new InstructionApplyActions(actionsInfos));
2476 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2477 MetaDataUtil.METADATA_MASK_VRFID));
2479 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
2480 BigInteger cookie = getCookieOutboundFlow(routerId);
2481 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
2482 flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
2483 LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
2487 public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId) {
2488 LOG.debug("NAT Service : installNaptPfibEntryWithBgpVpn called for dpnId {} and segmentId {} ,BGP VPN ID {}",
2489 dpnId, segmentId, changedVpnId);
2490 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2491 mdsalManager.installFlow(naptPfibFlowEntity);
2494 public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2496 LOG.debug("NAT Service : buildNaptPfibFlowEntityWithUpdatedVpnId is called for dpId {}, "
2497 + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2498 List<MatchInfo> matches = new ArrayList<>();
2499 matches.add(MatchEthernetType.IPV4);
2500 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2502 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2503 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2504 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
2505 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2506 instructionInfo.add(new InstructionApplyActions(listActionInfo));
2508 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2509 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2510 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2511 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2512 LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
2517 protected ExternalRoutersListener getDataTreeChangeListener() {
2518 return ExternalRoutersListener.this;
2521 protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId) {
2522 List<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
2524 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
2525 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
2526 if (subnetVpnId != -1) {
2527 LOG.debug("NAT Service : Calling externalRouterListener installNaptPfibEntry for dpnId {} "
2528 + "and vpnId {}", dpnId, subnetVpnId);
2529 installNaptPfibEntry(dpnId, subnetVpnId);