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.mdsalutil.ActionInfo;
30 import org.opendaylight.genius.mdsalutil.BucketInfo;
31 import org.opendaylight.genius.mdsalutil.FlowEntity;
32 import org.opendaylight.genius.mdsalutil.GroupEntity;
33 import org.opendaylight.genius.mdsalutil.InstructionInfo;
34 import org.opendaylight.genius.mdsalutil.MDSALUtil;
35 import org.opendaylight.genius.mdsalutil.MatchInfo;
36 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
37 import org.opendaylight.genius.mdsalutil.NwConstants;
38 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
39 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
40 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
41 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
43 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
44 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
45 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
46 import org.opendaylight.netvirt.elanmanager.api.IElanService;
47 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
48 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
79 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;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
83 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
84 import org.opendaylight.yangtools.yang.common.RpcResult;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
89 public class NaptSwitchHA {
90 private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
91 private final DataBroker dataBroker;
92 private final IMdsalApiManager mdsalManager;
93 private final ItmRpcService itmManager;
94 private final OdlInterfaceRpcService interfaceManager;
95 private final IdManagerService idManager;
96 private final NAPTSwitchSelector naptSwitchSelector;
97 private final ExternalRoutersListener externalRouterListener;
98 private final NaptEventHandler naptEventHandler;
99 private final IFibManager fibManager;
100 private final IElanService elanManager;
101 private final EvpnNaptSwitchHA evpnNaptSwitchHA;
102 private final SnatServiceManager natServiceManager;
103 private final NatMode natMode;
105 private volatile Collection<String> externalIpsCache;
108 public NaptSwitchHA(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
109 final ExternalRoutersListener externalRouterListener,
110 final ItmRpcService itmManager,
111 final OdlInterfaceRpcService interfaceManager,
112 final IdManagerService idManager,
113 final NAPTSwitchSelector naptSwitchSelector,
114 final IFibManager fibManager,
115 final EvpnNaptSwitchHA evpnNaptSwitchHA,
116 final IElanService elanManager,
117 final SnatServiceManager natServiceManager,
118 final NatserviceConfig config,
119 final NaptEventHandler naptEventHandler) {
120 this.dataBroker = dataBroker;
121 this.mdsalManager = mdsalManager;
122 this.externalRouterListener = externalRouterListener;
123 this.itmManager = itmManager;
124 this.interfaceManager = interfaceManager;
125 this.idManager = idManager;
126 this.naptSwitchSelector = naptSwitchSelector;
127 this.naptEventHandler = naptEventHandler;
128 this.fibManager = fibManager;
129 this.evpnNaptSwitchHA = evpnNaptSwitchHA;
130 this.elanManager = elanManager;
131 this.natServiceManager = natServiceManager;
132 if (config != null) {
133 this.natMode = config.getNatMode();
135 this.natMode = NatMode.Controller;
139 /* This method checks the switch that gone down is a NaptSwitch for a router.
140 If it is a NaptSwitch
141 1) selects new NAPT switch
142 2) installs nat flows in new NAPT switch
143 table 21(FIB)->26(PSNAT)->group(resubmit/napttunnel)->36(Terminating)->46(outbound)->47(resubmit)->21
144 3) modify the group and miss entry flow in other vSwitches pointing to newNaptSwitch
145 4) Remove nat flows in oldNaptSwitch
147 /*public void handleNaptSwitchDown(BigInteger dpnId){
149 LOG.debug("handleNaptSwitchDown method is called with dpnId {}",dpnId);
150 BigInteger naptSwitch;
152 NaptSwitches naptSwitches = NatUtil.getNaptSwitch(dataBroker);
153 if (naptSwitches == null || naptSwitches.getRouterToNaptSwitch() == null
154 || naptSwitches.getRouterToNaptSwitch().isEmpty()) {
155 LOG.debug("NaptSwitchDown: NaptSwitch is not allocated for none of the routers");
158 for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
159 String routerName = routerToNaptSwitch.getRouterName();
160 naptSwitch = routerToNaptSwitch.getPrimarySwitchId();
161 boolean naptStatus = isNaptSwitchDown(routerName,dpnId,naptSwitch);
163 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
166 removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
170 } catch (Exception ex) {
171 LOG.error("Exception in handleNaptSwitchDown method {}",ex);
175 protected void removeSnatFlowsInOldNaptSwitch(String routerName, Long routerId, BigInteger naptSwitch,
176 Map<String, Long> externalIpmap, WriteTransaction removeFlowInvTx) {
177 //remove SNAT flows in old NAPT SWITCH
178 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
179 String vpnName = getExtNetworkVpnName(routerName, networkId);
180 if (vpnName == null) {
181 LOG.error("removeSnatFlowsInOldNaptSwitch : Vpn is not associated to externalN/w of router {}",
185 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, networkId);
186 if (extNwProvType == null) {
187 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the External Network Provider Type "
188 + "for Router {}", routerName);
191 if (extNwProvType == ProviderTypes.VXLAN) {
192 evpnNaptSwitchHA.evpnRemoveSnatFlowsInOldNaptSwitch(routerName, routerId, vpnName, naptSwitch,
195 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
196 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
198 String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
200 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
203 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
204 + "with the DPN ID {} and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
205 mdsalManager.removeFlowToTx(tsNatFlowEntity, removeFlowInvTx);
207 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
208 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
209 NatUtil.removePreDnatToSnatTableEntry(mdsalManager, naptSwitch, removeFlowInvTx);
211 //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
212 String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
213 NwConstants.OUTBOUND_NAPT_TABLE, routerId);
214 FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
215 NwConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
216 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
217 NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
218 mdsalManager.removeFlowToTx(outboundNatFlowEntity, removeFlowInvTx);
220 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
221 // External Subnet Vpn Id.
222 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
224 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
225 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
226 if (subnetVpnId != -1) {
227 String natPfibSubnetFlowRef = externalRouterListener.getFlowRefTs(naptSwitch,
228 NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
229 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,
230 natPfibSubnetFlowRef);
231 mdsalManager.removeFlowToTx(natPfibFlowEntity, removeFlowInvTx);
232 LOG.debug("removeSnatFlowsInOldNaptSwitch : Removed the flow in table {} with external subnet "
233 + "Vpn Id {} as metadata on Napt Switch {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE,
234 subnetVpnId, naptSwitch);
238 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic
239 // matching on the router ID.
240 String naptPFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
241 FlowEntity naptPFibFlowEntity =
242 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
243 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
244 + "with the DPN ID {} and router ID {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
245 mdsalManager.removeFlowToTx(naptPFibFlowEntity, removeFlowInvTx);
247 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic
248 // matching on the vpn ID.
249 boolean switchSharedByRouters = false;
250 Uuid extNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
251 if (extNetworkId != null) {
252 List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
253 for (String routerNameAssociated : routerNamesAssociated) {
254 if (!routerNameAssociated.equals(routerName)) {
255 Long routerIdAssociated = NatUtil.getVpnId(dataBroker, routerNameAssociated);
256 BigInteger naptDpn = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerNameAssociated);
257 if (naptDpn != null && naptDpn.equals(naptSwitch)) {
258 LOG.debug("removeSnatFlowsInOldNaptSwitch : Napt switch {} is also acting as primary "
259 + "for router {}", routerIdAssociated);
260 switchSharedByRouters = true;
265 if (!switchSharedByRouters) {
266 Long vpnId = getVpnIdForRouter(routerId, extNetworkId);
267 if (vpnId != NatConstants.INVALID_ID) {
268 String naptFibflowRef =
269 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
270 FlowEntity naptFibFlowEntity =
271 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptFibflowRef);
272 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch"
273 + " with the DPN ID {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
274 mdsalManager.removeFlowToTx(naptFibFlowEntity, removeFlowInvTx);
276 LOG.error("removeSnatFlowsInOldNaptSwitch : Invalid vpnId retrieved for routerId {}",
283 //Remove Fib entries,tables 20->44 ,36-> 44
284 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
285 if (externalIpmap != null && !externalIpmap.isEmpty()) {
286 for (Entry<String, Long> entry : externalIpmap.entrySet()) {
287 String externalIp = entry.getKey();
288 Long label = entry.getValue();
289 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
290 extNetworkId, label, gwMacAddress, true, removeFlowInvTx);
291 LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} "
292 + "for router {} and externalIps {} label {}", naptSwitch, routerId, externalIp, label);
295 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
296 if (networkId != null) {
297 externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, networkId,
298 externalIps, null, gwMacAddress, removeFlowInvTx);
299 LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} for "
300 + "router {} with networkId {} and externalIps {}", naptSwitch, routerId, networkId,
303 LOG.debug("removeSnatFlowsInOldNaptSwitch : External network not associated to router {}", routerId);
305 externalRouterListener.removeNaptFibExternalOutputFlows(routerId, naptSwitch, extNetworkId,
306 externalIps, removeFlowInvTx);
309 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
310 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
311 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
312 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
313 LOG.warn("removeSnatFlowsInOldNaptSwitch : No Internal Ip Port mapping associated to router {}, "
314 + "no flows need to be removed in oldNaptSwitch {}", routerId, naptSwitch);
317 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
318 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
319 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
320 if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
321 LOG.debug("removeSnatFlowsInOldNaptSwitch : No {} session associated to router {},"
322 + "no flows need to be removed in oldNaptSwitch {}",
323 intextIpProtocolType.getProtocol(), routerId, naptSwitch);
326 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
327 for (IpPortMap ipPortMap : ipPortMaps) {
328 String ipPortInternal = ipPortMap.getIpPortInternal();
329 String[] ipPortParts = ipPortInternal.split(":");
330 if (ipPortParts.length != 2) {
331 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the Internal IP and port");
334 String internalIp = ipPortParts[0];
335 String internalPort = ipPortParts[1];
337 //Build and remove flow in outbound NAPT table
338 String switchFlowRef =
339 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
340 internalIp, Integer.parseInt(internalPort));
341 FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
342 cookieSnatFlow, switchFlowRef);
344 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch "
345 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
346 mdsalManager.removeFlowToTx(outboundNaptFlowEntity, removeFlowInvTx);
348 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
349 if (ipPortExternal == null) {
350 LOG.debug("removeSnatFlowsInOldNaptSwitch : External Ipport mapping not found for internalIp {} "
351 + "with port {} for router", internalIp, internalPort, routerId);
354 String externalIp = ipPortExternal.getIpAddress();
355 int externalPort = ipPortExternal.getPortNum();
357 //Build and remove flow in inbound NAPT table
359 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
360 externalIp, externalPort);
361 FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
362 cookieSnatFlow, switchFlowRef);
364 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch with the "
365 + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, naptSwitch, routerId);
366 mdsalManager.removeFlowToTx(inboundNaptFlowEntity, removeFlowInvTx);
372 private List<String> getRouterIdsForExtNetwork(Uuid extNetworkId) {
373 List<String> routerUuidsAsString = new ArrayList<>();
374 InstanceIdentifier<Networks> extNetwork = InstanceIdentifier.builder(ExternalNetworks.class)
375 .child(Networks.class, new NetworksKey(extNetworkId)).build();
376 Optional<Networks> extNetworkData =
377 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
378 LogicalDatastoreType.CONFIGURATION, extNetwork);
379 if (extNetworkData.isPresent()) {
380 List<Uuid> routerUuids = extNetworkData.get().getRouterIds();
381 if (routerUuids != null) {
382 for (Uuid routerUuid : routerUuids) {
383 routerUuidsAsString.add(routerUuid.getValue());
387 return routerUuidsAsString;
390 public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
391 Long routerVpnId, Collection<String> externalIpCache,
392 WriteTransaction writeFlowInvTx) {
393 return isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId, externalIpCache, true,
397 // TODO Clean up the exception handling
398 @SuppressWarnings("checkstyle:IllegalCatch")
399 public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
400 Long routerVpnId, Collection<String> externalIpCache, boolean isClearBgpRts,
401 WriteTransaction writeFlowInvTx) {
402 externalIpsCache = externalIpCache;
403 if (!naptSwitch.equals(dpnId)) {
404 LOG.debug("isNaptSwitchDown : DpnId {} is not a naptSwitch {} for Router {}",
405 dpnId, naptSwitch, routerName);
408 LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
409 if (routerId == NatConstants.INVALID_ID) {
410 LOG.error("isNaptSwitchDown : Invalid routerId returned for routerName {}", routerName);
413 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
414 String vpnName = getExtNetworkVpnName(routerName, networkId);
415 //elect a new NaptSwitch
416 naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
417 if (natMode == NatMode.Conntrack) {
418 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
419 natServiceManager.notify(extRouters, dpnId, dpnId, SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
420 natServiceManager.notify(extRouters, naptSwitch, naptSwitch,
421 SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
423 if (naptSwitch.equals(BigInteger.ZERO)) {
424 LOG.warn("isNaptSwitchDown : No napt switch is elected since all the switches for router {}"
425 + " are down. SNAT IS NOT SUPPORTED FOR ROUTER {}", routerName);
426 boolean naptUpdatedStatus = updateNaptSwitch(routerName, naptSwitch);
427 if (!naptUpdatedStatus) {
428 LOG.debug("isNaptSwitchDown : Failed to update naptSwitch {} for router {} in ds",
429 naptSwitch, routerName);
432 if (externalIpsCache != null) {
433 if (vpnName != null) {
434 //List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
435 //if (externalIps != null) {
437 LOG.debug("isNaptSwitchDown : Clearing both FIB entries and the BGP routes");
438 for (String externalIp : externalIpsCache) {
439 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
442 LOG.debug("isNaptSwitchDown : Clearing the FIB entries but not the BGP routes");
443 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
444 for (String externalIp : externalIpsCache) {
445 LOG.debug("isNaptSwitchDown : Removing Fib entry rd {} prefix {}", rd, externalIp);
446 fibManager.removeFibEntry(rd, externalIp, null);
450 LOG.debug("isNaptSwitchDown : vpn is not associated to extn/w for router {}", routerName);
453 LOG.debug("isNaptSwitchDown : No ExternalIps found for subnets under router {}, "
454 + "no bgp routes need to be cleared", routerName);
458 //checking elected switch health status
459 if (!getSwitchStatus(naptSwitch)) {
460 LOG.error("isNaptSwitchDown : Newly elected Napt switch {} for router {} is down",
461 naptSwitch, routerName);
464 LOG.debug("isNaptSwitchDown : New NaptSwitch {} is up for Router {} and can proceed for flow installation",
465 naptSwitch, routerName);
466 //update napt model for new napt switch
467 boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
469 //update group of ordinary switch point to naptSwitch tunnel port
470 updateNaptSwitchBucketStatus(routerName, routerId, naptSwitch);
472 LOG.error("isNaptSwitchDown : Failed to update naptSwitch model for newNaptSwitch {} for router {}",
473 naptSwitch, routerName);
476 //update table26 forward packets to table46(outbound napt table)
477 FlowEntity flowEntity =
478 buildSnatFlowEntityForNaptSwitch(naptSwitch, routerName, routerVpnId, NatConstants.ADD_FLOW);
479 if (flowEntity == null) {
480 LOG.error("isNaptSwitchDown : Failed to populate flowentity for router {} in naptSwitch {}",
481 routerName, naptSwitch);
483 LOG.debug("isNaptSwitchDown : Successfully installed flow in naptSwitch {} for router {}",
484 naptSwitch, routerName);
485 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
488 installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, writeFlowInvTx);
490 boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerName, routerId, dpnId, naptSwitch,
491 routerVpnId, networkId);
492 if (flowInstalledStatus) {
493 LOG.debug("isNaptSwitchDown :Installed all active session flows in newNaptSwitch {} for routerName {}",
494 naptSwitch, routerName);
496 LOG.error("isNaptSwitchDown : Failed to install flows in newNaptSwitch {} for routerId {}",
497 naptSwitch, routerId);
500 //remove group in new naptswitch, coz this switch acted previously as ordinary switch
501 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
502 GroupEntity groupEntity = null;
504 groupEntity = MDSALUtil.buildGroupEntity(naptSwitch, groupId, routerName,
505 GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
506 LOG.info("isNaptSwitchDown : Removing NAPT Group in new naptSwitch {}", naptSwitch);
507 mdsalManager.removeGroup(groupEntity);
508 } catch (Exception ex) {
509 LOG.error("isNaptSwitchDown : Failed to remove group in new naptSwitch {}", groupEntity, ex);
515 private String getExtNetworkVpnName(String routerName, Uuid networkId) {
516 if (networkId == null) {
517 LOG.error("getExtNetworkVpnName : networkId is null for the router ID {}", routerName);
519 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
520 if (vpnName != null) {
521 LOG.debug("getExtNetworkVpnName : retrieved vpn name {} associated with ext nw {} in router {}",
522 vpnName, networkId, routerName);
525 LOG.error("getExtNetworkVpnName : No VPN associated with ext nw {} belonging to routerId {}",
526 networkId, routerName);
529 LOG.error("getExtNetworkVpnName : External Network VPN not found for router : {}", routerName);
533 public void updateNaptSwitchBucketStatus(String routerName, long routerId, BigInteger naptSwitch) {
534 LOG.debug("updateNaptSwitchBucketStatus : called");
536 List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
537 //List<BigInteger> dpnList = getDpnListForRouter(routerName);
538 if (dpnList.isEmpty()) {
539 LOG.warn("updateNaptSwitchBucketStatus : No switches found for router {}", routerName);
542 for (BigInteger dpn : dpnList) {
543 if (!dpn.equals(naptSwitch)) {
544 LOG.debug("updateNaptSwitchBucketStatus : Updating SNAT_TABLE missentry for DpnId {} "
545 + "which is not naptSwitch for router {}", dpn, routerName);
546 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, routerId, naptSwitch);
547 modifySnatGroupEntry(dpn, bucketInfoList, routerName);
552 // TODO Clean up the exception handling
553 @SuppressWarnings("checkstyle:IllegalCatch")
554 private boolean handleNatFlowsInNewNaptSwitch(String routerName, Long routerId, BigInteger oldNaptSwitch,
555 BigInteger newNaptSwitch, Long routerVpnId, Uuid networkId) {
556 LOG.debug("handleNatFlowsInNewNaptSwitch : Proceeding to install flows in newNaptSwitch {} for routerId {}",
557 newNaptSwitch, routerId);
558 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
559 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
560 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
561 LOG.debug("handleNatFlowsInNewNaptSwitch : No Internal Ip Port mapping associated to router {},"
562 + "no flows need to be installed in newNaptSwitch {}", routerId, newNaptSwitch);
566 Long vpnId = getVpnIdForRouter(routerId, networkId);
567 if (vpnId == NatConstants.INVALID_ID) {
568 LOG.error("handleNatFlowsInNewNaptSwitch : Invalid vpnId for routerId {}", routerId);
572 if (routerId.equals(routerVpnId)) {
573 bgpVpnId = NatConstants.INVALID_ID;
575 bgpVpnId = routerVpnId;
577 LOG.debug("handleNatFlowsInNewNaptSwitch : retrieved bgpVpnId {} for router {}", bgpVpnId, routerId);
578 // Get the External Gateway MAC Address
579 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
580 if (extGwMacAddress != null) {
581 LOG.debug("handleNatFlowsInNewNaptSwitch :External Gateway MAC address {} found for External Router ID {}",
582 extGwMacAddress, routerId);
584 LOG.error("handleNatFlowsInNewNaptSwitch : No External Gateway MAC address found for External Router ID {}",
588 for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
589 if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
590 LOG.debug("handleNatFlowsInNewNaptSwitch : No {} session associated to router {}",
591 protocolType.getProtocol(), routerId);
594 for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
595 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
596 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
597 LOG.debug("handleNatFlowsInNewNaptSwitch : Found Internal IP Address {} and Port Number {}",
598 internalIpAddress, intportnum);
599 //Get the external IP address and the port from the model
600 NAPTEntryEvent.Protocol proto =
601 protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
602 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
603 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
604 internalIpAddress, intportnum, proto);
605 if (ipPortExternal == null) {
606 LOG.debug("handleNatFlowsInNewNaptSwitch : External Ipport mapping is not found for internalIp {} "
607 + "with port {}", internalIpAddress, intportnum);
610 String externalIpAddress = ipPortExternal.getIpAddress();
611 Integer extportNumber = ipPortExternal.getPortNum();
612 LOG.debug("handleNatFlowsInNewNaptSwitch : ExternalIPport {}:{} mapping for internal ipport {}:{}",
613 externalIpAddress, extportNumber, internalIpAddress, intportnum);
615 SessionAddress sourceAddress = new SessionAddress(internalIpAddress, Integer.parseInt(intportnum));
616 SessionAddress externalAddress = new SessionAddress(externalIpAddress, extportNumber);
618 //checking naptSwitch status before installing flows
619 if (getSwitchStatus(newNaptSwitch)) {
620 //Install the flow in newNaptSwitch Inbound NAPT table.
622 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.INBOUND_NAPT_TABLE,
623 vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto, extGwMacAddress);
624 } catch (RuntimeException ex) {
625 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in INBOUND_NAPT_TABLE for "
626 + "routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{} BgpVpnId {}",
627 routerId, newNaptSwitch, externalAddress, extportNumber, proto,
628 internalIpAddress, intportnum, bgpVpnId);
631 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
632 + "Inbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
633 newNaptSwitch, routerId, internalIpAddress,
634 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
635 //Install the flow in newNaptSwitch Outbound NAPT table.
637 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
638 vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto, extGwMacAddress);
639 } catch (RuntimeException ex) {
640 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in OUTBOUND_NAPT_TABLE for "
641 + "routerid {} dpnId {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {} - {}",
642 routerId, newNaptSwitch, internalIpAddress,
643 intportnum, proto, externalAddress, extportNumber, bgpVpnId, ex);
646 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
647 + "Outbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
648 newNaptSwitch, routerId, internalIpAddress,
649 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
651 LOG.error("handleNatFlowsInNewNaptSwitch : NewNaptSwitch {} gone down while installing flows "
652 + "from oldNaptswitch {}", newNaptSwitch, oldNaptSwitch);
660 // TODO Clean up the exception handling
661 @SuppressWarnings("checkstyle:IllegalCatch")
662 private Long getVpnIdForRouter(Long routerId, Uuid networkId) {
665 if (networkId == null) {
666 LOG.debug("getVpnIdForRouter : network is not associated to router {}", routerId);
668 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
669 if (vpnUuid == null) {
670 LOG.debug("getVpnIdForRouter : vpn is not associated for network {} in router {}",
671 networkId, routerId);
673 Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
675 LOG.debug("getVpnIdForRouter : retrieved vpnId {} for router {}", vpnId, routerId);
678 LOG.debug("getVpnIdForRouter : retrieved invalid vpn Id");
682 } catch (Exception ex) {
683 LOG.error("getVpnIdForRouter : Exception while retrieving vpnId for router {}", routerId, ex);
685 return NatConstants.INVALID_ID;
688 public boolean getSwitchStatus(BigInteger switchId) {
689 NodeId nodeId = new NodeId("openflow:" + switchId);
690 LOG.debug("getSwitchStatus : Querying switch with dpnId {} is up/down", nodeId);
691 InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
692 .child(Node.class, new NodeKey(nodeId)).build();
693 Optional<Node> nodeOptional =
694 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
695 LogicalDatastoreType.OPERATIONAL, nodeInstanceId);
696 if (nodeOptional.isPresent()) {
697 LOG.debug("getSwitchStatus : Switch {} is up", nodeId);
700 LOG.debug("getSwitchStatus : Switch {} is down", nodeId);
704 public List<BucketInfo> handleGroupInPrimarySwitch() {
705 List<BucketInfo> listBucketInfo = new ArrayList<>();
706 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
707 listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
708 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
709 listBucketInfo.add(bucketPrimary);
710 return listBucketInfo;
714 public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, long routerId,
715 BigInteger naptSwitch) {
716 List<BucketInfo> listBucketInfo = new ArrayList<>();
717 String ifNamePrimary;
718 if (routerId == NatConstants.INVALID_ID) {
719 LOG.error("handleGroupInNeighborSwitches : Invalid routerId returned for routerName {}", routerName);
720 return listBucketInfo;
722 ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
723 if (ifNamePrimary != null) {
724 LOG.debug("handleGroupInNeighborSwitches : TunnelInterface {} between ordinary switch {} and naptSwitch {}",
725 ifNamePrimary, dpnId, naptSwitch);
726 List<ActionInfo> listActionInfoPrimary =
727 NatUtil.getEgressActionsForInterface(interfaceManager, ifNamePrimary, routerId);
728 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
729 listBucketInfo.add(bucketPrimary);
731 LOG.debug("handleGroupInNeighborSwitches : No TunnelInterface between ordinary switch {} and naptSwitch {}",
734 return listBucketInfo;
737 // TODO Clean up the exception handling
738 @SuppressWarnings("checkstyle:IllegalCatch")
739 protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
740 GroupEntity groupEntity = null;
742 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
743 LOG.debug("installSnatGroupEntry : install SnatMissEntry for groupId {} for dpnId {} for router {}",
744 groupId, dpnId, routerName);
745 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
746 GroupTypes.GroupAll, bucketInfo);
747 mdsalManager.syncInstallGroup(groupEntity);
748 LOG.debug("installSnatGroupEntry : installed the SNAT to NAPT GroupEntity:{}", groupEntity);
749 } catch (Exception ex) {
750 LOG.error("installSnatGroupEntry : Failed to install group for groupEntity {}", groupEntity, ex);
754 private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
755 installSnatGroupEntry(dpnId, bucketInfo, routerName);
756 LOG.debug("modifySnatGroupEntry : modified SnatMissEntry for dpnId {} of router {}", dpnId, routerName);
759 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
760 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
761 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
764 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
765 new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId)
766 .setTunnelType(tunType).build());
767 rpcResult = result.get();
768 if (!rpcResult.isSuccessful()) {
769 tunType = TunnelTypeGre.class;
770 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
771 .setSourceDpid(srcDpId)
772 .setDestinationDpid(dstDpId)
773 .setTunnelType(tunType)
775 rpcResult = result.get();
776 if (!rpcResult.isSuccessful()) {
777 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
778 rpcResult.getErrors());
780 return rpcResult.getResult().getInterfaceName();
782 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
783 rpcResult.getErrors());
785 return rpcResult.getResult().getInterfaceName();
787 } catch (InterruptedException | ExecutionException e) {
788 LOG.error("getTunnelInterfaceName :Exception when getting tunnel interface Id for tunnel between {} and {}",
789 srcDpId, dstDpId, e);
791 LOG.error("getTunnelInterfaceName : Tunnel missing between dpn {}:{}", srcDpId, dstDpId);
795 // TODO Clean up the exception handling
796 @SuppressWarnings("checkstyle:IllegalCatch")
797 public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
798 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
799 .setPrimarySwitchId(naptSwitchId).build();
801 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
802 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
803 } catch (Exception ex) {
804 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
805 naptSwitchId, routerName);
808 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
809 naptSwitchId, routerName);
813 public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId,
814 long routerVpnId, int addordel) {
815 FlowEntity flowEntity;
816 List<MatchInfo> matches = new ArrayList<>();
817 matches.add(MatchEthernetType.IPV4);
818 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
820 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
822 if (addordel == NatConstants.ADD_FLOW) {
823 List<ActionInfo> actionsInfo = new ArrayList<>();
824 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerVpnId,
826 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
827 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
828 actionsInfo.add(new ActionGroup(groupId));
829 List<InstructionInfo> instructions = new ArrayList<>();
830 instructions.add(new InstructionApplyActions(actionsInfo));
832 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
833 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
834 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
836 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
837 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
838 NwConstants.COOKIE_SNAT_TABLE, matches, null);
843 public FlowEntity buildSnatFlowEntityForNaptSwitch(BigInteger dpId, String routerName,
844 long routerVpnId, int addordel) {
845 FlowEntity flowEntity;
846 List<MatchInfo> matches = new ArrayList<>();
847 matches.add(MatchEthernetType.IPV4);
848 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
850 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
852 if (addordel == NatConstants.ADD_FLOW) {
853 List<InstructionInfo> instructions = new ArrayList<>();
855 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
857 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
858 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
859 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
861 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
862 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
863 NwConstants.COOKIE_SNAT_TABLE, matches, null);
868 private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
869 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
870 .FLOWID_SEPARATOR + routerID;
873 protected void installSnatFlows(String routerName, Long routerId, BigInteger naptSwitch, Long routerVpnId,
874 WriteTransaction writeFlowInvTx) {
876 if (routerId.equals(routerVpnId)) {
877 LOG.debug("installSnatFlows : Installing flows for router with internalvpnId");
878 //36 -> 46 ..Install flow forwarding packet to table46 from table36
879 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
880 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
881 externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName, routerId, writeFlowInvTx);
883 //Install default flows punting to controller in table 46(OutBoundNapt table)
884 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
885 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
886 externalRouterListener.createOutboundTblEntry(naptSwitch, routerId, writeFlowInvTx);
888 //Table 47 point to table 21 for inbound traffic
889 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {}",
890 naptSwitch, routerId);
891 externalRouterListener.installNaptPfibEntry(naptSwitch, routerId, writeFlowInvTx);
893 //Table 47 point to group
894 LOG.debug("installSnatFlows : installNaptPfibExternalOutputFlow in naptswitch with dpnId {} for router {}",
895 naptSwitch, routerId);
896 externalRouterListener.installNaptPfibExternalOutputFlow(routerName, routerId, naptSwitch, writeFlowInvTx);
898 Uuid extNetworkUuid = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
899 if (extNetworkUuid == null) {
900 LOG.error("onRouterAssociatedToVpn : Unable to retrieve external network Uuid for router {}",
904 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
906 if (extNwProvType == null) {
907 LOG.error("onRouterAssociatedToVpn : External Network Provider Type missing");
910 //36 -> 46 ..Install flow forwarding packet to table46 from table36
911 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
912 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
913 externalRouterListener
914 .installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerId,
915 routerVpnId, writeFlowInvTx, extNwProvType);
917 //Install default flows punting to controller in table 46(OutBoundNapt table)
918 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
919 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
920 externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, writeFlowInvTx);
922 //Table 47 point to table 21 for inbound traffic
923 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {} "
924 + "with BgpVpnId {}", naptSwitch, routerId, routerVpnId);
925 externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, writeFlowInvTx);
928 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
929 String vpnName = getExtNetworkVpnName(routerName, networkId);
930 if (vpnName != null) {
931 //NAPT PFIB point to FIB table for outbound traffic
932 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
933 boolean shouldInstallNaptPfibWithExtNetworkVpnId = true;
934 Collection<Uuid> externalSubnetIds = NatUtil.getExternalSubnetIdsForRouter(dataBroker, routerName);
935 if (!externalSubnetIds.isEmpty()) {
936 //NAPT PFIB point to FIB table for outbound traffic - using external subnetID as vpnID.
937 for (Uuid externalSubnetId : externalSubnetIds) {
938 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, externalSubnetId);
939 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
940 shouldInstallNaptPfibWithExtNetworkVpnId = false;
941 LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
942 + "BgpVpnId {}", naptSwitch, externalSubnetVpnId);
943 externalRouterListener.installNaptPfibEntry(naptSwitch, externalSubnetVpnId, writeFlowInvTx);
947 if (vpnId != NatConstants.INVALID_ID && shouldInstallNaptPfibWithExtNetworkVpnId) {
948 //NAPT PFIB table point to FIB table for outbound traffic - using external networkID as vpnID.
949 LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
950 + "BgpVpnId {}", naptSwitch, vpnId);
951 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId, writeFlowInvTx);
952 } else if (vpnId != NatConstants.INVALID_ID) {
953 LOG.debug("installSnatFlows : Associated BgpvpnId not found for router {}", routerId);
956 //Install Fib entries for ExternalIps & program 36 -> 44
957 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
958 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
959 for (String externalIp : externalIps) {
960 removeFibEntry(rd, externalIp);
961 LOG.debug("installSnatFlows : advToBgpAndInstallFibAndTsFlows in naptswitch id {} "
962 + "with vpnName {} and externalIp {}", naptSwitch, vpnName, externalIp);
963 externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
964 vpnName, routerId, routerName, externalIp, networkId, null /* external-router */,
966 LOG.debug("installSnatFlows : Successfully added fib entries in naptswitch {} for "
967 + "router {} with external IP {}", naptSwitch, routerId, externalIp);
970 LOG.debug("installSnatFlows : Associated vpnName not found for router {}", routerId);
974 protected void bestEffortDeletion(long routerId, String routerName, Map<String, Long> externalIpLabel,
975 WriteTransaction removeFlowInvTx) {
976 Collection<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
977 if (externalIpsCache != null) {
978 Set<String> removedExternalIps = new HashSet<>(externalIpsCache);
979 removedExternalIps.removeAll(newExternalIps);
980 if (removedExternalIps.isEmpty()) {
981 LOG.info("bestEffortDeletion : No external Ip needed to be removed in bestEffortDeletion "
982 + "method for router {}", routerName);
985 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
986 String vpnName = getExtNetworkVpnName(routerName, networkId);
987 if (vpnName == null) {
988 LOG.error("bestEffortDeletion : Vpn is not associated to externalN/w of router {}", routerName);
991 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
992 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
993 LOG.error("bestEffortDeletion : No naptSwitch is selected for router {}", routerName);
996 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName, networkId);
997 if (extNwProvType == null) {
1000 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1001 if (gwMacAddress != null) {
1002 LOG.debug("bestEffortDeletion : External Gateway MAC address {} found for External Router ID {}",
1003 gwMacAddress, routerId);
1005 LOG.error("bestEffortDeletion : No External Gateway MAC address found for External Router ID {}",
1009 if (extNwProvType == ProviderTypes.VXLAN) {
1010 for (String externalIp : removedExternalIps) {
1011 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1012 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
1013 networkId, NatConstants.DEFAULT_LABEL_VALUE, gwMacAddress, true, removeFlowInvTx);
1014 LOG.debug("bestEffortDeletion : Successfully removed fib entry for externalIp {} for routerId {} "
1015 + "on NAPT switch {} ", externalIp, routerId, naptSwitch);
1018 if (externalIpLabel == null || externalIpLabel.isEmpty()) {
1019 LOG.error("bestEffortDeletion : ExternalIpLabel map is empty for router {}", routerName);
1023 for (String externalIp : removedExternalIps) {
1024 if (externalIpLabel.containsKey(externalIp)) {
1025 label = externalIpLabel.get(externalIp);
1026 LOG.debug("bestEffortDeletion : Label {} for ExternalIp {} for router {}",
1027 label, externalIp, routerName);
1029 LOG.debug("bestEffortDeletion : Label for ExternalIp {} is not found for router {}",
1030 externalIp, routerName);
1033 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1034 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
1035 networkId, label, gwMacAddress, true, removeFlowInvTx);
1036 LOG.debug("bestEffortDeletion : Successfully removed fib entries in switch {} for router {} "
1037 + "and externalIps {}", naptSwitch, routerId, externalIp);
1041 LOG.debug("bestEffortDeletion : No external IP found for router {}", routerId);
1045 private void removeFibEntry(String rd, String prefix) {
1046 InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
1047 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
1048 .child(VrfEntry.class, new VrfEntryKey(prefix));
1049 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
1050 Optional<VrfEntry> ent = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
1051 if (ent.isPresent()) {
1052 LOG.debug("removeFibEntry : Removing Fib entry rd {} prefix {}", rd, prefix);
1053 fibManager.removeFibEntry(rd, prefix, null);
1057 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
1058 externalRouterListener.subnetRegisterMapping(routerEntry, segmentId);