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.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.HashSet;
15 import java.util.List;
17 import java.util.Map.Entry;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.eclipse.jdt.annotation.NonNull;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.infra.Datastore.Configuration;
29 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
30 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
31 import org.opendaylight.genius.mdsalutil.ActionInfo;
32 import org.opendaylight.genius.mdsalutil.BucketInfo;
33 import org.opendaylight.genius.mdsalutil.FlowEntity;
34 import org.opendaylight.genius.mdsalutil.GroupEntity;
35 import org.opendaylight.genius.mdsalutil.InstructionInfo;
36 import org.opendaylight.genius.mdsalutil.MDSALUtil;
37 import org.opendaylight.genius.mdsalutil.MatchInfo;
38 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
39 import org.opendaylight.genius.mdsalutil.NwConstants;
40 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
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.netvirt.fibmanager.rev150330.FibEntries;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
76 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;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
81 import org.opendaylight.yangtools.yang.common.RpcResult;
82 import org.opendaylight.yangtools.yang.common.Uint32;
83 import org.opendaylight.yangtools.yang.common.Uint64;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
88 public class NaptSwitchHA {
89 private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
90 private final DataBroker dataBroker;
91 private final IMdsalApiManager mdsalManager;
92 private final ItmRpcService itmManager;
93 private final OdlInterfaceRpcService odlInterfaceRpcService;
94 private final IdManagerService idManager;
95 private final NAPTSwitchSelector naptSwitchSelector;
96 private final ExternalRoutersListener externalRouterListener;
97 private final NaptEventHandler naptEventHandler;
98 private final IFibManager fibManager;
99 private final IElanService elanManager;
100 private final EvpnNaptSwitchHA evpnNaptSwitchHA;
101 private final SnatServiceManager natServiceManager;
102 private final NatMode natMode;
103 private final IInterfaceManager interfaceManager;
104 private final NatOverVxlanUtil natOverVxlanUtil;
106 private volatile Collection<String> externalIpsCache;
109 public NaptSwitchHA(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
110 final ExternalRoutersListener externalRouterListener,
111 final ItmRpcService itmManager,
112 final OdlInterfaceRpcService odlInterfaceRpcService,
113 final IdManagerService idManager,
114 final NAPTSwitchSelector naptSwitchSelector,
115 final IFibManager fibManager,
116 final EvpnNaptSwitchHA evpnNaptSwitchHA,
117 final IElanService elanManager,
118 final SnatServiceManager natServiceManager,
119 final NatserviceConfig config,
120 final NaptEventHandler naptEventHandler,
121 final IInterfaceManager interfaceManager,
122 final NatOverVxlanUtil natOverVxlanUtil) {
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;
141 this.natOverVxlanUtil = natOverVxlanUtil;
144 protected void removeSnatFlowsInOldNaptSwitch(Routers extRouter, Uint32 routerId, Uint64 naptSwitch,
145 @Nullable Map<String, Uint32> externalIpmap, String externalVpnName,
146 TypedReadWriteTransaction<Configuration> confTx)
147 throws ExecutionException, InterruptedException {
149 //remove SNAT flows in old NAPT SWITCH
150 String routerName = extRouter.getRouterName();
151 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
152 String vpnName = getExtNetworkVpnName(routerName, networkId);
153 if (vpnName == null) {
154 LOG.error("removeSnatFlowsInOldNaptSwitch : Vpn is not associated to externalN/w of router {}",
158 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, networkId);
159 if (extNwProvType == null) {
160 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the External Network Provider Type "
161 + "for Router {}", routerName);
164 if (extNwProvType == ProviderTypes.VXLAN) {
165 evpnNaptSwitchHA.evpnRemoveSnatFlowsInOldNaptSwitch(routerName, routerId, vpnName, naptSwitch, confTx);
167 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
168 Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
169 idManager, routerId, routerName);
170 String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
171 Uint32.valueOf(tunnelId));
172 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
175 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
176 + "with the DPN ID {} and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
177 mdsalManager.removeFlow(confTx, tsNatFlowEntity);
179 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
180 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
181 NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, naptSwitch);
183 //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
184 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
185 NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
187 String outboundTcpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
188 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_TCP);
189 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
190 NwConstants.OUTBOUND_NAPT_TABLE, outboundTcpNatFlowRef);
191 mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
193 String outboundUdpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
194 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_UDP);
195 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
196 NwConstants.OUTBOUND_NAPT_TABLE, outboundUdpNatFlowRef);
197 mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
199 String icmpDropFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
200 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_ICMP);
201 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
203 mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
205 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
206 // External Subnet Vpn Id.
207 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
209 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
210 Uint32 subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
211 if (subnetVpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
212 dataBroker, externalSubnetId, routerName, naptSwitch)) {
213 String natPfibSubnetFlowRef = externalRouterListener.getFlowRefTs(naptSwitch,
214 NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
215 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,
216 natPfibSubnetFlowRef);
217 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
218 LOG.debug("removeSnatFlowsInOldNaptSwitch : Removed the flow in table {} with external subnet "
219 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
220 subnetVpnId, naptSwitch);
224 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic
225 // matching on the router ID.
226 String naptPFibflowRef =
227 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
228 FlowEntity naptPFibFlowEntity =
229 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
230 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
231 + "with the DPN ID {} and router ID {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
232 mdsalManager.removeFlow(confTx, naptPFibFlowEntity);
234 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic
235 // matching on the vpn ID.
236 boolean switchSharedByRouters = false;
237 Uuid extNetworkId = extRouter.getNetworkId();
238 if (extNetworkId != null && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(
239 dataBroker, extNetworkId, routerName, naptSwitch)) {
240 List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
241 for (String routerNameAssociated : routerNamesAssociated) {
242 if (!routerNameAssociated.equals(routerName)) {
243 Uint32 routerIdAssociated = NatUtil.getVpnId(dataBroker, routerNameAssociated);
244 Uint64 naptDpn = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerNameAssociated);
245 if (naptDpn != null && naptDpn.equals(naptSwitch)) {
246 LOG.debug("removeSnatFlowsInOldNaptSwitch : Napt switch {} is also acting as primary "
247 + "for router {}", naptSwitch, routerIdAssociated);
248 switchSharedByRouters = true;
253 if (!switchSharedByRouters) {
254 Uint32 vpnId = NatUtil.getVpnId(dataBroker,externalVpnName);
255 if (vpnId != NatConstants.INVALID_ID) {
256 String naptFibflowRef =
257 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
258 FlowEntity naptFibFlowEntity =
259 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptFibflowRef);
260 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch"
261 + " with the DPN ID {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
262 mdsalManager.removeFlow(confTx, naptFibFlowEntity);
264 LOG.error("removeSnatFlowsInOldNaptSwitch : Invalid vpnId retrieved for routerId {}",
271 //Remove Fib entries,tables 20->44 ,36-> 44
272 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
273 if (externalIpmap != null && !externalIpmap.isEmpty()) {
274 for (Entry<String, Uint32> entry : externalIpmap.entrySet()) {
275 String externalIp = entry.getKey();
276 Uint32 label = entry.getValue();
277 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp, vpnName,
278 extNetworkId, label, gwMacAddress, true, confTx);
279 LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} "
280 + "for router {} and externalIps {} label {}", naptSwitch, routerId, externalIp, label);
283 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
284 if (extNetworkId != null) {
285 externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, extNetworkId,
286 externalIps, null, gwMacAddress, confTx);
288 "removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} for "
289 + "router {} with networkId {} and externalIps {}", naptSwitch, routerId, extNetworkId,
292 LOG.debug("removeSnatFlowsInOldNaptSwitch : External network not associated to router {}",
295 externalRouterListener.removeNaptFibExternalOutputFlows(routerId, naptSwitch, extNetworkId,
296 externalIps, confTx);
299 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
300 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
301 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
302 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
303 LOG.warn("removeSnatFlowsInOldNaptSwitch : No Internal Ip Port mapping associated to router {}, "
304 + "no flows need to be removed in oldNaptSwitch {}", routerId, naptSwitch);
307 Uint64 cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
308 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
309 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
310 if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
311 LOG.debug("removeSnatFlowsInOldNaptSwitch : No {} session associated to router {},"
312 + "no flows need to be removed in oldNaptSwitch {}",
313 intextIpProtocolType.getProtocol(), routerId, naptSwitch);
316 String protocol = intextIpProtocolType.getProtocol().name();
317 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
318 for (IpPortMap ipPortMap : ipPortMaps) {
319 String ipPortInternal = ipPortMap.getIpPortInternal();
320 String[] ipPortParts = ipPortInternal.split(":");
321 if (ipPortParts.length != 2) {
322 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the Internal IP and port");
325 String internalIp = ipPortParts[0];
326 String internalPort = ipPortParts[1];
328 //Build and remove flow in outbound NAPT table
329 String switchFlowRef =
330 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
331 internalIp, Integer.parseInt(internalPort), protocol);
332 FlowEntity outboundNaptFlowEntity =
333 NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
334 cookieSnatFlow, switchFlowRef);
336 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch "
337 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
338 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
340 //Build and remove flow in inbound NAPT table
342 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
343 internalIp, Integer.parseInt(internalPort), protocol);
344 FlowEntity inboundNaptFlowEntity =
345 NatUtil.buildFlowEntity(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
346 cookieSnatFlow, switchFlowRef);
349 "removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch with the "
350 + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, naptSwitch, routerId);
351 mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
357 private List<String> getRouterIdsForExtNetwork(Uuid extNetworkId) {
358 List<String> routerUuidsAsString = new ArrayList<>();
359 InstanceIdentifier<Networks> extNetwork = InstanceIdentifier.builder(ExternalNetworks.class)
360 .child(Networks.class, new NetworksKey(extNetworkId)).build();
361 Optional<Networks> extNetworkData =
362 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
363 LogicalDatastoreType.CONFIGURATION, extNetwork);
364 if (extNetworkData.isPresent()) {
365 List<Uuid> routerUuids = extNetworkData.get().getRouterIds();
366 if (routerUuids != null) {
367 for (Uuid routerUuid : routerUuids) {
368 routerUuidsAsString.add(routerUuid.getValue());
372 return routerUuidsAsString;
375 public boolean isNaptSwitchDown(Routers extRouter, Uint32 routerId, Uint64 dpnId, Uint64 naptSwitch,
376 Uint32 routerVpnId, Collection<String> externalIpCache,
377 TypedReadWriteTransaction<Configuration> confTx)
378 throws ExecutionException, InterruptedException {
379 return isNaptSwitchDown(extRouter, routerId, dpnId, naptSwitch, routerVpnId, externalIpCache, true,
383 // TODO Clean up the exception handling
384 @SuppressWarnings("checkstyle:IllegalCatch")
385 public boolean isNaptSwitchDown(Routers extRouter, Uint32 routerId, Uint64 dpnId, Uint64 naptSwitch,
386 Uint32 routerVpnId, Collection<String> externalIpCache, boolean isClearBgpRts,
387 TypedReadWriteTransaction<Configuration> confTx)
388 throws ExecutionException, InterruptedException {
389 externalIpsCache = externalIpCache;
390 String routerName = extRouter.getRouterName();
391 if (!naptSwitch.equals(dpnId)) {
392 LOG.debug("isNaptSwitchDown : DpnId {} is not a naptSwitch {} for Router {}",
393 dpnId, naptSwitch, routerName);
396 LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
397 if (routerId == NatConstants.INVALID_ID) {
398 LOG.error("isNaptSwitchDown : Invalid routerId returned for routerName {}", routerName);
401 Uuid networkId = extRouter.getNetworkId();
402 String vpnName = getExtNetworkVpnName(routerName, networkId);
403 //elect a new NaptSwitch
404 naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName, Arrays.asList(naptSwitch));
405 if (natMode == NatMode.Conntrack) {
406 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
407 natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
408 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_DISBL);
409 if (extRouters.isEnableSnat()) {
410 natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
411 SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
413 natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
414 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
415 if (extRouters.isEnableSnat()) {
416 natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
417 SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
420 if (naptSwitch.equals(Uint64.ZERO)) {
421 LOG.warn("isNaptSwitchDown : No napt switch is elected since all the switches for router {}"
422 + " are down. SNAT IS NOT SUPPORTED FOR ROUTER {}", routerName, routerName);
423 boolean naptUpdatedStatus = updateNaptSwitch(routerName, naptSwitch);
424 if (!naptUpdatedStatus) {
425 LOG.debug("isNaptSwitchDown : Failed to update naptSwitch {} for router {} in ds",
426 naptSwitch, routerName);
429 if (externalIpsCache != null) {
430 if (vpnName != null) {
431 //List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
432 //if (externalIps != null) {
434 LOG.debug("isNaptSwitchDown : Clearing both FIB entries and the BGP routes");
435 for (String externalIp : externalIpsCache) {
436 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
439 LOG.debug("isNaptSwitchDown : Clearing the FIB entries but not the BGP routes");
440 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
441 for (String externalIp : externalIpsCache) {
442 LOG.debug("isNaptSwitchDown : Removing Fib entry rd {} prefix {}", rd, externalIp);
443 fibManager.removeFibEntry(rd, externalIp, null, null);
447 LOG.debug("isNaptSwitchDown : vpn is not associated to extn/w for router {}", routerName);
450 LOG.debug("isNaptSwitchDown : No ExternalIps found for subnets under router {}, "
451 + "no bgp routes need to be cleared", routerName);
455 //checking elected switch health status
456 if (!NatUtil.getSwitchStatus(dataBroker, naptSwitch)) {
457 LOG.error("isNaptSwitchDown : Newly elected Napt switch {} for router {} is down",
458 naptSwitch, routerName);
461 LOG.debug("isNaptSwitchDown : New NaptSwitch {} is up for Router {} and can proceed for flow installation",
462 naptSwitch, routerName);
463 //update napt model for new napt switch
464 boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
466 //update group of ordinary switch point to naptSwitch tunnel port
467 updateNaptSwitchBucketStatus(routerName, routerId, naptSwitch);
469 LOG.error("isNaptSwitchDown : Failed to update naptSwitch model for newNaptSwitch {} for router {}",
470 naptSwitch, routerName);
473 //update table26 forward packets to table46(outbound napt table)
474 FlowEntity flowEntity =
475 buildSnatFlowEntityForNaptSwitch(naptSwitch, routerName, routerVpnId, NatConstants.ADD_FLOW);
476 if (flowEntity == null) {
477 LOG.error("isNaptSwitchDown : Failed to populate flowentity for router {} in naptSwitch {}",
478 routerName, naptSwitch);
480 LOG.debug("isNaptSwitchDown : Successfully installed flow in naptSwitch {} for router {}",
481 naptSwitch, routerName);
482 mdsalManager.addFlow(confTx, flowEntity);
485 installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, networkId, vpnName, confTx);
487 boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerName, routerId, dpnId, naptSwitch,
488 routerVpnId, networkId);
489 if (flowInstalledStatus) {
490 LOG.debug("isNaptSwitchDown :Installed all active session flows in newNaptSwitch {} for routerName {}",
491 naptSwitch, routerName);
493 LOG.error("isNaptSwitchDown : Failed to install flows in newNaptSwitch {} for routerId {}",
494 naptSwitch, routerId);
497 //remove group in new naptswitch, coz this switch acted previously as ordinary switch
498 Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
499 NatUtil.getGroupIdKey(routerName));
500 if (groupId != NatConstants.INVALID_ID) {
502 LOG.info("isNaptSwitchDown : Removing NAPT Group in new naptSwitch {}",
504 mdsalManager.removeGroup(confTx, naptSwitch, groupId.longValue());
505 } catch (Exception ex) {
506 LOG.error("isNaptSwitchDown : Failed to remove group in new naptSwitch {}",
510 LOG.error("NAT Service : Unable to obtain groupId for router:{}", routerName);
517 private String getExtNetworkVpnName(String routerName, Uuid networkId) {
518 if (networkId == null) {
519 LOG.error("getExtNetworkVpnName : networkId is null for the router ID {}", routerName);
521 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
522 if (vpnName != null) {
523 LOG.debug("getExtNetworkVpnName : retrieved vpn name {} associated with ext nw {} in router {}",
524 vpnName, networkId, routerName);
527 LOG.error("getExtNetworkVpnName : No VPN associated with ext nw {} belonging to routerId {}",
528 networkId, routerName);
531 LOG.error("getExtNetworkVpnName : External Network VPN not found for router : {}", routerName);
535 public void updateNaptSwitchBucketStatus(String routerName, Uint32 routerId, Uint64 naptSwitch) {
536 LOG.debug("updateNaptSwitchBucketStatus : called");
538 List<Uint64> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
539 //List<BigInteger> dpnList = getDpnListForRouter(routerName);
540 if (dpnList.isEmpty()) {
541 LOG.warn("updateNaptSwitchBucketStatus : No switches found for router {}", routerName);
544 for (Uint64 dpn : dpnList) {
545 if (!dpn.equals(naptSwitch)) {
546 LOG.debug("updateNaptSwitchBucketStatus : Updating SNAT_TABLE missentry for DpnId {} "
547 + "which is not naptSwitch for router {}", dpn, routerName);
548 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, routerId, naptSwitch);
549 if (bucketInfoList.isEmpty()) {
550 LOG.error("Failed to populate bucketInfo for non-napt switch {} whose naptSwitch:{} for router:{}",
551 dpn,naptSwitch,routerName);
554 modifySnatGroupEntry(dpn, bucketInfoList, routerName);
555 externalRouterListener.installSnatMissEntry(dpn, bucketInfoList, routerName, routerId);
560 // TODO Clean up the exception handling
561 @SuppressWarnings("checkstyle:IllegalCatch")
562 private boolean handleNatFlowsInNewNaptSwitch(String routerName, Uint32 routerId, Uint64 oldNaptSwitch,
563 Uint64 newNaptSwitch, Uint32 routerVpnId, Uuid networkId) {
564 LOG.debug("handleNatFlowsInNewNaptSwitch : Proceeding to install flows in newNaptSwitch {} for routerId {}",
565 newNaptSwitch, routerId);
566 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
567 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
568 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
569 LOG.debug("handleNatFlowsInNewNaptSwitch : No Internal Ip Port mapping associated to router {},"
570 + "no flows need to be installed in newNaptSwitch {}", routerId, newNaptSwitch);
574 Uint32 vpnId = getVpnIdForRouter(routerId, networkId);
575 if (vpnId == NatConstants.INVALID_ID) {
576 LOG.error("handleNatFlowsInNewNaptSwitch : Invalid vpnId for routerId {}", routerId);
580 if (routerId.equals(routerVpnId)) {
581 bgpVpnId = NatConstants.INVALID_ID;
583 bgpVpnId = routerVpnId;
585 LOG.debug("handleNatFlowsInNewNaptSwitch : retrieved bgpVpnId {} for router {}", bgpVpnId, routerId);
586 // Get the External Gateway MAC Address
587 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
588 if (extGwMacAddress != null) {
589 LOG.debug("handleNatFlowsInNewNaptSwitch :External Gateway MAC address {} found for External Router ID {}",
590 extGwMacAddress, routerId);
592 LOG.error("handleNatFlowsInNewNaptSwitch : No External Gateway MAC address found for External Router ID {}",
596 for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
597 if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
598 LOG.debug("handleNatFlowsInNewNaptSwitch : No {} session associated to router {}",
599 protocolType.getProtocol(), routerId);
602 for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
603 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
604 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
605 LOG.debug("handleNatFlowsInNewNaptSwitch : Found Internal IP Address {} and Port Number {}",
606 internalIpAddress, intportnum);
607 //Get the external IP address and the port from the model
608 NAPTEntryEvent.Protocol proto =
609 protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
610 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
611 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
612 internalIpAddress, intportnum, proto);
613 if (ipPortExternal == null) {
614 LOG.debug("handleNatFlowsInNewNaptSwitch : External Ipport mapping is not found for internalIp {} "
615 + "with port {}", internalIpAddress, intportnum);
618 String externalIpAddress = ipPortExternal.getIpAddress();
619 Integer extportNumber = ipPortExternal.getPortNum().toJava();
620 LOG.debug("handleNatFlowsInNewNaptSwitch : ExternalIPport {}:{} mapping for internal ipport {}:{}",
621 externalIpAddress, extportNumber, internalIpAddress, intportnum);
623 SessionAddress sourceAddress = new SessionAddress(internalIpAddress, Integer.parseInt(intportnum));
624 SessionAddress externalAddress = new SessionAddress(externalIpAddress, extportNumber);
626 //checking naptSwitch status before installing flows
627 if (NatUtil.getSwitchStatus(dataBroker, newNaptSwitch)) {
628 //Install the flow in newNaptSwitch Inbound NAPT table.
630 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.INBOUND_NAPT_TABLE,
631 vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto, extGwMacAddress);
632 } catch (RuntimeException ex) {
633 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in INBOUND_NAPT_TABLE for "
634 + "routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{} BgpVpnId {}",
635 routerId, newNaptSwitch, externalAddress, extportNumber, proto,
636 internalIpAddress, intportnum, bgpVpnId);
639 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
640 + "Inbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
641 newNaptSwitch, routerId, internalIpAddress,
642 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
643 //Install the flow in newNaptSwitch Outbound NAPT table.
645 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
646 vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto, extGwMacAddress);
647 } catch (RuntimeException ex) {
648 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in OUTBOUND_NAPT_TABLE for "
649 + "routerid {} dpnId {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
650 routerId, newNaptSwitch, internalIpAddress,
651 intportnum, proto, externalAddress, extportNumber, bgpVpnId, ex);
654 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
655 + "Outbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
656 newNaptSwitch, routerId, internalIpAddress,
657 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
659 LOG.error("handleNatFlowsInNewNaptSwitch : NewNaptSwitch {} gone down while installing flows "
660 + "from oldNaptswitch {}", newNaptSwitch, oldNaptSwitch);
668 // TODO Clean up the exception handling
669 @SuppressWarnings("checkstyle:IllegalCatch")
670 private Uint32 getVpnIdForRouter(Uint32 routerId, Uuid networkId) {
673 if (networkId == null) {
674 LOG.debug("getVpnIdForRouter : network is not associated to router {}", routerId);
676 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
677 if (vpnUuid == null) {
678 LOG.debug("getVpnIdForRouter : vpn is not associated for network {} in router {}",
679 networkId, routerId);
681 Uint32 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
682 if (vpnId.longValue() > 0) {
683 LOG.debug("getVpnIdForRouter : retrieved vpnId {} for router {}", vpnId, routerId);
686 LOG.debug("getVpnIdForRouter : retrieved invalid vpn Id");
690 } catch (Exception ex) {
691 LOG.error("getVpnIdForRouter : Exception while retrieving vpnId for router {}", routerId, ex);
693 return NatConstants.INVALID_ID;
697 public List<BucketInfo> handleGroupInNeighborSwitches(Uint64 dpnId, String routerName, Uint32 routerId,
699 List<BucketInfo> listBucketInfo = new ArrayList<>();
700 String ifNamePrimary;
701 if (routerId == NatConstants.INVALID_ID) {
702 LOG.error("handleGroupInNeighborSwitches : Invalid routerId returned for routerName {}", routerName);
703 return listBucketInfo;
705 ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
706 if (ifNamePrimary != null) {
707 LOG.debug("handleGroupInNeighborSwitches : TunnelInterface {} between ordinary switch {} and naptSwitch {}",
708 ifNamePrimary, dpnId, naptSwitch);
709 List<ActionInfo> listActionInfoPrimary =
710 NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager, interfaceManager,
711 ifNamePrimary, routerId, true);
712 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
713 listBucketInfo.add(bucketPrimary);
715 LOG.debug("handleGroupInNeighborSwitches : No TunnelInterface between ordinary switch {} and naptSwitch {}",
718 return listBucketInfo;
721 // TODO Clean up the exception handling
722 @SuppressWarnings("checkstyle:IllegalCatch")
723 protected void installSnatGroupEntry(Uint64 dpnId, List<BucketInfo> bucketInfo, String routerName) {
724 GroupEntity groupEntity = null;
726 Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
727 NatUtil.getGroupIdKey(routerName));
728 if (groupId != NatConstants.INVALID_ID) {
730 "installSnatGroupEntry : install SnatMissEntry for groupId {} for dpnId {} for router {}",
731 groupId, dpnId, routerName);
732 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId.longValue(), routerName,
733 GroupTypes.GroupAll, bucketInfo);
734 mdsalManager.syncInstallGroup(groupEntity);
735 LOG.debug("installSnatGroupEntry : installed the SNAT to NAPT GroupEntity:{}",
738 LOG.error("installSnatGroupEntry: Unable to obtain groupId for router:{}", routerName);
740 } catch (Exception ex) {
741 LOG.error("installSnatGroupEntry : Failed to install group for groupEntity {}", groupEntity, ex);
745 private void modifySnatGroupEntry(Uint64 dpnId, List<BucketInfo> bucketInfo, String routerName) {
746 installSnatGroupEntry(dpnId, bucketInfo, routerName);
747 LOG.debug("modifySnatGroupEntry : modified SnatMissEntry for dpnId {} of router {}", dpnId, routerName);
751 protected String getTunnelInterfaceName(Uint64 srcDpId, Uint64 dstDpId) {
752 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
753 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
756 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
757 new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId)
758 .setTunnelType(tunType).build());
759 rpcResult = result.get();
760 if (!rpcResult.isSuccessful()) {
761 tunType = TunnelTypeGre.class;
762 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
763 .setSourceDpid(srcDpId)
764 .setDestinationDpid(dstDpId)
765 .setTunnelType(tunType)
767 rpcResult = result.get();
768 if (!rpcResult.isSuccessful()) {
769 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
770 rpcResult.getErrors());
772 return rpcResult.getResult().getInterfaceName();
774 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
775 rpcResult.getErrors());
777 return rpcResult.getResult().getInterfaceName();
779 } catch (InterruptedException | ExecutionException e) {
780 LOG.error("getTunnelInterfaceName :Exception when getting tunnel interface Id for tunnel between {} and {}",
781 srcDpId, dstDpId, e);
783 LOG.error("getTunnelInterfaceName : Tunnel missing between dpn {}:{}", srcDpId, dstDpId);
787 // TODO Clean up the exception handling
788 @SuppressWarnings("checkstyle:IllegalCatch")
789 public boolean updateNaptSwitch(String routerName, Uint64 naptSwitchId) {
790 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
791 .setPrimarySwitchId(naptSwitchId).build();
793 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
794 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
795 } catch (Exception ex) {
796 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
797 naptSwitchId, routerName);
800 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
801 naptSwitchId, routerName);
805 public FlowEntity buildSnatFlowEntity(Uint64 dpId, String routerName, long groupId,
806 Uint32 routerVpnId, int addordel) {
807 FlowEntity flowEntity;
808 List<MatchInfo> matches = new ArrayList<>();
809 matches.add(MatchEthernetType.IPV4);
810 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId.longValue()),
811 MetaDataUtil.METADATA_MASK_VRFID));
813 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
815 if (addordel == NatConstants.ADD_FLOW) {
816 List<ActionInfo> actionsInfo = new ArrayList<>();
817 Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
818 idManager, routerVpnId, routerName);
819 actionsInfo.add(new ActionSetFieldTunnelId(tunnelId));
820 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
821 actionsInfo.add(new ActionGroup(groupId));
822 List<InstructionInfo> instructions = new ArrayList<>();
823 instructions.add(new InstructionApplyActions(actionsInfo));
825 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
826 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
827 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
829 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
830 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
831 NwConstants.COOKIE_SNAT_TABLE, matches, null);
836 public FlowEntity buildSnatFlowEntityForNaptSwitch(Uint64 dpId, String routerName,
837 Uint32 routerVpnId, int addordel) {
838 FlowEntity flowEntity;
839 List<MatchInfo> matches = new ArrayList<>();
840 matches.add(MatchEthernetType.IPV4);
841 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId.longValue()),
842 MetaDataUtil.METADATA_MASK_VRFID));
844 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
846 if (addordel == NatConstants.ADD_FLOW) {
847 List<InstructionInfo> instructions = new ArrayList<>();
849 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
851 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
852 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
853 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
855 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
856 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
857 NwConstants.COOKIE_SNAT_TABLE, matches, null);
862 private String getFlowRefSnat(Uint64 dpnId, short tableId, String routerID) {
863 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
864 .FLOWID_SEPARATOR + routerID;
867 protected void installSnatFlows(String routerName, Uint32 routerId, Uint64 naptSwitch, Uint32 routerVpnId,
868 Uuid networkId, String vpnName, TypedReadWriteTransaction<Configuration> confTx) {
870 if (routerId.equals(routerVpnId)) {
871 LOG.debug("installSnatFlows : Installing flows for router with internalvpnId");
872 //36 -> 46 ..Install flow forwarding packet to table46 from table36
873 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
874 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
875 externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName, routerId, confTx);
877 //Install default flows punting to controller in table 46(OutBoundNapt table)
878 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
879 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
880 externalRouterListener.createOutboundTblEntry(naptSwitch, routerId, confTx);
882 //Table 47 point to table 21 for inbound traffic
883 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {}",
884 naptSwitch, routerId);
885 externalRouterListener.installNaptPfibEntry(naptSwitch, routerId, confTx);
887 //Table 47 point to group
888 LOG.debug("installSnatFlows : installNaptPfibExternalOutputFlow in naptswitch with dpnId {} for router {}",
889 naptSwitch, routerId);
890 externalRouterListener.installNaptPfibExternalOutputFlow(routerName, routerId, naptSwitch, confTx);
892 Uuid extNetworkUuid = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
893 if (extNetworkUuid == null) {
894 LOG.error("onRouterAssociatedToVpn : Unable to retrieve external network Uuid for router {}",
898 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
900 if (extNwProvType == null) {
901 LOG.error("onRouterAssociatedToVpn : External Network Provider Type missing");
904 //36 -> 46 ..Install flow forwarding packet to table46 from table36
905 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
906 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
907 externalRouterListener
908 .installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerId,
909 routerVpnId, confTx, extNwProvType);
911 //Install default flows punting to controller in table 46(OutBoundNapt table)
912 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
913 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
914 externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
916 //Table 47 point to table 21 for inbound traffic
917 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {} "
918 + "with BgpVpnId {}", naptSwitch, routerId, routerVpnId);
919 externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
922 if (vpnName != null) {
923 //NAPT PFIB point to FIB table for outbound traffic
924 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
925 .instance.to.vpn.id.VpnInstance vpnInstance = NatUtil.getVpnIdToVpnInstance(dataBroker, vpnName);
926 if (vpnInstance == null) {
927 LOG.error("NAT Service : installNaptPfibEntry vpnInstance not found for {}", vpnName);
930 Uint32 vpnId = vpnInstance.getVpnId();
931 if (vpnName.equals(networkId.getValue())) {
932 // below condition valid only for flat/vlan use-case
933 boolean shouldInstallNaptPfibWithExtNetworkVpnId = true;
934 Collection<Uuid> externalSubnetIds = NatUtil
935 .getExternalSubnetIdsForRouter(dataBroker, routerName);
936 if (!externalSubnetIds.isEmpty()) {
937 //NAPT PFIB point to FIB table for outbound traffic - using external subnetID as vpnID.
938 for (Uuid externalSubnetId : externalSubnetIds) {
939 Uint32 externalSubnetVpnId = NatUtil
940 .getExternalSubnetVpnId(dataBroker, externalSubnetId);
941 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
942 shouldInstallNaptPfibWithExtNetworkVpnId = false;
944 "installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
945 + "BgpVpnId {}", naptSwitch, externalSubnetVpnId);
946 externalRouterListener
947 .installNaptPfibEntry(naptSwitch, externalSubnetVpnId, confTx);
951 if (vpnId != NatConstants.INVALID_ID && shouldInstallNaptPfibWithExtNetworkVpnId) {
952 //NAPT PFIB table point to FIB table for outbound traffic - using external networkID as vpnID.
954 "installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
955 + "BgpVpnId {}", naptSwitch, vpnId);
956 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId, confTx);
957 } else if (vpnId != NatConstants.INVALID_ID) {
958 LOG.debug("installSnatFlows : Associated BgpvpnId not found for router {}",
962 //Install Fib entries for ExternalIps & program 36 -> 44
963 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
964 String rd = vpnInstance.getVrfId();
965 for (String externalIp : externalIps) {
966 removeFibEntry(rd, externalIp);
967 LOG.debug("installSnatFlows : advToBgpAndInstallFibAndTsFlows in naptswitch id {} "
968 + "with vpnName {} and externalIp {}", naptSwitch, vpnName, externalIp);
969 externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
970 vpnName, routerId, routerName, externalIp, networkId, null /* external-router */, confTx);
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(Uint32 routerId, String routerName, Map<String, Uint32> externalIpLabel,
980 TypedReadWriteTransaction<Configuration> confTx)
981 throws ExecutionException, InterruptedException {
982 Collection<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
983 if (externalIpsCache != null) {
984 Set<String> removedExternalIps = new HashSet<>(externalIpsCache);
985 removedExternalIps.removeAll(newExternalIps);
986 if (removedExternalIps.isEmpty()) {
987 LOG.info("bestEffortDeletion : No external Ip needed to be removed in bestEffortDeletion "
988 + "method for router {}", routerName);
991 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
992 String vpnName = getExtNetworkVpnName(routerName, networkId);
993 if (vpnName == null) {
994 LOG.error("bestEffortDeletion : Vpn is not associated to externalN/w of router {}", routerName);
997 Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
998 if (naptSwitch == null || naptSwitch.equals(Uint64.ZERO)) {
999 LOG.error("bestEffortDeletion : No naptSwitch is selected for router {}", routerName);
1002 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName, networkId);
1003 if (extNwProvType == null) {
1006 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1007 if (gwMacAddress != null) {
1008 LOG.debug("bestEffortDeletion : External Gateway MAC address {} found for External Router ID {}",
1009 gwMacAddress, routerId);
1011 LOG.error("bestEffortDeletion : No External Gateway MAC address found for External Router ID {}",
1015 if (extNwProvType == ProviderTypes.VXLAN) {
1016 for (String externalIp : removedExternalIps) {
1017 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1018 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
1019 vpnName, networkId, NatConstants.DEFAULT_LABEL_VALUE, gwMacAddress, true, confTx);
1020 LOG.debug("bestEffortDeletion : Successfully removed fib entry for externalIp {} for routerId {} "
1021 + "on NAPT switch {} ", externalIp, routerId, naptSwitch);
1024 if (externalIpLabel == null || externalIpLabel.isEmpty()) {
1025 LOG.error("bestEffortDeletion : ExternalIpLabel map is empty for router {}", routerName);
1029 for (String externalIp : removedExternalIps) {
1030 if (externalIpLabel.containsKey(externalIp)) {
1031 label = externalIpLabel.get(externalIp);
1032 LOG.debug("bestEffortDeletion : Label {} for ExternalIp {} for router {}",
1033 label, externalIp, routerName);
1035 LOG.debug("bestEffortDeletion : Label for ExternalIp {} is not found for router {}",
1036 externalIp, routerName);
1039 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1040 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
1041 vpnName, networkId, label, gwMacAddress, true, confTx);
1042 LOG.debug("bestEffortDeletion : Successfully removed fib entries in switch {} for router {} "
1043 + "and externalIps {}", naptSwitch, routerId, externalIp);
1047 LOG.debug("bestEffortDeletion : No external IP found for router {}", routerId);
1051 private void removeFibEntry(String rd, String prefix) {
1052 InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
1053 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
1054 .child(VrfEntry.class, new VrfEntryKey(prefix));
1055 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
1056 Optional<VrfEntry> ent = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
1057 if (ent.isPresent()) {
1058 LOG.debug("removeFibEntry : Removing Fib entry rd {} prefix {}", rd, prefix);
1059 fibManager.removeFibEntry(rd, prefix, null, null);
1063 protected void subnetRegisterMapping(Routers routerEntry, Uint32 segmentId) {
1064 externalRouterListener.subnetRegisterMapping(routerEntry, segmentId);