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 java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.HashSet;
16 import java.util.List;
18 import java.util.Map.Entry;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import javax.annotation.Nonnull;
23 import javax.inject.Inject;
24 import javax.inject.Singleton;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
30 import org.opendaylight.genius.mdsalutil.ActionInfo;
31 import org.opendaylight.genius.mdsalutil.BucketInfo;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
33 import org.opendaylight.genius.mdsalutil.GroupEntity;
34 import org.opendaylight.genius.mdsalutil.InstructionInfo;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.mdsalutil.MatchInfo;
37 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
38 import org.opendaylight.genius.mdsalutil.NwConstants;
39 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
40 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
41 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
46 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
47 import org.opendaylight.netvirt.elanmanager.api.IElanService;
48 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
49 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
80 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;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
84 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
85 import org.opendaylight.yangtools.yang.common.RpcResult;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
90 public class NaptSwitchHA {
91 private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
92 private final DataBroker dataBroker;
93 private final IMdsalApiManager mdsalManager;
94 private final ItmRpcService itmManager;
95 private final OdlInterfaceRpcService odlInterfaceRpcService;
96 private final IdManagerService idManager;
97 private final NAPTSwitchSelector naptSwitchSelector;
98 private final ExternalRoutersListener externalRouterListener;
99 private final NaptEventHandler naptEventHandler;
100 private final IFibManager fibManager;
101 private final IElanService elanManager;
102 private final EvpnNaptSwitchHA evpnNaptSwitchHA;
103 private final SnatServiceManager natServiceManager;
104 private final NatMode natMode;
105 private final IInterfaceManager interfaceManager;
107 private volatile Collection<String> externalIpsCache;
110 public NaptSwitchHA(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
111 final ExternalRoutersListener externalRouterListener,
112 final ItmRpcService itmManager,
113 final OdlInterfaceRpcService odlInterfaceRpcService,
114 final IdManagerService idManager,
115 final NAPTSwitchSelector naptSwitchSelector,
116 final IFibManager fibManager,
117 final EvpnNaptSwitchHA evpnNaptSwitchHA,
118 final IElanService elanManager,
119 final SnatServiceManager natServiceManager,
120 final NatserviceConfig config,
121 final NaptEventHandler naptEventHandler,
122 final IInterfaceManager interfaceManager) {
123 this.dataBroker = dataBroker;
124 this.mdsalManager = mdsalManager;
125 this.externalRouterListener = externalRouterListener;
126 this.itmManager = itmManager;
127 this.odlInterfaceRpcService = odlInterfaceRpcService;
128 this.idManager = idManager;
129 this.naptSwitchSelector = naptSwitchSelector;
130 this.naptEventHandler = naptEventHandler;
131 this.fibManager = fibManager;
132 this.evpnNaptSwitchHA = evpnNaptSwitchHA;
133 this.elanManager = elanManager;
134 this.natServiceManager = natServiceManager;
135 this.interfaceManager = interfaceManager;
136 if (config != null) {
137 this.natMode = config.getNatMode();
139 this.natMode = NatMode.Controller;
143 /* This method checks the switch that gone down is a NaptSwitch for a router.
144 If it is a NaptSwitch
145 1) selects new NAPT switch
146 2) installs nat flows in new NAPT switch
147 table 21(FIB)->26(PSNAT)->group(resubmit/napttunnel)->36(Terminating)->46(outbound)->47(resubmit)->21
148 3) modify the group and miss entry flow in other vSwitches pointing to newNaptSwitch
149 4) Remove nat flows in oldNaptSwitch
151 /*public void handleNaptSwitchDown(BigInteger dpnId){
153 LOG.debug("handleNaptSwitchDown method is called with dpnId {}",dpnId);
154 BigInteger naptSwitch;
156 NaptSwitches naptSwitches = NatUtil.getNaptSwitch(dataBroker);
157 if (naptSwitches == null || naptSwitches.getRouterToNaptSwitch() == null
158 || naptSwitches.getRouterToNaptSwitch().isEmpty()) {
159 LOG.debug("NaptSwitchDown: NaptSwitch is not allocated for none of the routers");
162 for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
163 String routerName = routerToNaptSwitch.getRouterName();
164 naptSwitch = routerToNaptSwitch.getPrimarySwitchId();
165 boolean naptStatus = isNaptSwitchDown(routerName,dpnId,naptSwitch);
167 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
170 removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
174 } catch (Exception ex) {
175 LOG.error("Exception in handleNaptSwitchDown method {}",ex);
179 protected void removeSnatFlowsInOldNaptSwitch(String routerName, Long routerId, BigInteger naptSwitch,
180 Map<String, Long> externalIpmap, WriteTransaction removeFlowInvTx) {
181 //remove SNAT flows in old NAPT SWITCH
182 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
183 String vpnName = getExtNetworkVpnName(routerName, networkId);
184 if (vpnName == null) {
185 LOG.error("removeSnatFlowsInOldNaptSwitch : Vpn is not associated to externalN/w of router {}",
189 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, networkId);
190 if (extNwProvType == null) {
191 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the External Network Provider Type "
192 + "for Router {}", routerName);
195 if (extNwProvType == ProviderTypes.VXLAN) {
196 evpnNaptSwitchHA.evpnRemoveSnatFlowsInOldNaptSwitch(routerName, routerId, vpnName, naptSwitch,
199 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
200 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
202 String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
204 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
207 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
208 + "with the DPN ID {} and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
209 mdsalManager.removeFlowToTx(tsNatFlowEntity, removeFlowInvTx);
211 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
212 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
213 NatUtil.removePreDnatToSnatTableEntry(mdsalManager, naptSwitch, removeFlowInvTx);
215 //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
216 String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
217 NwConstants.OUTBOUND_NAPT_TABLE, routerId);
218 FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
219 NwConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
220 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
221 NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
222 mdsalManager.removeFlowToTx(outboundNatFlowEntity, removeFlowInvTx);
224 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
225 // External Subnet Vpn Id.
226 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
228 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
229 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
230 if (subnetVpnId != -1) {
231 String natPfibSubnetFlowRef = externalRouterListener.getFlowRefTs(naptSwitch,
232 NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
233 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,
234 natPfibSubnetFlowRef);
235 mdsalManager.removeFlowToTx(natPfibFlowEntity, removeFlowInvTx);
236 LOG.debug("removeSnatFlowsInOldNaptSwitch : Removed the flow in table {} with external subnet "
237 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
238 subnetVpnId, naptSwitch);
242 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic
243 // matching on the router ID.
244 String naptPFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
245 FlowEntity naptPFibFlowEntity =
246 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
247 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
248 + "with the DPN ID {} and router ID {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
249 mdsalManager.removeFlowToTx(naptPFibFlowEntity, removeFlowInvTx);
251 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic
252 // matching on the vpn ID.
253 boolean switchSharedByRouters = false;
254 Uuid extNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
255 if (extNetworkId != null) {
256 List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
257 for (String routerNameAssociated : routerNamesAssociated) {
258 if (!routerNameAssociated.equals(routerName)) {
259 Long routerIdAssociated = NatUtil.getVpnId(dataBroker, routerNameAssociated);
260 BigInteger naptDpn = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerNameAssociated);
261 if (naptDpn != null && naptDpn.equals(naptSwitch)) {
262 LOG.debug("removeSnatFlowsInOldNaptSwitch : Napt switch {} is also acting as primary "
263 + "for router {}", naptSwitch, routerIdAssociated);
264 switchSharedByRouters = true;
269 if (!switchSharedByRouters) {
270 Long vpnId = getVpnIdForRouter(routerId, extNetworkId);
271 if (vpnId != NatConstants.INVALID_ID) {
272 String naptFibflowRef =
273 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
274 FlowEntity naptFibFlowEntity =
275 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptFibflowRef);
276 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch"
277 + " with the DPN ID {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
278 mdsalManager.removeFlowToTx(naptFibFlowEntity, removeFlowInvTx);
280 LOG.error("removeSnatFlowsInOldNaptSwitch : Invalid vpnId retrieved for routerId {}",
287 //Remove Fib entries,tables 20->44 ,36-> 44
288 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
289 if (externalIpmap != null && !externalIpmap.isEmpty()) {
290 for (Entry<String, Long> entry : externalIpmap.entrySet()) {
291 String externalIp = entry.getKey();
292 Long label = entry.getValue();
293 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
294 extNetworkId, label, gwMacAddress, true, removeFlowInvTx);
295 LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} "
296 + "for router {} and externalIps {} label {}", naptSwitch, routerId, externalIp, label);
299 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
300 if (networkId != null) {
301 externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, networkId,
302 externalIps, null, gwMacAddress, removeFlowInvTx);
303 LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} for "
304 + "router {} with networkId {} and externalIps {}", naptSwitch, routerId, networkId,
307 LOG.debug("removeSnatFlowsInOldNaptSwitch : External network not associated to router {}", routerId);
309 externalRouterListener.removeNaptFibExternalOutputFlows(routerId, naptSwitch, extNetworkId,
310 externalIps, removeFlowInvTx);
313 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
314 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
315 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
316 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
317 LOG.warn("removeSnatFlowsInOldNaptSwitch : No Internal Ip Port mapping associated to router {}, "
318 + "no flows need to be removed in oldNaptSwitch {}", routerId, naptSwitch);
321 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
322 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
323 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
324 if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
325 LOG.debug("removeSnatFlowsInOldNaptSwitch : No {} session associated to router {},"
326 + "no flows need to be removed in oldNaptSwitch {}",
327 intextIpProtocolType.getProtocol(), routerId, naptSwitch);
330 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
331 for (IpPortMap ipPortMap : ipPortMaps) {
332 String ipPortInternal = ipPortMap.getIpPortInternal();
333 String[] ipPortParts = ipPortInternal.split(":");
334 if (ipPortParts.length != 2) {
335 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the Internal IP and port");
338 String internalIp = ipPortParts[0];
339 String internalPort = ipPortParts[1];
341 //Build and remove flow in outbound NAPT table
342 String switchFlowRef =
343 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
344 internalIp, Integer.parseInt(internalPort));
345 FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
346 cookieSnatFlow, switchFlowRef);
348 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch "
349 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
350 mdsalManager.removeFlowToTx(outboundNaptFlowEntity, removeFlowInvTx);
352 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
353 if (ipPortExternal == null) {
354 LOG.debug("removeSnatFlowsInOldNaptSwitch : External Ipport mapping not found for internalIp {} "
355 + "with port {} for router {}", internalIp, internalPort, routerId);
358 String externalIp = ipPortExternal.getIpAddress();
359 int externalPort = ipPortExternal.getPortNum();
361 //Build and remove flow in inbound NAPT table
363 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
364 externalIp, externalPort);
365 FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
366 cookieSnatFlow, switchFlowRef);
368 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch with the "
369 + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, naptSwitch, routerId);
370 mdsalManager.removeFlowToTx(inboundNaptFlowEntity, removeFlowInvTx);
376 private List<String> getRouterIdsForExtNetwork(Uuid extNetworkId) {
377 List<String> routerUuidsAsString = new ArrayList<>();
378 InstanceIdentifier<Networks> extNetwork = InstanceIdentifier.builder(ExternalNetworks.class)
379 .child(Networks.class, new NetworksKey(extNetworkId)).build();
380 Optional<Networks> extNetworkData =
381 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
382 LogicalDatastoreType.CONFIGURATION, extNetwork);
383 if (extNetworkData.isPresent()) {
384 List<Uuid> routerUuids = extNetworkData.get().getRouterIds();
385 if (routerUuids != null) {
386 for (Uuid routerUuid : routerUuids) {
387 routerUuidsAsString.add(routerUuid.getValue());
391 return routerUuidsAsString;
394 public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
395 Long routerVpnId, Collection<String> externalIpCache,
396 WriteTransaction writeFlowInvTx) {
397 return isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId, externalIpCache, true,
401 // TODO Clean up the exception handling
402 @SuppressWarnings("checkstyle:IllegalCatch")
403 public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
404 Long routerVpnId, Collection<String> externalIpCache, boolean isClearBgpRts,
405 WriteTransaction writeFlowInvTx) {
406 externalIpsCache = externalIpCache;
407 if (!naptSwitch.equals(dpnId)) {
408 LOG.debug("isNaptSwitchDown : DpnId {} is not a naptSwitch {} for Router {}",
409 dpnId, naptSwitch, routerName);
412 LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
413 if (routerId == NatConstants.INVALID_ID) {
414 LOG.error("isNaptSwitchDown : Invalid routerId returned for routerName {}", routerName);
417 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
418 String vpnName = getExtNetworkVpnName(routerName, networkId);
419 //elect a new NaptSwitch
420 naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
421 if (natMode == NatMode.Conntrack) {
422 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
423 natServiceManager.notify(extRouters, dpnId, dpnId, SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
424 natServiceManager.notify(extRouters, naptSwitch, naptSwitch,
425 SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
427 if (naptSwitch.equals(BigInteger.ZERO)) {
428 LOG.warn("isNaptSwitchDown : No napt switch is elected since all the switches for router {}"
429 + " are down. SNAT IS NOT SUPPORTED FOR ROUTER {}", routerName, routerName);
430 boolean naptUpdatedStatus = updateNaptSwitch(routerName, naptSwitch);
431 if (!naptUpdatedStatus) {
432 LOG.debug("isNaptSwitchDown : Failed to update naptSwitch {} for router {} in ds",
433 naptSwitch, routerName);
436 if (externalIpsCache != null) {
437 if (vpnName != null) {
438 //List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
439 //if (externalIps != null) {
441 LOG.debug("isNaptSwitchDown : Clearing both FIB entries and the BGP routes");
442 for (String externalIp : externalIpsCache) {
443 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
446 LOG.debug("isNaptSwitchDown : Clearing the FIB entries but not the BGP routes");
447 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
448 for (String externalIp : externalIpsCache) {
449 LOG.debug("isNaptSwitchDown : Removing Fib entry rd {} prefix {}", rd, externalIp);
450 fibManager.removeFibEntry(rd, externalIp, null);
454 LOG.debug("isNaptSwitchDown : vpn is not associated to extn/w for router {}", routerName);
457 LOG.debug("isNaptSwitchDown : No ExternalIps found for subnets under router {}, "
458 + "no bgp routes need to be cleared", routerName);
462 //checking elected switch health status
463 if (!getSwitchStatus(naptSwitch)) {
464 LOG.error("isNaptSwitchDown : Newly elected Napt switch {} for router {} is down",
465 naptSwitch, routerName);
468 LOG.debug("isNaptSwitchDown : New NaptSwitch {} is up for Router {} and can proceed for flow installation",
469 naptSwitch, routerName);
470 //update napt model for new napt switch
471 boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
473 //update group of ordinary switch point to naptSwitch tunnel port
474 updateNaptSwitchBucketStatus(routerName, routerId, naptSwitch);
476 LOG.error("isNaptSwitchDown : Failed to update naptSwitch model for newNaptSwitch {} for router {}",
477 naptSwitch, routerName);
480 //update table26 forward packets to table46(outbound napt table)
481 FlowEntity flowEntity =
482 buildSnatFlowEntityForNaptSwitch(naptSwitch, routerName, routerVpnId, NatConstants.ADD_FLOW);
483 if (flowEntity == null) {
484 LOG.error("isNaptSwitchDown : Failed to populate flowentity for router {} in naptSwitch {}",
485 routerName, naptSwitch);
487 LOG.debug("isNaptSwitchDown : Successfully installed flow in naptSwitch {} for router {}",
488 naptSwitch, routerName);
489 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
492 installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, writeFlowInvTx);
494 boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerName, routerId, dpnId, naptSwitch,
495 routerVpnId, networkId);
496 if (flowInstalledStatus) {
497 LOG.debug("isNaptSwitchDown :Installed all active session flows in newNaptSwitch {} for routerName {}",
498 naptSwitch, routerName);
500 LOG.error("isNaptSwitchDown : Failed to install flows in newNaptSwitch {} for routerId {}",
501 naptSwitch, routerId);
504 //remove group in new naptswitch, coz this switch acted previously as ordinary switch
505 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
506 GroupEntity groupEntity = null;
508 groupEntity = MDSALUtil.buildGroupEntity(naptSwitch, groupId, routerName,
509 GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
510 LOG.info("isNaptSwitchDown : Removing NAPT Group in new naptSwitch {}", naptSwitch);
511 mdsalManager.removeGroup(groupEntity);
512 } catch (Exception ex) {
513 LOG.error("isNaptSwitchDown : Failed to remove group in new naptSwitch {}", groupEntity, ex);
519 private String getExtNetworkVpnName(String routerName, Uuid networkId) {
520 if (networkId == null) {
521 LOG.error("getExtNetworkVpnName : networkId is null for the router ID {}", routerName);
523 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
524 if (vpnName != null) {
525 LOG.debug("getExtNetworkVpnName : retrieved vpn name {} associated with ext nw {} in router {}",
526 vpnName, networkId, routerName);
529 LOG.error("getExtNetworkVpnName : No VPN associated with ext nw {} belonging to routerId {}",
530 networkId, routerName);
533 LOG.error("getExtNetworkVpnName : External Network VPN not found for router : {}", routerName);
537 public void updateNaptSwitchBucketStatus(String routerName, long routerId, BigInteger naptSwitch) {
538 LOG.debug("updateNaptSwitchBucketStatus : called");
540 List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
541 //List<BigInteger> dpnList = getDpnListForRouter(routerName);
542 if (dpnList.isEmpty()) {
543 LOG.warn("updateNaptSwitchBucketStatus : No switches found for router {}", routerName);
546 for (BigInteger dpn : dpnList) {
547 if (!dpn.equals(naptSwitch)) {
548 LOG.debug("updateNaptSwitchBucketStatus : Updating SNAT_TABLE missentry for DpnId {} "
549 + "which is not naptSwitch for router {}", dpn, routerName);
550 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, routerId, naptSwitch);
551 modifySnatGroupEntry(dpn, bucketInfoList, routerName);
556 // TODO Clean up the exception handling
557 @SuppressWarnings("checkstyle:IllegalCatch")
558 private boolean handleNatFlowsInNewNaptSwitch(String routerName, Long routerId, BigInteger oldNaptSwitch,
559 BigInteger newNaptSwitch, Long routerVpnId, Uuid networkId) {
560 LOG.debug("handleNatFlowsInNewNaptSwitch : Proceeding to install flows in newNaptSwitch {} for routerId {}",
561 newNaptSwitch, routerId);
562 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
563 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
564 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
565 LOG.debug("handleNatFlowsInNewNaptSwitch : No Internal Ip Port mapping associated to router {},"
566 + "no flows need to be installed in newNaptSwitch {}", routerId, newNaptSwitch);
570 Long vpnId = getVpnIdForRouter(routerId, networkId);
571 if (vpnId == NatConstants.INVALID_ID) {
572 LOG.error("handleNatFlowsInNewNaptSwitch : Invalid vpnId for routerId {}", routerId);
576 if (routerId.equals(routerVpnId)) {
577 bgpVpnId = NatConstants.INVALID_ID;
579 bgpVpnId = routerVpnId;
581 LOG.debug("handleNatFlowsInNewNaptSwitch : retrieved bgpVpnId {} for router {}", bgpVpnId, routerId);
582 // Get the External Gateway MAC Address
583 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
584 if (extGwMacAddress != null) {
585 LOG.debug("handleNatFlowsInNewNaptSwitch :External Gateway MAC address {} found for External Router ID {}",
586 extGwMacAddress, routerId);
588 LOG.error("handleNatFlowsInNewNaptSwitch : No External Gateway MAC address found for External Router ID {}",
592 for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
593 if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
594 LOG.debug("handleNatFlowsInNewNaptSwitch : No {} session associated to router {}",
595 protocolType.getProtocol(), routerId);
598 for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
599 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
600 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
601 LOG.debug("handleNatFlowsInNewNaptSwitch : Found Internal IP Address {} and Port Number {}",
602 internalIpAddress, intportnum);
603 //Get the external IP address and the port from the model
604 NAPTEntryEvent.Protocol proto =
605 protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
606 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
607 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
608 internalIpAddress, intportnum, proto);
609 if (ipPortExternal == null) {
610 LOG.debug("handleNatFlowsInNewNaptSwitch : External Ipport mapping is not found for internalIp {} "
611 + "with port {}", internalIpAddress, intportnum);
614 String externalIpAddress = ipPortExternal.getIpAddress();
615 Integer extportNumber = ipPortExternal.getPortNum();
616 LOG.debug("handleNatFlowsInNewNaptSwitch : ExternalIPport {}:{} mapping for internal ipport {}:{}",
617 externalIpAddress, extportNumber, internalIpAddress, intportnum);
619 SessionAddress sourceAddress = new SessionAddress(internalIpAddress, Integer.parseInt(intportnum));
620 SessionAddress externalAddress = new SessionAddress(externalIpAddress, extportNumber);
622 //checking naptSwitch status before installing flows
623 if (getSwitchStatus(newNaptSwitch)) {
624 //Install the flow in newNaptSwitch Inbound NAPT table.
626 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.INBOUND_NAPT_TABLE,
627 vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto, extGwMacAddress);
628 } catch (RuntimeException ex) {
629 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in INBOUND_NAPT_TABLE for "
630 + "routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{} BgpVpnId {}",
631 routerId, newNaptSwitch, externalAddress, extportNumber, proto,
632 internalIpAddress, intportnum, bgpVpnId);
635 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
636 + "Inbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
637 newNaptSwitch, routerId, internalIpAddress,
638 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
639 //Install the flow in newNaptSwitch Outbound NAPT table.
641 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
642 vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto, extGwMacAddress);
643 } catch (RuntimeException ex) {
644 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in OUTBOUND_NAPT_TABLE for "
645 + "routerid {} dpnId {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
646 routerId, newNaptSwitch, internalIpAddress,
647 intportnum, proto, externalAddress, extportNumber, bgpVpnId, ex);
650 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
651 + "Outbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
652 newNaptSwitch, routerId, internalIpAddress,
653 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
655 LOG.error("handleNatFlowsInNewNaptSwitch : NewNaptSwitch {} gone down while installing flows "
656 + "from oldNaptswitch {}", newNaptSwitch, oldNaptSwitch);
664 // TODO Clean up the exception handling
665 @SuppressWarnings("checkstyle:IllegalCatch")
666 private Long getVpnIdForRouter(Long routerId, Uuid networkId) {
669 if (networkId == null) {
670 LOG.debug("getVpnIdForRouter : network is not associated to router {}", routerId);
672 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
673 if (vpnUuid == null) {
674 LOG.debug("getVpnIdForRouter : vpn is not associated for network {} in router {}",
675 networkId, routerId);
677 Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
679 LOG.debug("getVpnIdForRouter : retrieved vpnId {} for router {}", vpnId, routerId);
682 LOG.debug("getVpnIdForRouter : retrieved invalid vpn Id");
686 } catch (Exception ex) {
687 LOG.error("getVpnIdForRouter : Exception while retrieving vpnId for router {}", routerId, ex);
689 return NatConstants.INVALID_ID;
692 public boolean getSwitchStatus(BigInteger switchId) {
693 NodeId nodeId = new NodeId("openflow:" + switchId);
694 LOG.debug("getSwitchStatus : Querying switch with dpnId {} is up/down", nodeId);
695 InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
696 .child(Node.class, new NodeKey(nodeId)).build();
697 Optional<Node> nodeOptional =
698 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
699 LogicalDatastoreType.OPERATIONAL, nodeInstanceId);
700 if (nodeOptional.isPresent()) {
701 LOG.debug("getSwitchStatus : Switch {} is up", nodeId);
704 LOG.debug("getSwitchStatus : Switch {} is down", nodeId);
708 public List<BucketInfo> handleGroupInPrimarySwitch() {
709 List<BucketInfo> listBucketInfo = new ArrayList<>();
710 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
711 listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
712 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
713 listBucketInfo.add(bucketPrimary);
714 return listBucketInfo;
718 public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, long routerId,
719 BigInteger naptSwitch) {
720 List<BucketInfo> listBucketInfo = new ArrayList<>();
721 String ifNamePrimary;
722 if (routerId == NatConstants.INVALID_ID) {
723 LOG.error("handleGroupInNeighborSwitches : Invalid routerId returned for routerName {}", routerName);
724 return listBucketInfo;
726 ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
727 if (ifNamePrimary != null) {
728 LOG.debug("handleGroupInNeighborSwitches : TunnelInterface {} between ordinary switch {} and naptSwitch {}",
729 ifNamePrimary, dpnId, naptSwitch);
730 List<ActionInfo> listActionInfoPrimary =
731 NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager, interfaceManager,
732 ifNamePrimary, routerId);
733 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
734 listBucketInfo.add(bucketPrimary);
736 LOG.debug("handleGroupInNeighborSwitches : No TunnelInterface between ordinary switch {} and naptSwitch {}",
739 return listBucketInfo;
742 // TODO Clean up the exception handling
743 @SuppressWarnings("checkstyle:IllegalCatch")
744 protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
745 GroupEntity groupEntity = null;
747 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
748 LOG.debug("installSnatGroupEntry : install SnatMissEntry for groupId {} for dpnId {} for router {}",
749 groupId, dpnId, routerName);
750 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
751 GroupTypes.GroupAll, bucketInfo);
752 mdsalManager.syncInstallGroup(groupEntity);
753 LOG.debug("installSnatGroupEntry : installed the SNAT to NAPT GroupEntity:{}", groupEntity);
754 } catch (Exception ex) {
755 LOG.error("installSnatGroupEntry : Failed to install group for groupEntity {}", groupEntity, ex);
759 private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
760 installSnatGroupEntry(dpnId, bucketInfo, routerName);
761 LOG.debug("modifySnatGroupEntry : modified SnatMissEntry for dpnId {} of router {}", dpnId, routerName);
764 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
765 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
766 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
769 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
770 new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId)
771 .setTunnelType(tunType).build());
772 rpcResult = result.get();
773 if (!rpcResult.isSuccessful()) {
774 tunType = TunnelTypeGre.class;
775 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
776 .setSourceDpid(srcDpId)
777 .setDestinationDpid(dstDpId)
778 .setTunnelType(tunType)
780 rpcResult = result.get();
781 if (!rpcResult.isSuccessful()) {
782 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
783 rpcResult.getErrors());
785 return rpcResult.getResult().getInterfaceName();
787 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
788 rpcResult.getErrors());
790 return rpcResult.getResult().getInterfaceName();
792 } catch (InterruptedException | ExecutionException e) {
793 LOG.error("getTunnelInterfaceName :Exception when getting tunnel interface Id for tunnel between {} and {}",
794 srcDpId, dstDpId, e);
796 LOG.error("getTunnelInterfaceName : Tunnel missing between dpn {}:{}", srcDpId, dstDpId);
800 // TODO Clean up the exception handling
801 @SuppressWarnings("checkstyle:IllegalCatch")
802 public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
803 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
804 .setPrimarySwitchId(naptSwitchId).build();
806 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
807 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
808 } catch (Exception ex) {
809 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
810 naptSwitchId, routerName);
813 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
814 naptSwitchId, routerName);
818 public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId,
819 long routerVpnId, int addordel) {
820 FlowEntity flowEntity;
821 List<MatchInfo> matches = new ArrayList<>();
822 matches.add(MatchEthernetType.IPV4);
823 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
825 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
827 if (addordel == NatConstants.ADD_FLOW) {
828 List<ActionInfo> actionsInfo = new ArrayList<>();
829 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerVpnId,
831 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
832 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
833 actionsInfo.add(new ActionGroup(groupId));
834 List<InstructionInfo> instructions = new ArrayList<>();
835 instructions.add(new InstructionApplyActions(actionsInfo));
837 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
838 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
839 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
841 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
842 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
843 NwConstants.COOKIE_SNAT_TABLE, matches, null);
848 public FlowEntity buildSnatFlowEntityForNaptSwitch(BigInteger dpId, String routerName,
849 long routerVpnId, int addordel) {
850 FlowEntity flowEntity;
851 List<MatchInfo> matches = new ArrayList<>();
852 matches.add(MatchEthernetType.IPV4);
853 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
855 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
857 if (addordel == NatConstants.ADD_FLOW) {
858 List<InstructionInfo> instructions = new ArrayList<>();
860 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
862 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
863 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
864 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
866 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
867 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
868 NwConstants.COOKIE_SNAT_TABLE, matches, null);
873 private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
874 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
875 .FLOWID_SEPARATOR + routerID;
878 protected void installSnatFlows(String routerName, Long routerId, BigInteger naptSwitch, Long routerVpnId,
879 WriteTransaction writeFlowInvTx) {
881 if (routerId.equals(routerVpnId)) {
882 LOG.debug("installSnatFlows : Installing flows for router with internalvpnId");
883 //36 -> 46 ..Install flow forwarding packet to table46 from table36
884 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
885 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
886 externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName, routerId, writeFlowInvTx);
888 //Install default flows punting to controller in table 46(OutBoundNapt table)
889 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
890 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
891 externalRouterListener.createOutboundTblEntry(naptSwitch, routerId, writeFlowInvTx);
893 //Table 47 point to table 21 for inbound traffic
894 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {}",
895 naptSwitch, routerId);
896 externalRouterListener.installNaptPfibEntry(naptSwitch, routerId, writeFlowInvTx);
898 //Table 47 point to group
899 LOG.debug("installSnatFlows : installNaptPfibExternalOutputFlow in naptswitch with dpnId {} for router {}",
900 naptSwitch, routerId);
901 externalRouterListener.installNaptPfibExternalOutputFlow(routerName, routerId, naptSwitch, writeFlowInvTx);
903 Uuid extNetworkUuid = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
904 if (extNetworkUuid == null) {
905 LOG.error("onRouterAssociatedToVpn : Unable to retrieve external network Uuid for router {}",
909 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
911 if (extNwProvType == null) {
912 LOG.error("onRouterAssociatedToVpn : External Network Provider Type missing");
915 //36 -> 46 ..Install flow forwarding packet to table46 from table36
916 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
917 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
918 externalRouterListener
919 .installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerId,
920 routerVpnId, writeFlowInvTx, extNwProvType);
922 //Install default flows punting to controller in table 46(OutBoundNapt table)
923 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
924 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
925 externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, writeFlowInvTx);
927 //Table 47 point to table 21 for inbound traffic
928 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {} "
929 + "with BgpVpnId {}", naptSwitch, routerId, routerVpnId);
930 externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, writeFlowInvTx);
933 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
934 String vpnName = getExtNetworkVpnName(routerName, networkId);
935 if (vpnName != null) {
936 //NAPT PFIB point to FIB table for outbound traffic
937 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
938 boolean shouldInstallNaptPfibWithExtNetworkVpnId = true;
939 Collection<Uuid> externalSubnetIds = NatUtil.getExternalSubnetIdsForRouter(dataBroker, routerName);
940 if (!externalSubnetIds.isEmpty()) {
941 //NAPT PFIB point to FIB table for outbound traffic - using external subnetID as vpnID.
942 for (Uuid externalSubnetId : externalSubnetIds) {
943 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, externalSubnetId);
944 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
945 shouldInstallNaptPfibWithExtNetworkVpnId = false;
946 LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
947 + "BgpVpnId {}", naptSwitch, externalSubnetVpnId);
948 externalRouterListener.installNaptPfibEntry(naptSwitch, externalSubnetVpnId, writeFlowInvTx);
952 if (vpnId != NatConstants.INVALID_ID && shouldInstallNaptPfibWithExtNetworkVpnId) {
953 //NAPT PFIB table point to FIB table for outbound traffic - using external networkID as vpnID.
954 LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
955 + "BgpVpnId {}", naptSwitch, vpnId);
956 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId, writeFlowInvTx);
957 } else if (vpnId != NatConstants.INVALID_ID) {
958 LOG.debug("installSnatFlows : Associated BgpvpnId not found for router {}", routerId);
961 //Install Fib entries for ExternalIps & program 36 -> 44
962 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
963 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
964 for (String externalIp : externalIps) {
965 removeFibEntry(rd, externalIp);
966 LOG.debug("installSnatFlows : advToBgpAndInstallFibAndTsFlows in naptswitch id {} "
967 + "with vpnName {} and externalIp {}", naptSwitch, vpnName, externalIp);
968 externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
969 vpnName, routerId, routerName, externalIp, networkId, null /* external-router */,
971 LOG.debug("installSnatFlows : Successfully added fib entries in naptswitch {} for "
972 + "router {} with external IP {}", naptSwitch, routerId, externalIp);
975 LOG.debug("installSnatFlows : Associated vpnName not found for router {}", routerId);
979 protected void bestEffortDeletion(long routerId, String routerName, Map<String, Long> externalIpLabel,
980 WriteTransaction removeFlowInvTx) {
981 Collection<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
982 if (externalIpsCache != null) {
983 Set<String> removedExternalIps = new HashSet<>(externalIpsCache);
984 removedExternalIps.removeAll(newExternalIps);
985 if (removedExternalIps.isEmpty()) {
986 LOG.info("bestEffortDeletion : No external Ip needed to be removed in bestEffortDeletion "
987 + "method for router {}", routerName);
990 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
991 String vpnName = getExtNetworkVpnName(routerName, networkId);
992 if (vpnName == null) {
993 LOG.error("bestEffortDeletion : Vpn is not associated to externalN/w of router {}", routerName);
996 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
997 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
998 LOG.error("bestEffortDeletion : No naptSwitch is selected for router {}", routerName);
1001 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName, networkId);
1002 if (extNwProvType == null) {
1005 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1006 if (gwMacAddress != null) {
1007 LOG.debug("bestEffortDeletion : External Gateway MAC address {} found for External Router ID {}",
1008 gwMacAddress, routerId);
1010 LOG.error("bestEffortDeletion : No External Gateway MAC address found for External Router ID {}",
1014 if (extNwProvType == ProviderTypes.VXLAN) {
1015 for (String externalIp : removedExternalIps) {
1016 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1017 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
1018 networkId, NatConstants.DEFAULT_LABEL_VALUE, gwMacAddress, true, removeFlowInvTx);
1019 LOG.debug("bestEffortDeletion : Successfully removed fib entry for externalIp {} for routerId {} "
1020 + "on NAPT switch {} ", externalIp, routerId, naptSwitch);
1023 if (externalIpLabel == null || externalIpLabel.isEmpty()) {
1024 LOG.error("bestEffortDeletion : ExternalIpLabel map is empty for router {}", routerName);
1028 for (String externalIp : removedExternalIps) {
1029 if (externalIpLabel.containsKey(externalIp)) {
1030 label = externalIpLabel.get(externalIp);
1031 LOG.debug("bestEffortDeletion : Label {} for ExternalIp {} for router {}",
1032 label, externalIp, routerName);
1034 LOG.debug("bestEffortDeletion : Label for ExternalIp {} is not found for router {}",
1035 externalIp, routerName);
1038 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1039 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
1040 networkId, label, gwMacAddress, true, removeFlowInvTx);
1041 LOG.debug("bestEffortDeletion : Successfully removed fib entries in switch {} for router {} "
1042 + "and externalIps {}", naptSwitch, routerId, externalIp);
1046 LOG.debug("bestEffortDeletion : No external IP found for router {}", routerId);
1050 private void removeFibEntry(String rd, String prefix) {
1051 InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
1052 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
1053 .child(VrfEntry.class, new VrfEntryKey(prefix));
1054 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
1055 Optional<VrfEntry> ent = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
1056 if (ent.isPresent()) {
1057 LOG.debug("removeFibEntry : Removing Fib entry rd {} prefix {}", rd, prefix);
1058 fibManager.removeFibEntry(rd, prefix, null);
1062 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
1063 externalRouterListener.subnetRegisterMapping(routerEntry, segmentId);