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 java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.HashSet;
14 import java.util.List;
16 import java.util.Map.Entry;
17 import java.util.Optional;
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.genius.datastoreutils.SingleTransactionDataBroker;
26 import org.opendaylight.genius.infra.Datastore.Configuration;
27 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
28 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
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.ActionSetFieldTunnelId;
40 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
41 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
42 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
43 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
44 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
45 import org.opendaylight.mdsal.binding.api.DataBroker;
46 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
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.IntextIpProtocolTypeKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
78 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;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
82 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
83 import org.opendaylight.yangtools.yang.common.RpcResult;
84 import org.opendaylight.yangtools.yang.common.Uint32;
85 import org.opendaylight.yangtools.yang.common.Uint64;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
90 public class NaptSwitchHA {
91 private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
92 private final DataBroker dataBroker;
93 private final IMdsalApiManager mdsalManager;
94 private final ItmRpcService itmManager;
95 private final OdlInterfaceRpcService odlInterfaceRpcService;
96 private final IdManagerService idManager;
97 private final NAPTSwitchSelector naptSwitchSelector;
98 private final ExternalRoutersListener externalRouterListener;
99 private final NaptEventHandler naptEventHandler;
100 private final IFibManager fibManager;
101 private final IElanService elanManager;
102 private final EvpnNaptSwitchHA evpnNaptSwitchHA;
103 private final SnatServiceManager natServiceManager;
104 private final NatMode natMode;
105 private final IInterfaceManager interfaceManager;
106 private final NatOverVxlanUtil natOverVxlanUtil;
108 private volatile Collection<String> externalIpsCache;
111 public NaptSwitchHA(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
112 final ExternalRoutersListener externalRouterListener,
113 final ItmRpcService itmManager,
114 final OdlInterfaceRpcService odlInterfaceRpcService,
115 final IdManagerService idManager,
116 final NAPTSwitchSelector naptSwitchSelector,
117 final IFibManager fibManager,
118 final EvpnNaptSwitchHA evpnNaptSwitchHA,
119 final IElanService elanManager,
120 final SnatServiceManager natServiceManager,
121 final NatserviceConfig config,
122 final NaptEventHandler naptEventHandler,
123 final IInterfaceManager interfaceManager,
124 final NatOverVxlanUtil natOverVxlanUtil) {
125 this.dataBroker = dataBroker;
126 this.mdsalManager = mdsalManager;
127 this.externalRouterListener = externalRouterListener;
128 this.itmManager = itmManager;
129 this.odlInterfaceRpcService = odlInterfaceRpcService;
130 this.idManager = idManager;
131 this.naptSwitchSelector = naptSwitchSelector;
132 this.naptEventHandler = naptEventHandler;
133 this.fibManager = fibManager;
134 this.evpnNaptSwitchHA = evpnNaptSwitchHA;
135 this.elanManager = elanManager;
136 this.natServiceManager = natServiceManager;
137 this.interfaceManager = interfaceManager;
138 if (config != null) {
139 this.natMode = config.getNatMode();
141 this.natMode = NatMode.Controller;
143 this.natOverVxlanUtil = natOverVxlanUtil;
146 protected void removeSnatFlowsInOldNaptSwitch(Routers extRouter, Uint32 routerId, Uint64 naptSwitch,
147 @Nullable Map<String, Uint32> externalIpmap, String externalVpnName,
148 TypedReadWriteTransaction<Configuration> confTx)
149 throws ExecutionException, InterruptedException {
151 //remove SNAT flows in old NAPT SWITCH
152 String routerName = extRouter.getRouterName();
153 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
154 String vpnName = getExtNetworkVpnName(routerName, networkId);
155 if (vpnName == null) {
156 LOG.error("removeSnatFlowsInOldNaptSwitch : Vpn is not associated to externalN/w of router {}",
160 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, networkId);
161 if (extNwProvType == null) {
162 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the External Network Provider Type "
163 + "for Router {}", routerName);
166 if (extNwProvType == ProviderTypes.VXLAN) {
167 evpnNaptSwitchHA.evpnRemoveSnatFlowsInOldNaptSwitch(routerName, routerId, vpnName, naptSwitch, confTx);
169 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
170 Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
171 idManager, routerId, routerName);
172 String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
173 Uint32.valueOf(tunnelId));
174 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
177 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
178 + "with the DPN ID {} and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
179 mdsalManager.removeFlow(confTx, tsNatFlowEntity);
181 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
182 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
183 NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, naptSwitch);
185 //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
186 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
187 NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
189 String outboundTcpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
190 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_TCP);
191 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
192 NwConstants.OUTBOUND_NAPT_TABLE, outboundTcpNatFlowRef);
193 mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
195 String outboundUdpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
196 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_UDP);
197 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
198 NwConstants.OUTBOUND_NAPT_TABLE, outboundUdpNatFlowRef);
199 mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
201 String icmpDropFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
202 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_ICMP);
203 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
205 mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
207 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
208 // External Subnet Vpn Id.
209 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
211 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
212 Uint32 subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
213 if (subnetVpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
214 dataBroker, externalSubnetId, routerName, naptSwitch)) {
215 String natPfibSubnetFlowRef = externalRouterListener.getFlowRefTs(naptSwitch,
216 NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
217 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,
218 natPfibSubnetFlowRef);
219 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
220 LOG.debug("removeSnatFlowsInOldNaptSwitch : Removed the flow in table {} with external subnet "
221 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
222 subnetVpnId, naptSwitch);
226 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic
227 // matching on the router ID.
228 String naptPFibflowRef =
229 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
230 FlowEntity naptPFibFlowEntity =
231 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
232 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
233 + "with the DPN ID {} and router ID {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
234 mdsalManager.removeFlow(confTx, naptPFibFlowEntity);
236 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic
237 // matching on the vpn ID.
238 boolean switchSharedByRouters = false;
239 Uuid extNetworkId = extRouter.getNetworkId();
240 if (extNetworkId != null && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(
241 dataBroker, extNetworkId, routerName, naptSwitch)) {
242 List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
243 for (String routerNameAssociated : routerNamesAssociated) {
244 if (!routerNameAssociated.equals(routerName)) {
245 Uint32 routerIdAssociated = NatUtil.getVpnId(dataBroker, routerNameAssociated);
246 Uint64 naptDpn = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerNameAssociated);
247 if (naptDpn != null && naptDpn.equals(naptSwitch)) {
248 LOG.debug("removeSnatFlowsInOldNaptSwitch : Napt switch {} is also acting as primary "
249 + "for router {}", naptSwitch, routerIdAssociated);
250 switchSharedByRouters = true;
255 if (!switchSharedByRouters) {
256 Uint32 vpnId = NatUtil.getVpnId(dataBroker,externalVpnName);
257 if (vpnId != NatConstants.INVALID_ID) {
258 String naptFibflowRef =
259 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
260 FlowEntity naptFibFlowEntity =
261 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptFibflowRef);
262 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch"
263 + " with the DPN ID {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
264 mdsalManager.removeFlow(confTx, naptFibFlowEntity);
266 LOG.error("removeSnatFlowsInOldNaptSwitch : Invalid vpnId retrieved for routerId {}",
273 //Remove Fib entries,tables 20->44 ,36-> 44
274 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
275 if (externalIpmap != null && !externalIpmap.isEmpty()) {
276 for (Entry<String, Uint32> entry : externalIpmap.entrySet()) {
277 String externalIp = entry.getKey();
278 Uint32 label = entry.getValue();
279 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp, vpnName,
280 extNetworkId, label, gwMacAddress, true, confTx);
281 LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} "
282 + "for router {} and externalIps {} label {}", naptSwitch, routerId, externalIp, label);
285 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
286 if (extNetworkId != null) {
287 externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, extNetworkId,
288 externalIps, null, gwMacAddress, confTx);
290 "removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} for "
291 + "router {} with networkId {} and externalIps {}", naptSwitch, routerId, extNetworkId,
294 LOG.debug("removeSnatFlowsInOldNaptSwitch : External network not associated to router {}",
297 externalRouterListener.removeNaptFibExternalOutputFlows(routerId, naptSwitch, extNetworkId,
298 externalIps, confTx);
301 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
302 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
303 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
304 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
305 LOG.warn("removeSnatFlowsInOldNaptSwitch : No Internal Ip Port mapping associated to router {}, "
306 + "no flows need to be removed in oldNaptSwitch {}", routerId, naptSwitch);
309 Uint64 cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
310 Map<IntextIpProtocolTypeKey, IntextIpProtocolType> keyIntextIpProtocolTypeMap
311 = ipPortMapping.getIntextIpProtocolType();
312 for (IntextIpProtocolType intextIpProtocolType : keyIntextIpProtocolTypeMap.values()) {
313 if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
314 LOG.debug("removeSnatFlowsInOldNaptSwitch : No {} session associated to router {},"
315 + "no flows need to be removed in oldNaptSwitch {}",
316 intextIpProtocolType.getProtocol(), routerId, naptSwitch);
319 String protocol = intextIpProtocolType.getProtocol().name();
320 Map<IpPortMapKey, IpPortMap> keyIpPortMapMap = intextIpProtocolType.getIpPortMap();
321 for (IpPortMap ipPortMap : keyIpPortMapMap.values()) {
322 String ipPortInternal = ipPortMap.getIpPortInternal();
323 String[] ipPortParts = ipPortInternal.split(":");
324 if (ipPortParts.length != 2) {
325 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the Internal IP and port");
328 String internalIp = ipPortParts[0];
329 String internalPort = ipPortParts[1];
331 //Build and remove flow in outbound NAPT table
332 String switchFlowRef =
333 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
334 internalIp, Integer.parseInt(internalPort), protocol);
335 FlowEntity outboundNaptFlowEntity =
336 NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
337 cookieSnatFlow, switchFlowRef);
339 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch "
340 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
341 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
343 //Build and remove flow in inbound NAPT table
345 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
346 internalIp, Integer.parseInt(internalPort), protocol);
347 FlowEntity inboundNaptFlowEntity =
348 NatUtil.buildFlowEntity(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
349 cookieSnatFlow, switchFlowRef);
352 "removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch with the "
353 + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, naptSwitch, routerId);
354 mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
360 private List<String> getRouterIdsForExtNetwork(Uuid extNetworkId) {
361 List<String> routerUuidsAsString = new ArrayList<>();
362 InstanceIdentifier<Networks> extNetwork = InstanceIdentifier.builder(ExternalNetworks.class)
363 .child(Networks.class, new NetworksKey(extNetworkId)).build();
364 Optional<Networks> extNetworkData =
365 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
366 LogicalDatastoreType.CONFIGURATION, extNetwork);
367 if (extNetworkData.isPresent()) {
368 List<Uuid> routerUuids = extNetworkData.get().getRouterIds();
369 if (routerUuids != null) {
370 for (Uuid routerUuid : routerUuids) {
371 routerUuidsAsString.add(routerUuid.getValue());
375 return routerUuidsAsString;
378 public boolean isNaptSwitchDown(Routers extRouter, Uint32 routerId, Uint64 dpnId, Uint64 naptSwitch,
379 Uint32 routerVpnId, Collection<String> externalIpCache,
380 TypedReadWriteTransaction<Configuration> confTx)
381 throws ExecutionException, InterruptedException {
382 return isNaptSwitchDown(extRouter, routerId, dpnId, naptSwitch, routerVpnId, externalIpCache, true,
386 // TODO Clean up the exception handling
387 @SuppressWarnings("checkstyle:IllegalCatch")
388 public boolean isNaptSwitchDown(Routers extRouter, Uint32 routerId, Uint64 dpnId, Uint64 naptSwitch,
389 Uint32 routerVpnId, Collection<String> externalIpCache, boolean isClearBgpRts,
390 TypedReadWriteTransaction<Configuration> confTx)
391 throws ExecutionException, InterruptedException {
392 externalIpsCache = externalIpCache;
393 String routerName = extRouter.getRouterName();
394 if (!naptSwitch.equals(dpnId)) {
395 LOG.debug("isNaptSwitchDown : DpnId {} is not a naptSwitch {} for Router {}",
396 dpnId, naptSwitch, routerName);
399 LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
400 if (routerId == NatConstants.INVALID_ID) {
401 LOG.error("isNaptSwitchDown : Invalid routerId returned for routerName {}", routerName);
404 Uuid networkId = extRouter.getNetworkId();
405 String vpnName = getExtNetworkVpnName(routerName, networkId);
406 //elect a new NaptSwitch
407 naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName, Arrays.asList(naptSwitch));
408 if (natMode == NatMode.Conntrack) {
409 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
410 natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
411 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_DISBL);
412 if (extRouters.isEnableSnat()) {
413 natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
414 SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
416 natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
417 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
418 if (extRouters.isEnableSnat()) {
419 natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
420 SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
423 if (naptSwitch.equals(Uint64.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, 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, 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 (!NatUtil.getSwitchStatus(dataBroker, 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.addFlow(confTx, flowEntity);
488 installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, networkId, vpnName, confTx);
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 Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
502 NatUtil.getGroupIdKey(routerName));
503 if (groupId != NatConstants.INVALID_ID) {
505 LOG.info("isNaptSwitchDown : Removing NAPT Group in new naptSwitch {}",
507 mdsalManager.removeGroup(confTx, naptSwitch, groupId.longValue());
508 } catch (Exception ex) {
509 LOG.error("isNaptSwitchDown : Failed to remove group in new naptSwitch {}",
513 LOG.error("NAT Service : Unable to obtain groupId for router:{}", routerName);
520 private String getExtNetworkVpnName(String routerName, Uuid networkId) {
521 if (networkId == null) {
522 LOG.error("getExtNetworkVpnName : networkId is null for the router ID {}", routerName);
524 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
525 if (vpnName != null) {
526 LOG.debug("getExtNetworkVpnName : retrieved vpn name {} associated with ext nw {} in router {}",
527 vpnName, networkId, routerName);
530 LOG.error("getExtNetworkVpnName : No VPN associated with ext nw {} belonging to routerId {}",
531 networkId, routerName);
534 LOG.error("getExtNetworkVpnName : External Network VPN not found for router : {}", routerName);
538 public void updateNaptSwitchBucketStatus(String routerName, Uint32 routerId, Uint64 naptSwitch) {
539 LOG.debug("updateNaptSwitchBucketStatus : called");
541 List<Uint64> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
542 //List<BigInteger> dpnList = getDpnListForRouter(routerName);
543 if (dpnList.isEmpty()) {
544 LOG.warn("updateNaptSwitchBucketStatus : No switches found for router {}", routerName);
547 for (Uint64 dpn : dpnList) {
548 if (!dpn.equals(naptSwitch)) {
549 LOG.debug("updateNaptSwitchBucketStatus : Updating SNAT_TABLE missentry for DpnId {} "
550 + "which is not naptSwitch for router {}", dpn, routerName);
551 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, routerId, naptSwitch);
552 if (bucketInfoList.isEmpty()) {
553 LOG.error("Failed to populate bucketInfo for non-napt switch {} whose naptSwitch:{} for router:{}",
554 dpn,naptSwitch,routerName);
557 modifySnatGroupEntry(dpn, bucketInfoList, routerName);
558 externalRouterListener.installSnatMissEntry(dpn, bucketInfoList, routerName, routerId);
563 // TODO Clean up the exception handling
564 @SuppressWarnings("checkstyle:IllegalCatch")
565 private boolean handleNatFlowsInNewNaptSwitch(String routerName, Uint32 routerId, Uint64 oldNaptSwitch,
566 Uint64 newNaptSwitch, Uint32 routerVpnId, Uuid networkId) {
567 LOG.debug("handleNatFlowsInNewNaptSwitch : Proceeding to install flows in newNaptSwitch {} for routerId {}",
568 newNaptSwitch, routerId);
569 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
570 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
571 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
572 LOG.debug("handleNatFlowsInNewNaptSwitch : No Internal Ip Port mapping associated to router {},"
573 + "no flows need to be installed in newNaptSwitch {}", routerId, newNaptSwitch);
577 Uint32 vpnId = getVpnIdForRouter(routerId, networkId);
578 if (vpnId == NatConstants.INVALID_ID) {
579 LOG.error("handleNatFlowsInNewNaptSwitch : Invalid vpnId for routerId {}", routerId);
583 if (routerId.equals(routerVpnId)) {
584 bgpVpnId = NatConstants.INVALID_ID;
586 bgpVpnId = routerVpnId;
588 LOG.debug("handleNatFlowsInNewNaptSwitch : retrieved bgpVpnId {} for router {}", bgpVpnId, routerId);
589 // Get the External Gateway MAC Address
590 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
591 if (extGwMacAddress != null) {
592 LOG.debug("handleNatFlowsInNewNaptSwitch :External Gateway MAC address {} found for External Router ID {}",
593 extGwMacAddress, routerId);
595 LOG.error("handleNatFlowsInNewNaptSwitch : No External Gateway MAC address found for External Router ID {}",
599 for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType().values()) {
600 if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
601 LOG.debug("handleNatFlowsInNewNaptSwitch : No {} session associated to router {}",
602 protocolType.getProtocol(), routerId);
605 for (IpPortMap intIpPortMap : protocolType.getIpPortMap().values()) {
606 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
607 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
608 LOG.debug("handleNatFlowsInNewNaptSwitch : Found Internal IP Address {} and Port Number {}",
609 internalIpAddress, intportnum);
610 //Get the external IP address and the port from the model
611 NAPTEntryEvent.Protocol proto =
612 protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
613 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
614 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
615 internalIpAddress, intportnum, proto);
616 if (ipPortExternal == null) {
617 LOG.debug("handleNatFlowsInNewNaptSwitch : External Ipport mapping is not found for internalIp {} "
618 + "with port {}", internalIpAddress, intportnum);
621 String externalIpAddress = ipPortExternal.getIpAddress();
622 Integer extportNumber = ipPortExternal.getPortNum().toJava();
623 LOG.debug("handleNatFlowsInNewNaptSwitch : ExternalIPport {}:{} mapping for internal ipport {}:{}",
624 externalIpAddress, extportNumber, internalIpAddress, intportnum);
626 SessionAddress sourceAddress = new SessionAddress(internalIpAddress, Integer.parseInt(intportnum));
627 SessionAddress externalAddress = new SessionAddress(externalIpAddress, extportNumber);
629 //checking naptSwitch status before installing flows
630 if (NatUtil.getSwitchStatus(dataBroker, newNaptSwitch)) {
631 //Install the flow in newNaptSwitch Inbound NAPT table.
633 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.INBOUND_NAPT_TABLE,
634 vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto, extGwMacAddress);
635 } catch (RuntimeException ex) {
636 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in INBOUND_NAPT_TABLE for "
637 + "routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{} BgpVpnId {}",
638 routerId, newNaptSwitch, externalAddress, extportNumber, proto,
639 internalIpAddress, intportnum, bgpVpnId);
642 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
643 + "Inbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
644 newNaptSwitch, routerId, internalIpAddress,
645 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
646 //Install the flow in newNaptSwitch Outbound NAPT table.
648 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
649 vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto, extGwMacAddress);
650 } catch (RuntimeException ex) {
651 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in OUTBOUND_NAPT_TABLE for "
652 + "routerid {} dpnId {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
653 routerId, newNaptSwitch, internalIpAddress,
654 intportnum, proto, externalAddress, extportNumber, bgpVpnId, ex);
657 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
658 + "Outbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
659 newNaptSwitch, routerId, internalIpAddress,
660 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
662 LOG.error("handleNatFlowsInNewNaptSwitch : NewNaptSwitch {} gone down while installing flows "
663 + "from oldNaptswitch {}", newNaptSwitch, oldNaptSwitch);
671 // TODO Clean up the exception handling
672 @SuppressWarnings("checkstyle:IllegalCatch")
673 private Uint32 getVpnIdForRouter(Uint32 routerId, Uuid networkId) {
676 if (networkId == null) {
677 LOG.debug("getVpnIdForRouter : network is not associated to router {}", routerId);
679 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
680 if (vpnUuid == null) {
681 LOG.debug("getVpnIdForRouter : vpn is not associated for network {} in router {}",
682 networkId, routerId);
684 Uint32 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
685 if (vpnId.longValue() > 0) {
686 LOG.debug("getVpnIdForRouter : retrieved vpnId {} for router {}", vpnId, routerId);
689 LOG.debug("getVpnIdForRouter : retrieved invalid vpn Id");
693 } catch (Exception ex) {
694 LOG.error("getVpnIdForRouter : Exception while retrieving vpnId for router {}", routerId, ex);
696 return NatConstants.INVALID_ID;
700 public List<BucketInfo> handleGroupInNeighborSwitches(Uint64 dpnId, String routerName, Uint32 routerId,
702 List<BucketInfo> listBucketInfo = new ArrayList<>();
703 String ifNamePrimary;
704 if (routerId == NatConstants.INVALID_ID) {
705 LOG.error("handleGroupInNeighborSwitches : Invalid routerId returned for routerName {}", routerName);
706 return listBucketInfo;
708 ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
709 if (ifNamePrimary != null) {
710 LOG.debug("handleGroupInNeighborSwitches : TunnelInterface {} between ordinary switch {} and naptSwitch {}",
711 ifNamePrimary, dpnId, naptSwitch);
712 List<ActionInfo> listActionInfoPrimary =
713 NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager, interfaceManager,
714 ifNamePrimary, routerId, true);
715 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
716 listBucketInfo.add(bucketPrimary);
718 LOG.debug("handleGroupInNeighborSwitches : No TunnelInterface between ordinary switch {} and naptSwitch {}",
721 return listBucketInfo;
724 // TODO Clean up the exception handling
725 @SuppressWarnings("checkstyle:IllegalCatch")
726 protected void installSnatGroupEntry(Uint64 dpnId, List<BucketInfo> bucketInfo, String routerName) {
727 GroupEntity groupEntity = null;
729 Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
730 NatUtil.getGroupIdKey(routerName));
731 if (groupId != NatConstants.INVALID_ID) {
733 "installSnatGroupEntry : install SnatMissEntry for groupId {} for dpnId {} for router {}",
734 groupId, dpnId, routerName);
735 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId.longValue(), routerName,
736 GroupTypes.GroupAll, bucketInfo);
737 mdsalManager.syncInstallGroup(groupEntity);
738 LOG.debug("installSnatGroupEntry : installed the SNAT to NAPT GroupEntity:{}",
741 LOG.error("installSnatGroupEntry: Unable to obtain groupId for router:{}", routerName);
743 } catch (Exception ex) {
744 LOG.error("installSnatGroupEntry : Failed to install group for groupEntity {}", groupEntity, ex);
748 private void modifySnatGroupEntry(Uint64 dpnId, List<BucketInfo> bucketInfo, String routerName) {
749 installSnatGroupEntry(dpnId, bucketInfo, routerName);
750 LOG.debug("modifySnatGroupEntry : modified SnatMissEntry for dpnId {} of router {}", dpnId, routerName);
754 protected String getTunnelInterfaceName(Uint64 srcDpId, Uint64 dstDpId) {
755 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
756 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
759 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
760 new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId)
761 .setTunnelType(tunType).build());
762 rpcResult = result.get();
763 if (!rpcResult.isSuccessful()) {
764 tunType = TunnelTypeGre.class;
765 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
766 .setSourceDpid(srcDpId)
767 .setDestinationDpid(dstDpId)
768 .setTunnelType(tunType)
770 rpcResult = result.get();
771 if (!rpcResult.isSuccessful()) {
772 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
773 rpcResult.getErrors());
775 return rpcResult.getResult().getInterfaceName();
777 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
778 rpcResult.getErrors());
780 return rpcResult.getResult().getInterfaceName();
782 } catch (InterruptedException | ExecutionException e) {
783 LOG.error("getTunnelInterfaceName :Exception when getting tunnel interface Id for tunnel between {} and {}",
784 srcDpId, dstDpId, e);
786 LOG.error("getTunnelInterfaceName : Tunnel missing between dpn {}:{}", srcDpId, dstDpId);
790 // TODO Clean up the exception handling
791 @SuppressWarnings("checkstyle:IllegalCatch")
792 public boolean updateNaptSwitch(String routerName, Uint64 naptSwitchId) {
793 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
794 .setPrimarySwitchId(naptSwitchId).build();
796 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
797 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
798 } catch (Exception ex) {
799 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
800 naptSwitchId, routerName);
803 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
804 naptSwitchId, routerName);
808 public FlowEntity buildSnatFlowEntity(Uint64 dpId, String routerName, long groupId,
809 Uint32 routerVpnId, int addordel) {
810 FlowEntity flowEntity;
811 List<MatchInfo> matches = new ArrayList<>();
812 matches.add(MatchEthernetType.IPV4);
813 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId.longValue()),
814 MetaDataUtil.METADATA_MASK_VRFID));
816 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
818 if (addordel == NatConstants.ADD_FLOW) {
819 List<ActionInfo> actionsInfo = new ArrayList<>();
820 Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
821 idManager, routerVpnId, routerName);
822 actionsInfo.add(new ActionSetFieldTunnelId(tunnelId));
823 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
824 actionsInfo.add(new ActionGroup(groupId));
825 List<InstructionInfo> instructions = new ArrayList<>();
826 instructions.add(new InstructionApplyActions(actionsInfo));
828 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
829 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
830 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
832 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
833 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
834 NwConstants.COOKIE_SNAT_TABLE, matches, null);
839 public FlowEntity buildSnatFlowEntityForNaptSwitch(Uint64 dpId, String routerName,
840 Uint32 routerVpnId, int addordel) {
841 FlowEntity flowEntity;
842 List<MatchInfo> matches = new ArrayList<>();
843 matches.add(MatchEthernetType.IPV4);
844 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId.longValue()),
845 MetaDataUtil.METADATA_MASK_VRFID));
847 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
849 if (addordel == NatConstants.ADD_FLOW) {
850 List<InstructionInfo> instructions = new ArrayList<>();
852 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
854 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
855 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
856 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
858 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
859 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
860 NwConstants.COOKIE_SNAT_TABLE, matches, null);
865 private String getFlowRefSnat(Uint64 dpnId, short tableId, String routerID) {
866 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
867 .FLOWID_SEPARATOR + routerID;
870 protected void installSnatFlows(String routerName, Uint32 routerId, Uint64 naptSwitch, Uint32 routerVpnId,
871 Uuid networkId, String vpnName, TypedReadWriteTransaction<Configuration> confTx) {
873 if (routerId.equals(routerVpnId)) {
874 LOG.debug("installSnatFlows : Installing flows for router with internalvpnId");
875 //36 -> 46 ..Install flow forwarding packet to table46 from table36
876 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
877 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
878 externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName, routerId, confTx);
880 //Install default flows punting to controller in table 46(OutBoundNapt table)
881 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
882 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
883 externalRouterListener.createOutboundTblEntry(naptSwitch, routerId, confTx);
885 //Table 47 point to table 21 for inbound traffic
886 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {}",
887 naptSwitch, routerId);
888 externalRouterListener.installNaptPfibEntry(naptSwitch, routerId, confTx);
890 //Table 47 point to group
891 LOG.debug("installSnatFlows : installNaptPfibExternalOutputFlow in naptswitch with dpnId {} for router {}",
892 naptSwitch, routerId);
893 externalRouterListener.installNaptPfibExternalOutputFlow(routerName, routerId, naptSwitch, confTx);
895 Uuid extNetworkUuid = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
896 if (extNetworkUuid == null) {
897 LOG.error("onRouterAssociatedToVpn : Unable to retrieve external network Uuid for router {}",
901 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
903 if (extNwProvType == null) {
904 LOG.error("onRouterAssociatedToVpn : External Network Provider Type missing");
907 //36 -> 46 ..Install flow forwarding packet to table46 from table36
908 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
909 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
910 externalRouterListener
911 .installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerId,
912 routerVpnId, confTx, extNwProvType);
914 //Install default flows punting to controller in table 46(OutBoundNapt table)
915 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
916 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
917 externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
919 //Table 47 point to table 21 for inbound traffic
920 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {} "
921 + "with BgpVpnId {}", naptSwitch, routerId, routerVpnId);
922 externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
925 if (vpnName != null) {
926 //NAPT PFIB point to FIB table for outbound traffic
927 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
928 .instance.to.vpn.id.VpnInstance vpnInstance = NatUtil.getVpnIdToVpnInstance(dataBroker, vpnName);
929 if (vpnInstance == null) {
930 LOG.error("NAT Service : installNaptPfibEntry vpnInstance not found for {}", vpnName);
933 Uint32 vpnId = vpnInstance.getVpnId();
934 if (vpnName.equals(networkId.getValue())) {
935 // below condition valid only for flat/vlan use-case
936 boolean shouldInstallNaptPfibWithExtNetworkVpnId = true;
937 Collection<Uuid> externalSubnetIds = NatUtil
938 .getExternalSubnetIdsForRouter(dataBroker, routerName);
939 if (!externalSubnetIds.isEmpty()) {
940 //NAPT PFIB point to FIB table for outbound traffic - using external subnetID as vpnID.
941 for (Uuid externalSubnetId : externalSubnetIds) {
942 Uint32 externalSubnetVpnId = NatUtil
943 .getExternalSubnetVpnId(dataBroker, externalSubnetId);
944 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
945 shouldInstallNaptPfibWithExtNetworkVpnId = false;
947 "installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
948 + "BgpVpnId {}", naptSwitch, externalSubnetVpnId);
949 externalRouterListener
950 .installNaptPfibEntry(naptSwitch, externalSubnetVpnId, confTx);
954 if (vpnId != NatConstants.INVALID_ID && shouldInstallNaptPfibWithExtNetworkVpnId) {
955 //NAPT PFIB table point to FIB table for outbound traffic - using external networkID as vpnID.
957 "installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
958 + "BgpVpnId {}", naptSwitch, vpnId);
959 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId, confTx);
960 } else if (vpnId != NatConstants.INVALID_ID) {
961 LOG.debug("installSnatFlows : Associated BgpvpnId not found for router {}",
965 //Install Fib entries for ExternalIps & program 36 -> 44
966 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
967 String rd = vpnInstance.getVrfId();
968 for (String externalIp : externalIps) {
969 removeFibEntry(rd, externalIp);
970 LOG.debug("installSnatFlows : advToBgpAndInstallFibAndTsFlows in naptswitch id {} "
971 + "with vpnName {} and externalIp {}", naptSwitch, vpnName, externalIp);
972 externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
973 vpnName, routerId, routerName, externalIp, networkId, null /* external-router */, confTx);
974 LOG.debug("installSnatFlows : Successfully added fib entries in naptswitch {} for "
975 + "router {} with external IP {}", naptSwitch, routerId, externalIp);
978 LOG.debug("installSnatFlows : Associated vpnName not found for router {}", routerId);
982 protected void bestEffortDeletion(Uint32 routerId, String routerName, Map<String, Uint32> externalIpLabel,
983 TypedReadWriteTransaction<Configuration> confTx)
984 throws ExecutionException, InterruptedException {
985 Collection<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
986 if (externalIpsCache != null) {
987 Set<String> removedExternalIps = new HashSet<>(externalIpsCache);
988 removedExternalIps.removeAll(newExternalIps);
989 if (removedExternalIps.isEmpty()) {
990 LOG.info("bestEffortDeletion : No external Ip needed to be removed in bestEffortDeletion "
991 + "method for router {}", routerName);
994 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
995 String vpnName = getExtNetworkVpnName(routerName, networkId);
996 if (vpnName == null) {
997 LOG.error("bestEffortDeletion : Vpn is not associated to externalN/w of router {}", routerName);
1000 Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1001 if (naptSwitch == null || naptSwitch.equals(Uint64.ZERO)) {
1002 LOG.error("bestEffortDeletion : No naptSwitch is selected for router {}", routerName);
1005 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName, networkId);
1006 if (extNwProvType == null) {
1009 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
1010 if (gwMacAddress != null) {
1011 LOG.debug("bestEffortDeletion : External Gateway MAC address {} found for External Router ID {}",
1012 gwMacAddress, routerId);
1014 LOG.error("bestEffortDeletion : No External Gateway MAC address found for External Router ID {}",
1018 if (extNwProvType == ProviderTypes.VXLAN) {
1019 for (String externalIp : removedExternalIps) {
1020 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1021 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
1022 vpnName, networkId, NatConstants.DEFAULT_LABEL_VALUE, gwMacAddress, true, confTx);
1023 LOG.debug("bestEffortDeletion : Successfully removed fib entry for externalIp {} for routerId {} "
1024 + "on NAPT switch {} ", externalIp, routerId, naptSwitch);
1027 if (externalIpLabel == null || externalIpLabel.isEmpty()) {
1028 LOG.error("bestEffortDeletion : ExternalIpLabel map is empty for router {}", routerName);
1032 for (String externalIp : removedExternalIps) {
1033 if (externalIpLabel.containsKey(externalIp)) {
1034 label = externalIpLabel.get(externalIp);
1035 LOG.debug("bestEffortDeletion : Label {} for ExternalIp {} for router {}",
1036 label, externalIp, routerName);
1038 LOG.debug("bestEffortDeletion : Label for ExternalIp {} is not found for router {}",
1039 externalIp, routerName);
1042 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1043 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
1044 vpnName, networkId, label, gwMacAddress, true, confTx);
1045 LOG.debug("bestEffortDeletion : Successfully removed fib entries in switch {} for router {} "
1046 + "and externalIps {}", naptSwitch, routerId, externalIp);
1050 LOG.debug("bestEffortDeletion : No external IP found for router {}", routerId);
1054 private void removeFibEntry(String rd, String prefix) {
1055 InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
1056 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
1057 .child(VrfEntry.class, new VrfEntryKey(prefix));
1058 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
1059 Optional<VrfEntry> ent;
1061 ent = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1062 LogicalDatastoreType.CONFIGURATION, vrfEntryId);
1063 } catch (ExecutionException | InterruptedException e) {
1064 LOG.error("removeFibEntry: Exception while reading the VrfEntry for the prefix {} rd {}", prefix, rd, e);
1067 if (ent.isPresent()) {
1068 LOG.debug("removeFibEntry : Removing Fib entry rd {} prefix {}", rd, prefix);
1069 fibManager.removeFibEntry(rd, prefix, null, null);
1073 protected void subnetRegisterMapping(Routers routerEntry, Uint32 segmentId) {
1074 externalRouterListener.subnetRegisterMapping(routerEntry, segmentId);