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 javax.annotation.PostConstruct;
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
34 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
35 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
36 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
37 import org.opendaylight.genius.mdsalutil.ActionInfo;
38 import org.opendaylight.genius.mdsalutil.BucketInfo;
39 import org.opendaylight.genius.mdsalutil.FlowEntity;
40 import org.opendaylight.genius.mdsalutil.GroupEntity;
41 import org.opendaylight.genius.mdsalutil.InstructionInfo;
42 import org.opendaylight.genius.mdsalutil.MDSALUtil;
43 import org.opendaylight.genius.mdsalutil.MatchInfo;
44 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
45 import org.opendaylight.genius.mdsalutil.NwConstants;
46 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
47 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
48 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
49 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
50 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
51 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
52 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
53 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
54 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
55 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
56 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
57 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
58 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
59 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
60 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
61 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
62 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
63 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
64 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
65 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
66 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
67 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
68 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
110 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;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIds;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsKey;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
127 import org.opendaylight.yangtools.yang.binding.DataObject;
128 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
129 import org.opendaylight.yangtools.yang.common.RpcResult;
130 import org.slf4j.Logger;
131 import org.slf4j.LoggerFactory;
134 public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener> {
135 private static final Logger LOG = LoggerFactory.getLogger(ExternalRoutersListener.class);
136 private final DataBroker dataBroker;
137 private final IMdsalApiManager mdsalManager;
138 private final ItmRpcService itmManager;
139 private final OdlInterfaceRpcService interfaceManager;
140 private final IdManagerService idManager;
141 private final NaptManager naptManager;
142 private final NAPTSwitchSelector naptSwitchSelector;
143 private final IBgpManager bgpManager;
144 private final VpnRpcService vpnService;
145 private final FibRpcService fibService;
146 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
147 private final NaptEventHandler naptEventHandler;
148 private final NaptPacketInHandler naptPacketInHandler;
149 private final IFibManager fibManager;
150 private final IVpnManager vpnManager;
151 private final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer;
152 private final CentralizedSwitchScheduler centralizedSwitchScheduler;
153 private NatMode natMode = NatMode.Controller;
154 private final INeutronVpnManager nvpnManager;
155 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
156 static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
159 public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
160 final ItmRpcService itmManager,
161 final OdlInterfaceRpcService interfaceManager,
162 final IdManagerService idManager,
163 final NaptManager naptManager,
164 final NAPTSwitchSelector naptSwitchSelector,
165 final IBgpManager bgpManager,
166 final VpnRpcService vpnService,
167 final FibRpcService fibService,
168 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
169 final NaptEventHandler naptEventHandler,
170 final NaptPacketInHandler naptPacketInHandler,
171 final IFibManager fibManager,
172 final IVpnManager vpnManager,
173 final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer,
174 final INeutronVpnManager nvpnManager,
175 final CentralizedSwitchScheduler centralizedSwitchScheduler,
176 final NatserviceConfig config) {
177 super(Routers.class, ExternalRoutersListener.class);
178 this.dataBroker = dataBroker;
179 this.mdsalManager = mdsalManager;
180 this.itmManager = itmManager;
181 this.interfaceManager = interfaceManager;
182 this.idManager = idManager;
183 this.naptManager = naptManager;
184 this.naptSwitchSelector = naptSwitchSelector;
185 this.bgpManager = bgpManager;
186 this.vpnService = vpnService;
187 this.fibService = fibService;
188 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
189 this.naptEventHandler = naptEventHandler;
190 this.naptPacketInHandler = naptPacketInHandler;
191 this.fibManager = fibManager;
192 this.vpnManager = vpnManager;
193 this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
194 this.nvpnManager = nvpnManager;
195 this.centralizedSwitchScheduler = centralizedSwitchScheduler;
196 if (config != null) {
197 this.natMode = config.getNatMode();
204 LOG.info("{} init", getClass().getSimpleName());
205 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
210 protected InstanceIdentifier<Routers> getWildCardPath() {
211 return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
215 // TODO Clean up the exception handling
216 @SuppressWarnings("checkstyle:IllegalCatch")
217 protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
218 // Populate the router-id-name container
219 String routerName = routers.getRouterName();
220 LOG.info("NAT Service : Add external router event for {}", routerName);
221 NatUtil.createRouterIdsConfigDS(dataBroker, routerName);
222 if (natMode == NatMode.Conntrack) {
223 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
224 if (bgpVpnUuid != null) {
227 // Allocate Primary Napt Switch for this router
228 if (routers.isEnableSnat()) {
229 boolean result = centralizedSwitchScheduler.scheduleCentralizedSwitch(routerName);
231 //snatServiceManger.notify(routers, null, Action.ADD);
233 LOG.info("NAT Service : Installing NAT default route on all dpns part of router {}", routerName);
235 addOrDelDefFibRouteToSNAT(routerName, true);
236 } catch (Exception ex) {
237 LOG.debug("NAT Service : Exception {} while Installing NAT default route on all dpns part of router {}",
241 long segmentId = NatUtil.getVpnId(dataBroker, routerName);
242 // Allocate Primary Napt Switch for this router
243 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName, segmentId);
244 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
246 "NAT Service: Failed to get or allocate NAPT switch for router {}. NAPT"
247 + " flow installation will be delayed", routerName);
251 handleRouterGwFlows(routers, primarySwitchId, NwConstants.ADD_FLOW);
252 if (!routers.isEnableSnat()) {
253 LOG.info("NAT Service : SNAT is disabled for external router {} ", routerName);
257 handleEnableSnat(routers, segmentId, primarySwitchId);
261 public void handleEnableSnat(Routers routers, long segmentId, BigInteger primarySwitchId) {
262 String routerName = routers.getRouterName();
263 LOG.info("NAT Service : Handling SNAT for router {}", routerName);
265 naptManager.initialiseExternalCounter(routers, segmentId);
266 subnetRegisterMapping(routers, segmentId);
268 LOG.debug("NAT Service : About to create and install outbound miss entry in Primary Switch {} for router {}",
269 primarySwitchId, routerName);
271 long bgpVpnId = NatConstants.INVALID_ID;
272 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
273 if (bgpVpnUuid != null) {
274 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
276 if (bgpVpnId != NatConstants.INVALID_ID) {
277 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, segmentId, false);
279 // write metadata and punt
280 installOutboundMissEntry(routerName, primarySwitchId);
281 // Now install entries in SNAT tables to point to Primary for each router
282 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
283 if (switches != null) {
284 for (BigInteger dpnId : switches) {
285 // Handle switches and NAPT switches separately
286 if (!dpnId.equals(primarySwitchId)) {
287 LOG.debug("NAT Service : Handle Ordinary switch");
288 handleSwitches(dpnId, routerName, primarySwitchId);
290 LOG.debug("NAT Service : Handle NAPT switch");
291 handlePrimaryNaptSwitch(dpnId, routerName);
297 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, segmentId);
298 if (externalIps == null || externalIps.isEmpty()) {
299 LOG.debug("NAT Service : Internal External mapping found for router {}", routerName);
302 for (String externalIpAddrPrefix : externalIps) {
303 LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, "
304 + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
305 handleSnatReverseTraffic(primarySwitchId, routers, segmentId, routerName, externalIpAddrPrefix);
308 LOG.info("NAT Service : handleEnableSnat() Exit");
311 private BigInteger getPrimaryNaptSwitch(String routerName, long segmentId) {
312 // Allocate Primary Napt Switch for this router
313 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
314 if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
315 LOG.debug("NAT Service : Primary NAPT switch with DPN ID {} is already elected for router {}",
316 primarySwitchId, routerName);
317 return primarySwitchId;
320 // Validating and creating VNI pool during when NAPT switch is selected.
321 // With Assumption this might be the first NAT service comes up.
322 if (nvpnManager.getEnforceOpenstackSemanticsConfig()) {
323 NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager,
324 idManager, NatConstants.ODL_VNI_POOL_NAME);
326 primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
327 LOG.debug("NAT Service : Primary NAPT switch DPN ID {}", primarySwitchId);
328 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
329 LOG.info("NAT Service : Unable to to select the primary NAPT switch for router {}", routerName);
332 return primarySwitchId;
335 protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId) {
336 Long extVpnId = NatUtil.getVpnId(dataBroker, routerId);
337 if (extVpnId == null || extVpnId == NatConstants.INVALID_ID) {
338 LOG.debug("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
341 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
342 if (externalIps == null || externalIps.isEmpty()) {
343 LOG.debug("installNaptPfibExternalOutputFlow - empty external Ips list for dpnId {} extVpnId {}",
347 for (String ip : externalIps) {
348 Uuid subnetId = getSubnetIdForFixedIp(ip);
349 if (subnetId != null) {
350 long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
351 if (subnetVpnId != NatConstants.INVALID_ID) {
352 extVpnId = subnetVpnId;
354 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
355 dpnId, extVpnId, subnetId);
356 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
357 mdsalManager.installFlow(postNaptFlowEntity);
362 private Uuid getSubnetIdForFixedIp(String ip) {
364 IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
365 Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
366 Uuid subnetId = NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
372 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
373 List<Uuid> subnetList = null;
374 List<String> externalIps = null;
375 LOG.debug("NAT Service : Fetching values from extRouters model");
376 subnetList = routerEntry.getSubnetIds();
377 externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
379 int extIpCounter = externalIps.size();
380 LOG.debug("NAT Service : counter values before looping counter {} and extIpCounter {}", counter, extIpCounter);
381 for (Uuid subnet : subnetList) {
382 LOG.debug("NAT Service : Looping internal subnets for subnet {}", subnet);
383 InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
384 .builder(Subnetmaps.class)
385 .child(Subnetmap.class, new SubnetmapKey(subnet))
387 Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
388 if (sn.isPresent()) {
390 Subnetmap subnetmapEntry = sn.get();
391 String subnetString = subnetmapEntry.getSubnetIp();
392 String[] subnetSplit = subnetString.split("/");
393 String subnetIp = subnetSplit[0];
395 InetAddress address = InetAddress.getByName(subnetIp);
396 if (address instanceof Inet6Address) {
397 // TODO: Revisit when IPv6 external connectivity support is added.
398 LOG.debug("Skipping ipv6 address {}.", address);
401 } catch (UnknownHostException e) {
402 LOG.warn("Invalid ip address {}", subnetIp, e);
405 String subnetPrefix = "0";
406 if (subnetSplit.length == 2) {
407 subnetPrefix = subnetSplit[1];
409 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
410 LOG.debug("NAT Service : subnetAddr is {} and subnetPrefix is {}",
411 subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
413 LOG.debug("NAT Service : counter values counter {} and extIpCounter {}", counter, extIpCounter);
414 if (extIpCounter != 0) {
415 if (counter < extIpCounter) {
416 String[] ipSplit = externalIps.get(counter).split("/");
417 String externalIp = ipSplit[0];
418 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
419 if (ipSplit.length == 2) {
420 extPrefix = ipSplit[1];
422 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
423 LOG.debug("NAT Service : externalIp is {} and extPrefix is {}",
424 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
425 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
426 LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. "
427 + "prefix {}", subnetIp, subnetPrefix, externalIp, extPrefix);
429 counter = 0; //Reset the counter which runs on externalIps for round-robbin effect
430 LOG.debug("NAT Service : Counter on externalIps got reset");
431 String[] ipSplit = externalIps.get(counter).split("/");
432 String externalIp = ipSplit[0];
433 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
434 if (ipSplit.length == 2) {
435 extPrefix = ipSplit[1];
437 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
438 LOG.debug("NAT Service : externalIp is {} and extPrefix is {}",
439 externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
440 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
441 LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. "
442 + "prefix {}", subnetIp, subnetPrefix,
443 externalIp, extPrefix);
447 LOG.debug("NAT Service : Counter on externalIps incremented to {}", counter);
449 LOG.warn("NAT Service : No internal subnets present in extRouters Model");
454 private void addOrDelDefFibRouteToSNAT(String routerName, boolean create) {
455 //Check if BGP VPN exists. If exists then invoke the new method.
456 long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
457 if (bgpVpnId != NatConstants.INVALID_ID) {
458 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
459 if (bgpVpnUuid != null) {
460 String bgpVpnName = bgpVpnUuid.getValue();
461 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
462 bgpVpnId, bgpVpnName);
463 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId))
464 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
465 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
466 getRoutersIdentifier(bgpVpnId), rtrs);
468 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, bgpVpnId, create);
472 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
473 addOrDelDefaultFibRouteForSNAT(routerName, create);
476 private void addOrDelDefaultFibRouteForSNAT(String routerName, boolean create) {
477 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
478 if (switches == null || switches.isEmpty()) {
479 LOG.debug("No switches found for router {}", routerName);
482 long routerId = NatUtil.readVpnId(dataBroker, routerName);
483 if (routerId == NatConstants.INVALID_ID) {
484 LOG.error("Could not retrieve router Id for {} to program default NAT route in FIB", routerName);
487 for (BigInteger dpnId : switches) {
489 LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} for the internal vpn",
491 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
493 LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} for the internal vpn",
495 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
500 private void addOrDelDefaultFibRouteForSnatWithBgpVpn(String routerName, long bgpVpnId, boolean create) {
501 List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
502 if (dpnIds == null || dpnIds.isEmpty()) {
503 LOG.debug("NAT Service : Current no dpns part of router {} to program default NAT route", routerName);
506 long routerId = NatUtil.getVpnId(dataBroker, routerName);
507 for (BigInteger dpnId : dpnIds) {
509 if (bgpVpnId != NatConstants.INVALID_ID) {
510 LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} "
511 + "for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
512 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
514 LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} "
515 + "for the internal vpn", routerId, dpnId);
516 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
519 if (bgpVpnId != NatConstants.INVALID_ID) {
520 LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} "
521 + "for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
522 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
524 LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} "
525 + "for the internal vpn", routerId, dpnId);
526 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
532 // TODO Clean up the exception handling
533 @SuppressWarnings("checkstyle:IllegalCatch")
534 public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
535 InstanceIdentifier<T> path) {
536 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
539 return tx.read(datastoreType, path).get();
540 } catch (Exception e) {
541 throw new RuntimeException(e);
545 protected void installOutboundMissEntry(String routerName, BigInteger primarySwitchId) {
546 long routerId = NatUtil.getVpnId(dataBroker, routerName);
547 LOG.debug("NAT Service : Router ID from getVpnId {}", routerId);
548 if (routerId != NatConstants.INVALID_ID) {
549 LOG.debug("NAT Service : Creating miss entry on primary {}, for router {}", primarySwitchId, routerId);
550 createOutboundTblEntry(primarySwitchId, routerId);
552 LOG.error("NAT Service : Unable to fetch Router Id for RouterName {}, failed to "
553 + "createAndInstallMissEntry", routerName);
557 public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID) {
558 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
559 .FLOWID_SEPARATOR + routerID;
562 private String getFlowRefNaptFib(BigInteger dpnId, short tableId, long routerID, String externalIp) {
563 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
564 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + externalIp;
567 public BigInteger getCookieOutboundFlow(long routerId) {
568 return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
569 BigInteger.valueOf(routerId));
572 protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId) {
573 LOG.debug("NAT Service : buildOutboundFlowEntity called for dpId {} and routerId{}", dpId, routerId);
574 List<MatchInfo> matches = new ArrayList<>();
575 matches.add(MatchEthernetType.IPV4);
576 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
578 List<InstructionInfo> instructions = new ArrayList<>();
579 List<ActionInfo> actionsInfos = new ArrayList<>();
580 actionsInfos.add(new ActionPuntToController());
581 instructions.add(new InstructionApplyActions(actionsInfos));
582 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
583 MetaDataUtil.METADATA_MASK_VRFID));
585 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
586 BigInteger cookie = getCookieOutboundFlow(routerId);
587 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
589 cookie, matches, instructions);
590 LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
594 public void createOutboundTblEntry(BigInteger dpnId, long routerId) {
595 LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}", dpnId, routerId);
596 FlowEntity flowEntity = buildOutboundFlowEntity(dpnId, routerId);
597 LOG.debug("NAT Service : Installing flow {}", flowEntity);
598 mdsalManager.installFlow(flowEntity);
601 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
602 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
603 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
605 Future<RpcResult<GetTunnelInterfaceNameOutput>> result =
606 itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
607 .setSourceDpid(srcDpId)
608 .setDestinationDpid(dstDpId)
609 .setTunnelType(tunType)
611 rpcResult = result.get();
612 if (!rpcResult.isSuccessful()) {
613 tunType = TunnelTypeGre.class;
614 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
615 .setSourceDpid(srcDpId)
616 .setDestinationDpid(dstDpId)
617 .setTunnelType(tunType)
619 rpcResult = result.get();
620 if (!rpcResult.isSuccessful()) {
621 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
623 return rpcResult.getResult().getInterfaceName();
625 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
627 return rpcResult.getResult().getInterfaceName();
629 } catch (InterruptedException | ExecutionException | NullPointerException e) {
630 LOG.warn("NAT Service : Exception when getting tunnel interface Id for tunnel between {} and {}",
631 srcDpId, dstDpId, e);
637 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName) {
638 LOG.debug("NAT Service : installSnatMissEntry called for for the primary NAPT switch dpnId {} ", dpnId);
639 // Install miss entry pointing to group
640 FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName);
641 mdsalManager.installFlow(flowEntity);
644 protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
645 LOG.debug("NAT Service : installSnatMissEntry called for dpnId {} with primaryBucket {} ",
646 dpnId, bucketInfo.get(0));
647 // Install the select group
648 long groupId = createGroupId(getGroupIdKey(routerName));
649 GroupEntity groupEntity =
650 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
651 LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
652 mdsalManager.syncInstallGroup(groupEntity, 0);
653 // Install miss entry pointing to group
654 FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, groupId);
655 if (flowEntity == null) {
656 LOG.error("NAT Service : Flow entity received as NULL. "
657 + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
658 + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
661 mdsalManager.installFlow(flowEntity);
664 long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo) {
665 long groupId = createGroupId(getGroupIdKey(routerName));
666 GroupEntity groupEntity =
667 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
668 LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
669 mdsalManager.syncInstallGroup(groupEntity, 0);
673 private FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId) {
674 LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
675 dpId, routerName, groupId);
676 long routerId = NatUtil.getVpnId(dataBroker, routerName);
677 List<MatchInfo> matches = new ArrayList<>();
678 matches.add(MatchEthernetType.IPV4);
679 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
681 List<ActionInfo> actionsInfo = new ArrayList<>();
682 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, nvpnManager, idManager,
683 routerId, routerName);
684 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
685 LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
686 actionsInfo.add(new ActionGroup(groupId));
687 List<InstructionInfo> instructions = new ArrayList<>();
688 instructions.add(new InstructionApplyActions(actionsInfo));
689 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
690 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
691 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
692 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
694 LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
698 private FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName) {
700 LOG.debug("NAT Service : buildSnatFlowEntity is called for primary NAPT switch dpId {}, routerName {}", dpId,
702 long routerId = NatUtil.getVpnId(dataBroker, routerName);
703 List<MatchInfo> matches = new ArrayList<>();
704 matches.add(MatchEthernetType.IPV4);
705 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
707 List<InstructionInfo> instructions = new ArrayList<>();
708 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
710 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
711 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
712 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
713 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
715 LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
719 // TODO : Replace this with ITM Rpc once its available with full functionality
720 protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName) {
721 LOG.debug("NAT Service : creating entry for Terminating Service Table for switch {}, routerName {}",
723 FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName);
724 if (flowEntity == null) {
725 LOG.error("NAT Service : Flow entity received as NULL. "
726 + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
727 + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
731 mdsalManager.installFlow(flowEntity);
735 private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName) {
736 long routerId = NatUtil.getVpnId(dataBroker, routerName);
737 List<MatchInfo> matches = new ArrayList<>();
738 matches.add(MatchEthernetType.IPV4);
739 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, nvpnManager, idManager,
740 routerId, routerName);
741 matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
742 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
743 List<InstructionInfo> instructions = new ArrayList<>();
744 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
745 MetaDataUtil.METADATA_MASK_VRFID));
746 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
747 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
748 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
753 public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
754 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
755 .FLOWID_SEPARATOR + routerID;
758 public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
759 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
760 .FLOWID_SEPARATOR + routerID;
763 private String getGroupIdKey(String routerName) {
764 return "snatmiss." + routerName;
767 protected long createGroupId(String groupIdKey) {
768 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
769 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
772 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
773 RpcResult<AllocateIdOutput> rpcResult = result.get();
774 return rpcResult.getResult().getIdValue();
775 } catch (NullPointerException | InterruptedException | ExecutionException e) {
781 protected void createGroupIdPool() {
782 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
783 .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
784 .setLow(NatConstants.SNAT_ID_LOW_VALUE)
785 .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
788 Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
789 if ((result != null) && (result.get().isSuccessful())) {
790 LOG.debug("NAT Service : Created GroupIdPool");
792 LOG.error("NAT Service : Unable to create GroupIdPool");
794 } catch (InterruptedException | ExecutionException e) {
795 LOG.error("Failed to create PortPool for NAPT Service", e);
799 protected void handleSwitches(BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
800 LOG.debug("NAT Service : Installing SNAT miss entry in switch {}", dpnId);
801 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
802 String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
803 List<BucketInfo> listBucketInfo = new ArrayList<>();
804 long routerId = NatUtil.getVpnId(dataBroker, routerName);
806 if (ifNamePrimary != null) {
807 LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
808 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(interfaceManager, ifNamePrimary, routerId);
810 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
812 listBucketInfo.add(0, bucketPrimary);
813 installSnatMissEntry(dpnId, listBucketInfo, routerName);
816 List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
817 BigInteger primarySwitchId, String routerName) {
818 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
819 String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
820 List<BucketInfo> listBucketInfo = new ArrayList<>();
821 long routerId = NatUtil.getVpnId(dataBroker, routerName);
823 if (ifNamePrimary != null) {
824 LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
825 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(interfaceManager, ifNamePrimary, routerId);
827 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
829 listBucketInfo.add(0, bucketPrimary);
830 return listBucketInfo;
833 protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName) {
835 * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
838 LOG.debug("NAT Service : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
841 List<BucketInfo> listBucketInfo = new ArrayList<>();
842 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
843 listActionInfoPrimary.add(new ActionNxResubmit(NatConstants.TERMINATING_SERVICE_TABLE));
844 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
845 listBucketInfo.add(0, bucketPrimary);
848 long routerId = NatUtil.getVpnId(dataBroker, routerName);
850 installSnatMissEntryForPrimrySwch(dpnId, routerName);
851 installTerminatingServiceTblEntry(dpnId, routerName);
852 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
853 installNaptPfibEntry(dpnId, routerId);
854 Long vpnId = NatUtil.getVpnId(dataBroker, routerName);
855 installNaptPfibEntriesForExternalSubnets(routerName, dpnId);
856 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
857 if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
858 installNaptPfibEntry(dpnId, vpnId);
862 List<BucketInfo> getBucketInfoForPrimaryNaptSwitch() {
863 List<BucketInfo> listBucketInfo = new ArrayList<>();
864 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
865 listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
866 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
867 listBucketInfo.add(0, bucketPrimary);
868 return listBucketInfo;
871 public void installNaptPfibEntry(BigInteger dpnId, long segmentId) {
872 LOG.debug("NAT Service : installNaptPfibEntry called for dpnId {} and segmentId {} ", dpnId, segmentId);
873 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
874 mdsalManager.installFlow(naptPfibFlowEntity);
877 public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
879 LOG.debug("NAT Service : buildNaptPfibFlowEntity is called for dpId {}, segmentId {}", dpId, segmentId);
880 List<MatchInfo> matches = new ArrayList<>();
881 matches.add(MatchEthernetType.IPV4);
882 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
884 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
885 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
886 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
887 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
888 instructionInfo.add(new InstructionApplyActions(listActionInfo));
890 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
891 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
892 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
893 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
894 LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
898 private void handleSnatReverseTraffic(BigInteger dpnId, Routers router, long routerId, String routerName,
900 LOG.debug("NAT Service : handleSnatReverseTraffic() entry for DPN ID {}, routerId {}, externalIp: {}",
901 dpnId, routerId, externalIp);
902 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
903 if (networkId == null) {
904 LOG.error("NAT Service : networkId is null for the router ID {}", routerId);
907 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
908 if (vpnName == null) {
909 LOG.error("NAT Service : No VPN associated with ext nw {} to handle add external ip "
910 + "configuration {} in router {}",
911 networkId, externalIp, routerId);
914 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
915 externalIp, router, vpnService, fibService, bgpManager, dataBroker, LOG);
916 LOG.debug("NAT Service : handleSnatReverseTraffic() exit for DPN ID {}, routerId {}, externalIp : {}",
917 dpnId, routerId, externalIp);
920 public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
921 final long routerId, final String routerName, final String externalIp,
922 final Routers router, VpnRpcService vpnService,
923 final FibRpcService fibService, final IBgpManager bgpManager,
924 final DataBroker dataBroker, final Logger log) {
925 LOG.debug("NAT Service : advToBgpAndInstallFibAndTsFlows() entry for DPN ID {}, tableId {}, vpnname {} "
926 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
927 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
928 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
929 if (rd == null || rd.isEmpty()) {
930 LOG.error("NAT Service : Unable to get RD for VPN Name {}", vpnName);
933 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName);
934 if (extNwProvType == null) {
937 if (extNwProvType == ProviderTypes.VXLAN) {
938 WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
939 evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
940 nextHopIp, writeTx, routerId);
944 //Generate VPN label for the external IP
945 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
946 .setIpPrefix(externalIp).build();
947 Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
949 //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
950 ListenableFuture<RpcResult<Void>> future =
951 Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture),
952 (AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>) result -> {
953 if (result.isSuccessful()) {
954 LOG.debug("NAT Service : inside apply with result success");
955 GenerateVpnLabelOutput output = result.getResult();
956 final long label = output.getLabel();
958 int externalIpInDsFlag = 0;
959 //Get IPMaps from the DB for the router ID
960 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
961 if (dbIpMaps != null) {
962 for (IpMap dbIpMap : dbIpMaps) {
963 String dbExternalIp = dbIpMap.getExternalIp();
964 //Select the IPMap, whose external IP is the IP for which FIB is installed
965 if (dbExternalIp.contains(externalIp)) {
966 String dbInternalIp = dbIpMap.getInternalIp();
967 IpMapKey dbIpMapKey = dbIpMap.getKey();
968 LOG.debug("Setting label {} for internalIp {} and externalIp {}",
969 label, dbInternalIp, externalIp);
970 IpMap newIpm = new IpMapBuilder().setKey(dbIpMapKey).setInternalIp(dbInternalIp)
971 .setExternalIp(dbExternalIp).setLabel(label).build();
972 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
973 naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
974 externalIpInDsFlag++;
977 if (externalIpInDsFlag <= 0) {
978 LOG.debug("NAT Service : External Ip {} not found in DS, Failed to update label {} "
979 + "for routerId {} in DS", externalIp, label, routerId);
980 String errMsg = String.format("Failed to update label %s due to external Ip %s not"
981 + " found in DS for router %s", label, externalIp, routerId);
982 return Futures.immediateFailedFuture(new Exception(errMsg));
985 LOG.error("NAT Service : Failed to write label {} for externalIp {} for "
986 + "routerId {} in DS", label, externalIp, routerId);
990 if (nvpnManager.getEnforceOpenstackSemanticsConfig()) {
991 l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
993 Routers extRouter = router != null ? router :
994 NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
995 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(dataBroker, externalIp,
997 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, externalSubnetId,
998 externalIp, nextHopIp, extRouter.getNetworkId().getValue(), null, label, l3vni, log,
999 RouteOrigin.STATIC, dpnId);
1001 //Install custom FIB routes
1002 List<Instruction> tunnelTableCustomInstructions = new ArrayList<>();
1003 tunnelTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
1004 makeTunnelTableEntry(dpnId, label, l3vni, tunnelTableCustomInstructions);
1005 makeLFibTableEntry(dpnId, label, tableId);
1007 //Install custom FIB routes - FIB table.
1008 List<Instruction> fibTableCustomInstructions = createFibTableCustomInstructions(dataBroker,
1009 tableId, routerName, externalIp);
1010 if (nvpnManager.getEnforceOpenstackSemanticsConfig()) {
1011 //Install the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
1012 NatUtil.makePreDnatToSnatTableEntry(mdsalManager, dpnId,
1013 NwConstants.INBOUND_NAPT_TABLE);
1015 String fibExternalIp = externalIp.contains("/32") ? externalIp : (externalIp + "/32");
1016 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
1017 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
1018 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
1019 .setInstruction(fibTableCustomInstructions).build();
1020 Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
1021 return JdkFutureAdapters.listenInPoolThread(future1);
1023 LOG.error("NAT Service : inside apply with result failed");
1024 String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
1025 externalIp, vpnName, result.getErrors());
1026 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1030 Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
1033 public void onFailure(Throwable error) {
1034 log.error("NAT Service : Error in generate label or fib install process", error);
1038 public void onSuccess(RpcResult<Void> result) {
1039 if (result.isSuccessful()) {
1040 log.info("NAT Service : Successfully installed custom FIB routes for prefix {}", externalIp);
1042 log.error("NAT Service : Error in rpc call to create custom Fib entries for prefix {} in "
1043 + "DPN {}, {}", externalIp, dpnId, result.getErrors());
1049 private List<Instruction> createFibTableCustomInstructions(DataBroker dataBroker, short tableId,
1050 String routerName, String externalIp) {
1051 List<Instruction> fibTableCustomInstructions = new ArrayList<>();
1052 Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1053 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
1054 externalIp, router);
1055 int instructionIndex = 0;
1056 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
1057 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
1058 fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
1059 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
1063 fibTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(instructionIndex));
1064 return fibTableCustomInstructions;
1067 private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId) {
1068 List<MatchInfo> matches = new ArrayList<>();
1069 matches.add(MatchEthernetType.MPLS_UNICAST);
1070 matches.add(new MatchMplsLabel(serviceId));
1072 List<Instruction> instructions = new ArrayList<>();
1073 List<ActionInfo> actionsInfos = new ArrayList<>();
1074 actionsInfos.add(new ActionPopMpls());
1075 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
1076 instructions.add(writeInstruction);
1077 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
1079 // Install the flow entry in L3_LFIB_TABLE
1080 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1082 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1084 COOKIE_VM_LFIB_TABLE, matches, instructions);
1086 mdsalManager.installFlow(dpId, flowEntity);
1088 LOG.debug("NAT Service : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
1091 private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, long l3Vni,
1092 List<Instruction> customInstructions) {
1093 List<MatchInfo> mkMatches = new ArrayList<>();
1095 LOG.debug("NAT Service : Create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
1096 dpnId, serviceId, customInstructions);
1098 if (nvpnManager.getEnforceOpenstackSemanticsConfig()) {
1099 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
1101 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
1104 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1105 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5,
1106 String.format("%s:%d", "TST Flow Entry ", serviceId),
1107 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1109 mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
1112 protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1113 InstanceIdentifier<RouterIds> id = InstanceIdentifier.builder(
1114 RouterIdName.class).child(RouterIds.class, new RouterIdsKey(routerId)).build();
1118 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1119 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
1120 .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
1124 protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1125 String routerName = original.getRouterName();
1126 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1127 if (routerId == NatConstants.INVALID_ID) {
1128 LOG.error("NAT Service : Update external router event - Invalid routerId for routerName {}", routerName);
1131 BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1132 Uuid networkId = original.getNetworkId();
1134 // Check if its update on SNAT flag
1135 boolean originalSNATEnabled = original.isEnableSnat();
1136 boolean updatedSNATEnabled = update.isEnableSnat();
1137 LOG.debug("NAT Service : update of externalRoutersListener called with originalFlag and updatedFlag "
1138 + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
1139 if (natMode == NatMode.Conntrack) {
1140 if (originalSNATEnabled != updatedSNATEnabled) {
1141 BigInteger primarySwitchId;
1142 if (originalSNATEnabled) {
1143 //SNAT disabled for the router
1144 centralizedSwitchScheduler.releaseCentralizedSwitch(routerName);
1146 centralizedSwitchScheduler.scheduleCentralizedSwitch(routerName);
1150 if (originalSNATEnabled != updatedSNATEnabled) {
1151 if (originalSNATEnabled) {
1152 //SNAT disabled for the router
1153 Uuid networkUuid = original.getNetworkId();
1154 LOG.info("NAT Service : SNAT disabled for Router {}", routerName);
1155 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1156 handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId);
1158 // Allocate Primary Napt Switch for existing router
1159 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName, routerId);
1160 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
1161 LOG.error("NAT Service: Failed to get or allocated NAPT switch in"
1162 + " ExternalRouterListener.Update()");
1165 LOG.info("NAT Service : SNAT enabled for Router {}", original.getRouterName());
1166 handleEnableSnat(original, routerId, primarySwitchId);
1170 if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1171 handleRouterGwFlows(original, dpnId, NwConstants.DEL_FLOW);
1172 handleRouterGwFlows(update, dpnId, NwConstants.ADD_FLOW);
1175 //Check if the Update is on External IPs
1176 LOG.debug("NAT Service : Checking if this is update on External IPs");
1177 List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
1178 List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
1180 //Check if the External IPs are added during the update.
1181 Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
1182 addedExternalIps.removeAll(originalExternalIps);
1183 if (addedExternalIps.size() != 0) {
1184 LOG.debug("NAT Service : Start processing of the External IPs addition during the update operation");
1185 vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
1186 update.getExtGwMacAddress(), dpnId,
1187 update.getNetworkId(), null, NwConstants.ADD_FLOW);
1189 for (String addedExternalIp : addedExternalIps) {
1191 1) Do nothing in the IntExtIp model.
1192 2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1194 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1195 String externalIp = externalIpParts[0];
1196 String externalIpPrefix = externalIpParts[1];
1197 String externalpStr = externalIp + "/" + externalIpPrefix;
1198 LOG.debug("NAT Service : Initialise the count mapping of the external IP {} for the "
1199 + "router ID {} in the ExternalIpsCounter model.",
1200 externalpStr, routerId);
1201 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1203 LOG.debug("NAT Service : End processing of the External IPs addition during the update operation");
1206 //Check if the External IPs are removed during the update.
1207 Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
1208 removedExternalIps.removeAll(updatedExternalIps);
1209 if (removedExternalIps.size() > 0) {
1210 LOG.debug("NAT Service : Start processing of the External IPs removal during the update operation");
1211 vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerName,
1212 removedExternalIps, original.getExtGwMacAddress(),
1213 dpnId, networkId, null, NwConstants.DEL_FLOW);
1215 for (String removedExternalIp : removedExternalIps) {
1217 1) Remove the mappings in the IntExt IP model which has external IP.
1218 2) Remove the external IP in the ExternalCounter model.
1219 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the
1220 least loaded external IP.
1221 Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1222 4) Increase the count of the allocated external IP by one.
1223 5) Advertise to the BGP if external IP is allocated for the first time for the router
1224 i.e. the route for the external IP is absent.
1225 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for
1226 the removed external IPs and also from the model.
1227 7) Advertise to the BGP for removing the route for the removed external IPs.
1230 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1231 String externalIp = externalIpParts[0];
1232 String externalIpPrefix = externalIpParts[1];
1233 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1235 LOG.debug("NAT Service : Clear the routes from the BGP and remove the FIB and TS "
1236 + "entries for removed external IP {}", externalIpAddrStr);
1237 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1238 String vpnName = "";
1239 if (vpnUuId != null) {
1240 vpnName = vpnUuId.getValue();
1242 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName);
1244 LOG.debug("NAT Service : Remove the mappings in the IntExtIP model which has external IP.");
1245 //Get the internal IPs which are associated to the removed external IPs
1246 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1247 List<String> removedInternalIps = new ArrayList<>();
1248 for (IpMap ipMap : ipMaps) {
1249 if (ipMap.getExternalIp().equals(externalIpAddrStr)) {
1250 removedInternalIps.add(ipMap.getInternalIp());
1254 LOG.debug("Remove the mappings of the internal IPs from the IntExtIP model.");
1255 for (String removedInternalIp : removedInternalIps) {
1256 LOG.debug("NAT Service : Remove the IP mapping of the internal IP {} for the "
1257 + "router ID {} from the IntExtIP model",
1258 removedInternalIp, routerId);
1259 naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1262 LOG.debug("NAT Service : Remove the count mapping of the external IP {} for the "
1263 + "router ID {} from the ExternalIpsCounter model.",
1264 externalIpAddrStr, routerId);
1265 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1267 LOG.debug("NAT Service : Allocate the least loaded external IPs to the subnets "
1268 + "whose external IPs were removed.");
1269 for (String removedInternalIp : removedInternalIps) {
1270 allocateExternalIp(dpnId, update, routerId, routerName, networkId, removedInternalIp);
1273 LOG.debug("NAT Service : Remove the NAPT translation entries from "
1274 + "Inbound and Outbound NAPT tables for the removed external IPs.");
1275 //Get the internalIP and internal Port which were associated to the removed external IP.
1276 List<Integer> externalPorts = new ArrayList<>();
1277 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1278 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier
1279 .builder(IntextIpPortMap.class)
1280 .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1281 Optional<IpPortMapping> ipPortMapping =
1282 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1283 if (ipPortMapping.isPresent()) {
1284 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get()
1285 .getIntextIpProtocolType();
1286 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1287 ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1288 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1289 for (IpPortMap ipPortMap : ipPortMaps) {
1290 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1291 if (ipPortExternal.getIpAddress().equals(externalIp)) {
1292 externalPorts.add(ipPortExternal.getPortNum());
1293 List<String> removedInternalIpPorts = protoTypesIntIpPortsMap.get(protoType);
1294 if (removedInternalIpPorts != null) {
1295 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1296 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1298 removedInternalIpPorts = new ArrayList<>();
1299 removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1300 protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1307 //Remove the IP port map from the intext-ip-port-map model, which were containing
1308 // the removed external IP.
1309 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts = protoTypesIntIpPortsMap
1311 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1312 for (Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts) {
1313 ProtocolTypes protocolType = (ProtocolTypes) protoTypesIntIpPort.getKey();
1314 List<String> removedInternalIpPorts = (List<String>) protoTypesIntIpPort.getValue();
1315 for (String removedInternalIpPort : removedInternalIpPorts) {
1316 // Remove the IP port map from the intext-ip-port-map model,
1317 // which were containing the removed external IP
1318 naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort, protocolType);
1319 //Remove the IP port incomint packer map.
1320 naptPacketInHandler.removeIncomingPacketMap(removedInternalIpPort);
1321 String[] removedInternalIpPortParts = removedInternalIpPort.split(":");
1322 if (removedInternalIpPortParts.length == 2) {
1323 String removedInternalIp = removedInternalIpPortParts[0];
1324 String removedInternalPort = removedInternalIpPortParts[1];
1325 List<String> removedInternalPortsList = internalIpPortMap.get(removedInternalPort);
1326 if (removedInternalPortsList != null) {
1327 removedInternalPortsList.add(removedInternalPort);
1328 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1330 removedInternalPortsList = new ArrayList<>();
1331 removedInternalPortsList.add(removedInternalPort);
1332 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1338 // Delete the entry from SnatIntIpPortMap DS
1339 Set<String> internalIps = internalIpPortMap.keySet();
1340 for (String internalIp : internalIps) {
1341 LOG.debug("NAT Service : Removing IpPort having the internal IP {} from the "
1342 + "model SnatIntIpPortMap", internalIp);
1343 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1346 naptManager.removeNaptPortPool(externalIp);
1348 LOG.debug("Remove the NAPT translation entries from Inbound NAPT tables for the removed "
1349 + "external IP {}", externalIp);
1350 for (Integer externalPort : externalPorts) {
1351 //Remove the NAPT translation entries from Inbound NAPT table
1352 naptEventHandler.removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1353 routerId, externalIp, externalPort);
1356 Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
1357 for (Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
1358 String internalIp = internalIpPort.getKey();
1359 LOG.debug("Remove the NAPT translation entries from Outbound NAPT tables for "
1360 + "the removed internal IP {}", internalIp);
1361 List<String> internalPorts = internalIpPort.getValue();
1362 for (String internalPort : internalPorts) {
1363 //Remove the NAPT translation entries from Outbound NAPT table
1364 naptEventHandler.removeNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1365 routerId, internalIp, Integer.valueOf(internalPort));
1369 LOG.debug("NAT Service : End processing of the External IPs removal during the update operation");
1372 //Check if its Update on subnets
1373 LOG.debug("NAT Service : Checking if this is update on subnets");
1374 List<Uuid> originalSubnetIds = original.getSubnetIds();
1375 List<Uuid> updatedSubnetIds = update.getSubnetIds();
1376 Set<Uuid> addedSubnetIds = new HashSet<>(updatedSubnetIds);
1377 addedSubnetIds.removeAll(originalSubnetIds);
1379 //Check if the Subnet IDs are added during the update.
1380 if (addedSubnetIds.size() != 0) {
1381 LOG.debug("NAT Service : Start processing of the Subnet IDs addition during the update operation");
1382 for (Uuid addedSubnetId : addedSubnetIds) {
1384 1) Select the least loaded external IP for the subnet and store the mapping of the
1385 subnet IP and the external IP in the IntExtIp model.
1386 2) Increase the count of the selected external IP by one.
1387 3) Advertise to the BGP if external IP is allocated for the first time for the
1388 router i.e. the route for the external IP is absent.
1390 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1391 if (subnetIp != null) {
1392 allocateExternalIp(dpnId, update, routerId, routerName, networkId, subnetIp);
1395 LOG.debug("NAT Service : End processing of the Subnet IDs addition during the update operation");
1398 //Check if the Subnet IDs are removed during the update.
1399 Set<Uuid> removedSubnetIds = new HashSet<>(originalSubnetIds);
1400 removedSubnetIds.removeAll(updatedSubnetIds);
1401 if (removedSubnetIds.size() != 0) {
1402 LOG.debug("NAT Service : Start processing of the Subnet IDs removal during the update operation");
1403 for (Uuid removedSubnetId : removedSubnetIds) {
1404 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1405 if (subnetAddr != null) {
1407 1) Remove the subnet IP and the external IP in the IntExtIp map
1408 2) Decrease the count of the coresponding external IP by one.
1409 3) Advertise to the BGP for removing the routes of the corresponding external
1410 IP if its not allocated to any other internal IP.
1414 naptManager.getExternalIpAllocatedForSubnet(routerId, subnetAddr[0] + "/"
1416 if (externalIp == null) {
1417 LOG.debug("No mapping found for router ID {} and internal IP {}", routerId, subnetAddr[0]);
1421 naptManager.updateCounter(routerId, externalIp, false);
1422 // Traverse entire model of external-ip counter whether external ip is not
1423 // used by any other internal ip in any router
1424 if (!isExternalIpAllocated(externalIp)) {
1425 LOG.debug("NAT Service : external ip is not allocated to any other "
1426 + "internal IP so proceeding to remove routes");
1427 List<String> externalIps = new ArrayList<>();
1428 externalIps.add(externalIp);
1429 clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId, externalIps, null);
1430 LOG.debug("Successfully removed fib entries in switch {} for "
1431 + "router {} with networkId {} and externalIps {}",
1432 dpnId, routerId, networkId, externalIps);
1435 LOG.debug("NAT Service : Remove the IP mapping for the router ID {} and "
1436 + "internal IP {} external IP {}", routerId, subnetAddr[0], externalIp);
1437 naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1440 LOG.debug("NAT Service : End processing of the Subnet IDs removal during the update operation");
1445 private boolean isExternalIpAllocated(String externalIp) {
1446 InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1447 Optional<ExternalIpsCounter> externalCountersData =
1448 MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1449 if (externalCountersData.isPresent()) {
1450 ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1451 List<ExternalCounters> externalCounters = externalIpsCounters.getExternalCounters();
1452 for (ExternalCounters ext : externalCounters) {
1453 for (ExternalIpCounter externalIpCount : ext.getExternalIpCounter()) {
1454 if (externalIpCount.getExternalIp().equals(externalIp)) {
1455 if (externalIpCount.getCounter() != 0) {
1466 private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
1467 Uuid networkId, String subnetIp) {
1468 String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1470 InetAddress address = InetAddress.getByName(subnetIpParts[0]);
1471 if (address instanceof Inet6Address) {
1472 // TODO: Revisit when IPv6 external connectivity support is added.
1473 LOG.debug("Currently skipping ipv6 address {}.", address);
1476 } catch (UnknownHostException e) {
1477 LOG.warn("Invalid ip address {}", subnetIpParts[0], e);
1480 String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1481 if (leastLoadedExtIpAddr != null) {
1482 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1483 String leastLoadedExtIp = externalIpParts[0];
1484 String leastLoadedExtIpPrefix = externalIpParts[1];
1485 IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1486 subnetIp = subnetIpParts[0];
1487 String subnetIpPrefix = subnetIpParts[1];
1488 IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1489 LOG.debug("NAT Service : Add the IP mapping for the router ID {} and internal "
1490 + "IP {} and prefix {} -> external IP {} and prefix {}",
1491 routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1492 naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1495 // Check if external IP is already assigned a route. (i.e. External IP is previously
1496 // allocated to any of the subnets)
1497 // If external IP is already assigned a route, (, do not re-advertise to the BGP
1498 String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1499 Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1500 if (label != null) {
1502 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1503 IpMapKey ipMapKey = new IpMapKey(internalIp);
1504 LOG.debug("Setting label {} for internalIp {} and externalIp {}",
1505 label, internalIp, leastLoadedExtIpAddrStr);
1506 IpMap newIpm = new IpMapBuilder().setKey(ipMapKey).setInternalIp(internalIp)
1507 .setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1508 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1509 naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1513 // Re-advertise to the BGP for the external IP, which is allocated to the subnet
1514 // for the first time and hence not having a route.
1515 //Get the VPN Name using the network ID
1516 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
1517 if (vpnName != null) {
1518 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkId);
1519 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1520 LOG.debug("Best effort for getting primary napt switch when router i/f are"
1521 + "added after gateway-set");
1522 dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1524 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1525 leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, router,
1526 vpnService, fibService, bgpManager, dataBroker, LOG);
1531 protected Long checkExternalIpLabel(long routerId, String externalIp) {
1532 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1533 for (IpMap ipMap : ipMaps) {
1534 if (ipMap.getExternalIp().equals(externalIp)) {
1535 if (ipMap.getLabel() != null) {
1536 return ipMap.getLabel();
1544 protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1545 LOG.trace("NAT Service : Router delete method");
1548 ROUTER DELETE SCENARIO
1549 1) Get the router ID from the event.
1550 2) Build the cookie information from the router ID.
1551 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1552 4) Build the flow with the cookie value.
1553 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1554 6) Remove the flows from the other switches which points to the primary and secondary
1555 switches for the flows related the router ID.
1556 7) Get the list of external IP address maintained for the router ID.
1557 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1558 9) Withdraw the corresponding routes from the BGP.
1561 if (identifier == null || router == null) {
1562 LOG.info("++++++++++++++NAT Service : ExternalRoutersListener:remove:: "
1563 + "returning without processing since routers is null");
1567 String routerName = router.getRouterName();
1568 if (natMode == NatMode.Conntrack) {
1569 if (router.isEnableSnat()) {
1570 centralizedSwitchScheduler.releaseCentralizedSwitch(routerName);
1573 LOG.info("Removing default NAT route from FIB on all dpns part of router {} ", routerName);
1574 addOrDelDefFibRouteToSNAT(routerName, false);
1575 Uuid networkUuid = router.getNetworkId();
1576 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1577 if (routerId == NatConstants.INVALID_ID) {
1578 LOG.error("NAT Service : Remove external router event - Invalid routerId for routerName {}",
1583 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1584 handleRouterGwFlows(router, primarySwitchId, NwConstants.DEL_FLOW);
1585 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1586 handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId);
1587 if (nvpnManager.getEnforceOpenstackSemanticsConfig()) {
1588 NatOverVxlanUtil.releaseVNI(routerName, idManager);
1594 private void handleRouterGwFlows(Routers router, BigInteger primarySwitchId, int addOrRemove) {
1595 WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
1596 vpnManager.setupRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
1597 router.getNetworkId(), writeTx, addOrRemove);
1598 vpnManager.setupArpResponderFlowsToExternalNetworkIps(router.getRouterName(),
1599 NatUtil.getIpsListFromExternalIps(router.getExternalIps()),
1600 router.getExtGwMacAddress(), primarySwitchId, router.getNetworkId(), writeTx, addOrRemove);
1604 // TODO Clean up the exception handling
1605 @SuppressWarnings("checkstyle:IllegalCatch")
1606 public void handleDisableSnat(Routers router, Uuid networkUuid, List<String> externalIps, boolean routerFlag,
1607 String vpnId, BigInteger naptSwitchDpnId) {
1608 LOG.info("NAT Service : handleDisableSnat() Entry");
1609 String routerName = router.getRouterName();
1611 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1612 // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
1613 // for the router ID.
1614 LOG.debug("NAT Service : Remove the Internal to external IP address maintained for the "
1615 + "router ID {} in the DS", routerId);
1616 naptManager.removeMapping(routerId);
1619 removeNaptSwitch(routerName);
1621 updateNaptSwitch(routerName, BigInteger.ZERO);
1624 LOG.debug("NAT Service : Remove the ExternalCounter model for the router ID {}", routerId);
1625 naptManager.removeExternalCounter(routerId);
1627 LOG.debug("NAT Service : got primarySwitch as dpnId {}", naptSwitchDpnId);
1628 if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
1629 LOG.error("NAT Service : Unable to retrieve the primary NAPT switch for the "
1630 + "router ID {} from RouterNaptSwitch model", routerId);
1633 removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId, externalIps);
1634 removeFlowsFromNonActiveSwitches(routerName, naptSwitchDpnId, networkUuid);
1636 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1637 } catch (Exception ex) {
1638 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}",
1639 routerId, naptSwitchDpnId, ex);
1642 } catch (Exception ex) {
1643 LOG.error("Exception while handling disableSNAT : {}", ex);
1645 LOG.info("NAT Service : handleDisableSnat() Exit");
1648 // TODO Clean up the exception handling
1649 @SuppressWarnings("checkstyle:IllegalCatch")
1650 public void handleDisableSnatInternetVpn(String routerName, Uuid networkUuid, List<String> externalIps,
1651 boolean routerFlag, String vpnId) {
1652 LOG.debug("NAT Service : handleDisableSnatInternetVpn() Entry");
1654 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1655 BigInteger naptSwitchDpnId = null;
1656 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
1657 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1658 Optional<RouterToNaptSwitch> rtrToNapt =
1659 read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1660 if (rtrToNapt.isPresent()) {
1661 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1663 LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1665 removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId);
1667 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1668 } catch (Exception ex) {
1669 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}",
1670 routerId, naptSwitchDpnId, ex);
1672 NatOverVxlanUtil.releaseVNI(vpnId, idManager);
1673 } catch (Exception ex) {
1674 LOG.error("Exception while handling disableSNATInternetVpn : {}", ex);
1676 LOG.debug("NAT Service : handleDisableSnatInternetVpn() Exit");
1679 // TODO Clean up the exception handling
1680 @SuppressWarnings("checkstyle:IllegalCatch")
1681 public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1682 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
1683 .setPrimarySwitchId(naptSwitchId).build();
1685 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1686 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1687 } catch (Exception ex) {
1688 LOG.error("Failed to write naptSwitch {} for router {} in ds",
1689 naptSwitchId, routerName);
1691 LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
1692 naptSwitchId, routerName);
1695 protected void removeNaptSwitch(String routerName) {
1696 // Remove router and switch from model
1697 InstanceIdentifier<RouterToNaptSwitch> id =
1698 InstanceIdentifier.builder(NaptSwitches.class)
1699 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1700 LOG.debug("NAPT Service : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1701 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1702 //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
1703 NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
1706 public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
1707 BigInteger dpnId, Uuid networkId, String vpnName,
1708 List<String> externalIps) {
1709 LOG.debug("NAT Service : Remove NAPT flows from Active switch");
1710 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1712 //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1713 // traffic which comes from the VMs of the NAPT switches)
1714 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1715 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1717 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1718 NwConstants.PSNAT_TABLE, dpnId, routerId);
1719 mdsalManager.removeFlow(preSnatFlowEntity);
1721 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1722 // traffic which comes from the VMs of the non NAPT switches)
1723 long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
1724 String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
1725 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1726 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1727 NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
1728 mdsalManager.removeFlow(tsNatFlowEntity);
1730 //Remove the Outbound flow entry which forwards the packet to FIB Table
1731 String outboundNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
1732 FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1733 outboundNatFlowRef);
1735 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1736 NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1737 mdsalManager.removeFlow(outboundNatFlowEntity);
1739 removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps);
1741 //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1742 String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1743 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1745 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1746 NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
1747 mdsalManager.removeFlow(natPfibFlowEntity);
1749 // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
1750 // - This does not work since ext-routers is deleted already - no network info
1751 //Get the VPN ID from the ExternalNetworks model
1753 if ((vpnName == null) || (vpnName.isEmpty())) {
1754 // ie called from router delete cases
1755 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1756 LOG.debug("NAT Service : vpnUuid is {}", vpnUuid);
1757 if (vpnUuid != null) {
1758 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1759 LOG.debug("NAT Service : vpnId for routerdelete or disableSNAT scenario {}", vpnId);
1762 // ie called from disassociate vpn case
1763 LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1764 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1765 LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId);
1768 if (vpnId != NatConstants.INVALID_ID) {
1769 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1770 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
1771 FlowEntity natPfibVpnFlowEntity =
1772 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1773 LOG.info("NAT Service : Remove the flow in the for the active switch with the DPN ID {} and VPN ID {}",
1774 NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
1775 mdsalManager.removeFlow(natPfibVpnFlowEntity);
1778 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
1779 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1780 if (ipPortMapping == null) {
1781 LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1785 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1786 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1787 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1788 for (IpPortMap ipPortMap : ipPortMaps) {
1789 String ipPortInternal = ipPortMap.getIpPortInternal();
1790 String[] ipPortParts = ipPortInternal.split(":");
1791 if (ipPortParts.length != 2) {
1792 LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1795 String internalIp = ipPortParts[0];
1796 String internalPort = ipPortParts[1];
1798 //Build the flow for the outbound NAPT table
1799 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1800 String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1801 FlowEntity outboundNaptFlowEntity =
1802 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1804 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and "
1805 + "router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1806 mdsalManager.removeFlow(outboundNaptFlowEntity);
1808 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1809 String externalIp = ipPortExternal.getIpAddress();
1810 int externalPort = ipPortExternal.getPortNum();
1812 //Build the flow for the inbound NAPT table
1813 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1814 String.valueOf(routerId), externalIp, externalPort);
1815 FlowEntity inboundNaptFlowEntity =
1816 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1818 LOG.info("NAT Service : Remove the flow in the {} for the active active switch with the "
1819 + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
1820 mdsalManager.removeFlow(inboundNaptFlowEntity);
1825 protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
1826 List<String> externalIps) {
1827 Long extVpnId = null;
1828 if (networkId != null) {
1829 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1830 if (vpnUuid != null) {
1831 extVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1833 LOG.debug("NAT Service: removeNaptFibExternalOutputFlows - vpnUuid is null");
1836 LOG.debug("NAT Service: removeNaptFibExternalOutputFlows - networkId is null");
1837 extVpnId = NatUtil.getVpnId(dataBroker, routerId);
1839 if (extVpnId == null || extVpnId == NatConstants.INVALID_ID) {
1840 LOG.debug("removeNaptFibExternalOutputFlows - extVpnId not found for routerId {}", routerId);
1841 extVpnId = routerId;
1843 for (String ip : externalIps) {
1844 String extIp = removeMaskFromIp(ip);
1845 String naptFlowRef = getFlowRefNaptFib(dpnId, NwConstants.NAPT_PFIB_TABLE, extVpnId, extIp);
1846 LOG.info("NAT Service: Remove the flow in the " + NwConstants.NAPT_PFIB_TABLE + " for the active switch"
1847 + " with the DPN ID {} and router ID {} and IP {} flowRef {}", dpnId, routerId, extIp, naptFlowRef);
1848 mdsalManager.removeFlow(NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef));
1852 private String removeMaskFromIp(String ip) {
1853 if (ip != null && !ip.trim().isEmpty()) {
1854 return ip.split("/")[0];
1859 public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
1860 BigInteger dpnId, Uuid networkId, String vpnName) {
1861 LOG.debug("NAT Service : Remove NAPT flows from Active switch Internet Vpn");
1862 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1864 //Remove the NAPT PFIB TABLE entry
1866 if (vpnName != null) {
1867 // ie called from disassociate vpn case
1868 LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1869 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1870 LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId);
1873 if (vpnId != NatConstants.INVALID_ID) {
1874 //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1875 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
1876 FlowEntity natPfibVpnFlowEntity =
1877 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1878 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} "
1879 + "and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
1880 mdsalManager.removeFlow(natPfibVpnFlowEntity);
1882 // Remove IP-PORT active NAPT entries and release port from IdManager
1883 // For the router ID get the internal IP , internal port and the corresponding
1884 // external IP and external Port.
1885 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1886 if (ipPortMapping == null) {
1887 LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1890 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1891 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1892 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1893 for (IpPortMap ipPortMap : ipPortMaps) {
1894 String ipPortInternal = ipPortMap.getIpPortInternal();
1895 String[] ipPortParts = ipPortInternal.split(":");
1896 if (ipPortParts.length != 2) {
1897 LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1900 String internalIp = ipPortParts[0];
1901 String internalPort = ipPortParts[1];
1903 //Build the flow for the outbound NAPT table
1904 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1905 String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1906 FlowEntity outboundNaptFlowEntity =
1907 NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1909 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the "
1910 + "DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1911 mdsalManager.removeFlow(outboundNaptFlowEntity);
1913 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1914 String externalIp = ipPortExternal.getIpAddress();
1915 int externalPort = ipPortExternal.getPortNum();
1917 //Build the flow for the inbound NAPT table
1918 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1919 String.valueOf(routerId), externalIp, externalPort);
1920 FlowEntity inboundNaptFlowEntity =
1921 NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1923 LOG.info("NAT Service : Remove the flow in the {} for the active active switch with "
1924 + "the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
1925 mdsalManager.removeFlow(inboundNaptFlowEntity);
1927 // Finally release port from idmanager
1928 String internalIpPort = internalIp + ":" + internalPort;
1929 naptManager.removePortFromPool(internalIpPort, externalIp);
1931 //Remove sessions from models
1932 naptManager.removeIpPortMappingForRouterID(routerId);
1933 naptManager.removeIntIpPortMappingForRouterID(routerId);
1937 LOG.error("NAT Service : Invalid vpnId {}", vpnId);
1941 public void removeFlowsFromNonActiveSwitches(String routerName, BigInteger naptSwitchDpnId, Uuid networkId) {
1942 LOG.debug("NAT Service : Remove NAPT related flows from non active switches");
1944 // Remove the flows from the other switches which points to the primary and secondary switches
1945 // for the flows related the router ID.
1946 List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
1947 if (allSwitchList == null || allSwitchList.isEmpty()) {
1948 LOG.error("NAT Service : Unable to get the swithces for the router {}", routerName);
1951 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1952 for (BigInteger dpnId : allSwitchList) {
1953 if (!naptSwitchDpnId.equals(dpnId)) {
1954 LOG.info("NAT Service : Handle Ordinary switch");
1956 //Remove the PSNAT entry which forwards the packet to Terminating Service table
1957 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
1958 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1960 LOG.info("Remove the flow in the {} for the non active switch with the DPN ID {} and router ID {}",
1961 NwConstants.PSNAT_TABLE, dpnId, routerId);
1962 mdsalManager.removeFlow(preSnatFlowEntity);
1964 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
1965 long groupId = createGroupId(getGroupIdKey(routerName));
1966 List<BucketInfo> listBucketInfo = new ArrayList<>();
1967 GroupEntity preSnatGroupEntity =
1968 MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
1970 LOG.info("NAT Service : Remove the group {} for the non active switch with the DPN ID {} "
1971 + "and router ID {}", groupId, dpnId, routerId);
1972 mdsalManager.removeGroup(preSnatGroupEntity);
1978 public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid,
1979 List<String> externalIps, String vpnName) {
1980 //Withdraw the corresponding routes from the BGP.
1981 //Get the network ID using the router ID.
1982 LOG.debug("NAT Service : Advertise to BGP and remove routes for externalIps {} with routerId {},"
1983 + "network Id {} and vpnName {}",
1984 externalIps, routerId, networkUuid, vpnName);
1985 if (networkUuid == null) {
1986 LOG.error("NAT Service : networkId is null");
1990 if (externalIps == null || externalIps.isEmpty()) {
1991 LOG.debug("NAT Service : externalIps is null");
1995 if (vpnName == null) {
1996 //Get the VPN Name using the network ID
1997 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
1998 if (vpnName == null) {
1999 LOG.error("No VPN associated with ext nw {} for the router {}",
2000 networkUuid, routerId);
2004 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2006 //Remove custom FIB routes
2007 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2008 for (String extIp : externalIps) {
2009 clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName);
2013 protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
2014 clearBgpRoutes(extIp, vpnName);
2015 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
2018 protected void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp,
2019 final String vpnName, long tempLabel) {
2020 LOG.debug("NAT Service : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2021 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2022 if (routerName == null) {
2023 LOG.error("NAT Service : Could not retrieve Router Name from Router ID {} ", routerId);
2026 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
2027 if (extNwProvType == null) {
2030 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2031 * external network provided type is VxLAN
2033 if (extNwProvType == ProviderTypes.VXLAN) {
2034 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
2037 if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
2038 LOG.error("NAT Service : Label not found for externalIp {} with router id {}", extIp, routerId);
2042 final long label = tempLabel;
2043 final String externalIp = extIp;
2045 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
2046 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
2047 Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
2049 ListenableFuture<RpcResult<Void>> labelFuture =
2050 Futures.transform(JdkFutureAdapters.listenInPoolThread(future),
2051 (AsyncFunction<RpcResult<Void>, RpcResult<Void>>) result -> {
2053 if (result.isSuccessful()) {
2054 removeTunnelTableEntry(dpnId, label);
2055 removeLFibTableEntry(dpnId, label);
2056 NatUtil.removePreDnatToSnatTableEntry(mdsalManager, dpnId);
2057 RemoveVpnLabelInput labelInput =
2058 new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
2059 Future<RpcResult<Void>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
2060 return JdkFutureAdapters.listenInPoolThread(labelFuture1);
2063 String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s "
2064 + "Failed - %s", dpnId, externalIp, result.getErrors());
2066 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2070 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
2073 public void onFailure(Throwable error) {
2074 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
2078 public void onSuccess(RpcResult<Void> result) {
2079 if (result.isSuccessful()) {
2080 LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}",
2081 externalIp, vpnName);
2083 LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}",
2084 externalIp, vpnName, result.getErrors());
2090 private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
2091 LOG.debug("NAT Service : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2092 String routerName = NatUtil.getRouterName(dataBroker,routerId);
2093 if (routerName == null) {
2094 LOG.error("NAT Service : Could not retrieve Router Name from Router ID {} ", routerId);
2097 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
2098 if (extNwProvType == null) {
2101 /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2102 * external network provided type is VxLAN
2104 if (extNwProvType == ProviderTypes.VXLAN) {
2105 evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
2108 //Get IPMaps from the DB for the router ID
2109 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
2110 if (dbIpMaps == null || dbIpMaps.isEmpty()) {
2111 LOG.error("NAT Service : IPMaps not found for router {}", routerId);
2115 long tempLabel = NatConstants.INVALID_ID;
2116 for (IpMap dbIpMap : dbIpMaps) {
2117 String dbExternalIp = dbIpMap.getExternalIp();
2118 LOG.debug("Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
2119 //Select the IPMap, whose external IP is the IP for which FIB is installed
2120 if (extIp.equals(dbExternalIp)) {
2121 tempLabel = dbIpMap.getLabel();
2122 LOG.debug("Retrieved label {} for dbExternalIp {} with router id {}",
2123 tempLabel, dbExternalIp, routerId);
2127 if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
2128 LOG.error("NAT Service : Label not found for externalIp {} with router id {}", extIp, routerId);
2132 final long label = tempLabel;
2133 final String externalIp = extIp;
2135 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
2136 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
2137 Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
2139 ListenableFuture<RpcResult<Void>> labelFuture =
2140 Futures.transform(JdkFutureAdapters.listenInPoolThread(future),
2141 (AsyncFunction<RpcResult<Void>, RpcResult<Void>>) result -> {
2143 if (result.isSuccessful()) {
2144 removeTunnelTableEntry(dpnId, label);
2145 removeLFibTableEntry(dpnId, label);
2146 RemoveVpnLabelInput labelInput =
2147 new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
2148 Future<RpcResult<Void>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
2149 return JdkFutureAdapters.listenInPoolThread(labelFuture1);
2152 String.format("RPC call to remove custom FIB entries on dpn %s for "
2153 + "prefix %s Failed - %s",
2154 dpnId, externalIp, result.getErrors());
2156 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2160 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
2163 public void onFailure(Throwable error) {
2164 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
2168 public void onSuccess(RpcResult<Void> result) {
2169 if (result.isSuccessful()) {
2170 LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}",
2171 externalIp, vpnName);
2173 LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}",
2174 externalIp, vpnName, result.getErrors());
2180 protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2181 List<String> externalIps, String vpnName) {
2182 //Withdraw the corresponding routes from the BGP.
2183 //Get the network ID using the router ID.
2184 LOG.debug("NAT Service : clearFibTsAndReverseTraffic for externalIps {} with routerId {},"
2185 + "network Id {} and vpnName {}",
2186 externalIps, routerId, networkUuid, vpnName);
2187 if (networkUuid == null) {
2188 LOG.error("NAT Service : networkId is null");
2192 if (externalIps == null || externalIps.isEmpty()) {
2193 LOG.debug("NAT Service : externalIps is null");
2197 if (vpnName == null) {
2198 //Get the VPN Name using the network ID
2199 vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
2200 if (vpnName == null) {
2201 LOG.error("No VPN associated with ext nw {} for the router {}",
2202 networkUuid, routerId);
2206 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2208 //Remove custom FIB routes
2209 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2210 for (String extIp : externalIps) {
2211 delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
2215 protected void clearBgpRoutes(String externalIp, final String vpnName) {
2216 //Inform BGP about the route removal
2217 LOG.info("Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
2218 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
2219 NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp, vpnName, LOG);
2222 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
2223 LOG.info("NAT Service : remove terminatingServiceActions called with DpnId = {} and label = {}",
2225 List<MatchInfo> mkMatches = new ArrayList<>();
2226 // Matching metadata
2227 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
2228 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
2229 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
2230 5, String.format("%s:%d", "TST Flow Entry ", serviceId), 0, 0,
2231 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
2232 mdsalManager.removeFlow(dpnId, flowEntity);
2233 LOG.debug("NAT Service : Terminating service Entry for dpID {} : label : {} removed successfully {}",
2237 private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
2238 List<MatchInfo> matches = new ArrayList<>();
2239 matches.add(MatchEthernetType.MPLS_UNICAST);
2240 matches.add(new MatchMplsLabel(serviceId));
2242 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2244 LOG.debug("NAT Service : removing LFib entry with flow ref {}", flowRef);
2246 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
2248 COOKIE_VM_LFIB_TABLE, matches, null);
2250 mdsalManager.removeFlow(dpnId, flowEntity);
2252 LOG.debug("NAT Service : LFIB Entry for dpID : {} label : {} removed successfully", dpnId, serviceId);
2256 * router association to vpn.
2258 * @param routerName - Name of router
2259 * @param bgpVpnName BGP VPN name
2261 public void changeLocalVpnIdToBgpVpnId(String routerName, String bgpVpnName) {
2262 LOG.debug("NAT Service : Router associated to BGP VPN");
2263 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2264 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2266 LOG.debug("BGP VPN ID value {} ", bgpVpnId);
2268 if (bgpVpnId != NatConstants.INVALID_ID) {
2269 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
2270 bgpVpnId, bgpVpnName);
2271 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId))
2272 .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2273 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2274 getRoutersIdentifier(bgpVpnId), rtrs);
2276 // Get the allocated Primary NAPT Switch for this router
2277 long routerId = NatUtil.getVpnId(dataBroker, routerName);
2278 LOG.debug("Router ID value {} ", routerId);
2279 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2281 LOG.debug("NAT Service : Update the Router ID {} to the BGP VPN ID {} ", routerId, bgpVpnId);
2282 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, bgpVpnId, true);
2285 long groupId = createGroupId(getGroupIdKey(routerName));
2286 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true);
2292 * router disassociation from vpn.
2294 * @param routerName - Name of router
2295 * @param bgpVpnName BGP VPN name
2297 public void changeBgpVpnIdToLocalVpnId(String routerName, String bgpVpnName) {
2298 LOG.debug("NAT Service : Router dissociated from BGP VPN");
2299 if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2300 long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2301 LOG.debug("BGP VPN ID value {} ", bgpVpnId);
2303 // Get the allocated Primary NAPT Switch for this router
2304 long routerId = NatUtil.getVpnId(dataBroker, routerName);
2305 LOG.debug("Router ID value {} ", routerId);
2306 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2308 LOG.debug("NAT Service : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2309 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, NatConstants.INVALID_ID, true);
2312 long groupId = createGroupId(getGroupIdKey(routerName));
2313 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true);
2317 boolean chkExtRtrAndSnatEnbl(Uuid routerUuid) {
2318 InstanceIdentifier<Routers> routerInstanceIndentifier =
2319 InstanceIdentifier.builder(ExtRouters.class)
2320 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
2321 Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2322 return routerData.isPresent() && routerData.get().isEnableSnat();
2325 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2326 long routerId, boolean isSnatCfgd) {
2327 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, isSnatCfgd, null);
2330 public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2331 long routerId, boolean isSnatCfgd, Routers router) {
2332 long changedVpnId = bgpVpnId;
2333 String logMsg = "NAT Service : Update the BGP VPN ID {}";
2334 if (bgpVpnId == NatConstants.INVALID_ID) {
2335 changedVpnId = routerId;
2336 logMsg = "NAT Service : Update the router ID {}";
2339 List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2340 if (switches == null || switches.isEmpty()) {
2341 LOG.debug("No switches found for router {}", routerName);
2344 for (BigInteger dpnId : switches) {
2345 // Update the BGP VPN ID in the SNAT miss entry to group
2346 if (!dpnId.equals(primarySwitchId)) {
2347 LOG.debug("NAT Service : Install group in non NAPT switch {}", dpnId);
2348 List<BucketInfo> bucketInfoForNonNaptSwitches =
2349 getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName);
2350 long groupId = createGroupId(getGroupIdKey(routerName));
2352 groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
2355 LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
2356 changedVpnId, groupId, dpnId);
2357 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
2358 mdsalManager.installFlow(flowEntity);
2360 LOG.debug(logMsg + " in the SNAT miss entry pointing to group in the primary switch {}",
2361 changedVpnId, primarySwitchId);
2362 FlowEntity flowEntity =
2363 buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2364 mdsalManager.installFlow(flowEntity);
2366 LOG.debug(logMsg + " in the Terminating Service table (table ID 36) which forwards the packet"
2367 + " to the table 46 in the Primary switch {}", changedVpnId, primarySwitchId);
2368 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, changedVpnId);
2370 LOG.debug(logMsg + " in the Outbound NAPT table (table ID 46) which punts the packet to the"
2371 + " controller in the Primary switch {}", changedVpnId, primarySwitchId);
2372 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2374 LOG.debug(logMsg + " in the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table in the"
2375 + "Primary switch {}",
2376 changedVpnId, primarySwitchId);
2377 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2379 LOG.debug(logMsg + " in the NAPT flows for the Outbound NAPT table (table ID 46) and the "
2380 + "INBOUND NAPT table (table ID 44) in the Primary switch {}",
2381 changedVpnId, primarySwitchId);
2382 updateNaptFlowsWithVpnId(primarySwitchId, routerId, bgpVpnId);
2384 LOG.debug("NAT Service : Installing SNAT PFIB flow in the primary switch {}", primarySwitchId);
2385 Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
2386 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2387 if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
2388 installNaptPfibEntry(primarySwitchId, vpnId);
2394 public void updateNaptFlowsWithVpnId(BigInteger dpnId, long routerId, long bgpVpnId) {
2395 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2396 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2397 if (ipPortMapping == null) {
2398 LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
2401 // Get the External Gateway MAC Address
2402 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
2403 if (extGwMacAddress != null) {
2404 LOG.debug("External Gateway MAC address {} found for External Router ID {}", extGwMacAddress, routerId);
2406 LOG.error("No External Gateway MAC address found for External Router ID {}", routerId);
2409 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2410 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
2411 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2412 for (IpPortMap ipPortMap : ipPortMaps) {
2413 String ipPortInternal = ipPortMap.getIpPortInternal();
2414 String[] ipPortParts = ipPortInternal.split(":");
2415 if (ipPortParts.length != 2) {
2416 LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
2419 String internalIp = ipPortParts[0];
2420 String internalPort = ipPortParts[1];
2421 LOG.debug("NAT Service : Found Internal IP {} and Internal Port {}", internalIp, internalPort);
2422 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2423 NAPTEntryEvent.Protocol protocol;
2424 switch (protocolTypes) {
2426 protocol = NAPTEntryEvent.Protocol.TCP;
2429 protocol = NAPTEntryEvent.Protocol.UDP;
2432 protocol = NAPTEntryEvent.Protocol.TCP;
2434 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.valueOf(internalPort));
2435 SessionAddress externalAddress =
2436 naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2437 long internetVpnid = NatUtil.getVpnId(dataBroker, routerId);
2438 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
2439 routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
2440 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
2441 routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
2446 public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
2447 long changedVpnId) {
2449 LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} groupId {} "
2450 + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
2451 List<MatchInfo> matches = new ArrayList<>();
2452 matches.add(MatchEthernetType.IPV4);
2453 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2455 List<ActionInfo> actionsInfo = new ArrayList<>();
2456 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, nvpnManager, idManager,
2457 changedVpnId, routerName);
2458 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
2459 LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
2460 actionsInfo.add(new ActionGroup(groupId));
2461 List<InstructionInfo> instructions = new ArrayList<>();
2462 instructions.add(new InstructionApplyActions(actionsInfo));
2463 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2464 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2465 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2466 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2468 LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2472 public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
2473 long changedVpnId) {
2475 LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} changed VPN ID {}",
2476 dpId, routerName, changedVpnId);
2477 List<MatchInfo> matches = new ArrayList<>();
2478 matches.add(MatchEthernetType.IPV4);
2479 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2481 List<InstructionInfo> instructions = new ArrayList<>();
2482 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2484 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2485 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2486 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2487 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2489 LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2493 // TODO : Replace this with ITM Rpc once its available with full functionality
2494 protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
2495 long changedVpnId) {
2496 LOG.debug("NAT Service : installTerminatingServiceTblEntryWithUpdatedVpnId called for switch {}, "
2497 + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2498 FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, changedVpnId);
2499 mdsalManager.installFlow(flowEntity);
2503 private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long changedVpnId) {
2504 LOG.debug("NAT Service : buildTsFlowEntityWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}",
2505 dpId, routerName, changedVpnId);
2506 List<MatchInfo> matches = new ArrayList<>();
2507 matches.add(MatchEthernetType.IPV4);
2509 BigInteger tunnelId = BigInteger.valueOf(changedVpnId);
2510 if (nvpnManager.getEnforceOpenstackSemanticsConfig()) {
2511 tunnelId = NatOverVxlanUtil.getRouterVni(idManager, routerName, changedVpnId);
2513 matches.add(new MatchTunnelId(tunnelId));
2515 List<InstructionInfo> instructions = new ArrayList<>();
2516 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2517 MetaDataUtil.METADATA_MASK_VRFID));
2518 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2519 BigInteger routerId = BigInteger.valueOf(NatUtil.getVpnId(dataBroker, routerName));
2520 String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2521 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2522 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2523 NwConstants.COOKIE_TS_TABLE, matches, instructions);
2527 public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId) {
2528 LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}, BGP VPN ID {}",
2529 dpnId, routerId, changedVpnId);
2530 FlowEntity flowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId);
2531 LOG.debug("NAT Service : Installing flow {}", flowEntity);
2532 mdsalManager.installFlow(flowEntity);
2535 protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId, long changedVpnId) {
2536 LOG.debug("NAT Service : buildOutboundFlowEntityWithBgpVpn called for dpId {} and routerId {}, BGP VPN ID {}",
2537 dpId, routerId, changedVpnId);
2538 List<MatchInfo> matches = new ArrayList<>();
2539 matches.add(MatchEthernetType.IPV4);
2540 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2542 List<InstructionInfo> instructions = new ArrayList<>();
2543 List<ActionInfo> actionsInfos = new ArrayList<>();
2544 actionsInfos.add(new ActionPuntToController());
2545 instructions.add(new InstructionApplyActions(actionsInfos));
2546 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2547 MetaDataUtil.METADATA_MASK_VRFID));
2549 String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
2550 BigInteger cookie = getCookieOutboundFlow(routerId);
2551 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
2552 flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
2553 LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
2557 public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId) {
2558 LOG.debug("NAT Service : installNaptPfibEntryWithBgpVpn called for dpnId {} and segmentId {} ,BGP VPN ID {}",
2559 dpnId, segmentId, changedVpnId);
2560 FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2561 mdsalManager.installFlow(naptPfibFlowEntity);
2564 public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2566 LOG.debug("NAT Service : buildNaptPfibFlowEntityWithUpdatedVpnId is called for dpId {}, "
2567 + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2568 List<MatchInfo> matches = new ArrayList<>();
2569 matches.add(MatchEthernetType.IPV4);
2570 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2572 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2573 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2574 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
2575 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2576 instructionInfo.add(new InstructionApplyActions(listActionInfo));
2578 String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2579 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2580 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2581 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2582 LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
2587 protected ExternalRoutersListener getDataTreeChangeListener() {
2588 return ExternalRoutersListener.this;
2591 protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId) {
2592 List<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
2594 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
2595 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
2596 if (subnetVpnId != -1) {
2597 LOG.debug("NAT Service : Calling externalRouterListener installNaptPfibEntry for dpnId {} "
2598 + "and vpnId {}", dpnId, subnetVpnId);
2599 installNaptPfibEntry(dpnId, subnetVpnId);