2 * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.natservice.internal;
10 import com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.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.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
86 public class NaptSwitchHA {
87 private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
88 private final DataBroker dataBroker;
89 private final IMdsalApiManager mdsalManager;
90 private final ItmRpcService itmManager;
91 private final OdlInterfaceRpcService odlInterfaceRpcService;
92 private final IdManagerService idManager;
93 private final NAPTSwitchSelector naptSwitchSelector;
94 private final ExternalRoutersListener externalRouterListener;
95 private final NaptEventHandler naptEventHandler;
96 private final IFibManager fibManager;
97 private final IElanService elanManager;
98 private final EvpnNaptSwitchHA evpnNaptSwitchHA;
99 private final SnatServiceManager natServiceManager;
100 private final NatMode natMode;
101 private final IInterfaceManager interfaceManager;
102 private final NatOverVxlanUtil natOverVxlanUtil;
104 private volatile Collection<String> externalIpsCache;
107 public NaptSwitchHA(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
108 final ExternalRoutersListener externalRouterListener,
109 final ItmRpcService itmManager,
110 final OdlInterfaceRpcService odlInterfaceRpcService,
111 final IdManagerService idManager,
112 final NAPTSwitchSelector naptSwitchSelector,
113 final IFibManager fibManager,
114 final EvpnNaptSwitchHA evpnNaptSwitchHA,
115 final IElanService elanManager,
116 final SnatServiceManager natServiceManager,
117 final NatserviceConfig config,
118 final NaptEventHandler naptEventHandler,
119 final IInterfaceManager interfaceManager,
120 final NatOverVxlanUtil natOverVxlanUtil) {
121 this.dataBroker = dataBroker;
122 this.mdsalManager = mdsalManager;
123 this.externalRouterListener = externalRouterListener;
124 this.itmManager = itmManager;
125 this.odlInterfaceRpcService = odlInterfaceRpcService;
126 this.idManager = idManager;
127 this.naptSwitchSelector = naptSwitchSelector;
128 this.naptEventHandler = naptEventHandler;
129 this.fibManager = fibManager;
130 this.evpnNaptSwitchHA = evpnNaptSwitchHA;
131 this.elanManager = elanManager;
132 this.natServiceManager = natServiceManager;
133 this.interfaceManager = interfaceManager;
134 if (config != null) {
135 this.natMode = config.getNatMode();
137 this.natMode = NatMode.Controller;
139 this.natOverVxlanUtil = natOverVxlanUtil;
142 protected void removeSnatFlowsInOldNaptSwitch(String routerName, Long routerId, BigInteger naptSwitch,
143 @Nullable Map<String, Long> externalIpmap,
144 TypedReadWriteTransaction<Configuration> confTx)
145 throws ExecutionException, InterruptedException {
147 //remove SNAT flows in old NAPT SWITCH
148 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
149 String vpnName = getExtNetworkVpnName(routerName, networkId);
150 if (vpnName == null) {
151 LOG.error("removeSnatFlowsInOldNaptSwitch : Vpn is not associated to externalN/w of router {}",
155 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, networkId);
156 if (extNwProvType == null) {
157 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the External Network Provider Type "
158 + "for Router {}", routerName);
161 if (extNwProvType == ProviderTypes.VXLAN) {
162 evpnNaptSwitchHA.evpnRemoveSnatFlowsInOldNaptSwitch(routerName, routerId, vpnName, naptSwitch, confTx);
164 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
165 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
166 idManager, routerId, routerName);
167 String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
169 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
172 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
173 + "with the DPN ID {} and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
174 mdsalManager.removeFlow(confTx, tsNatFlowEntity);
176 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
177 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
178 NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, naptSwitch);
180 //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
181 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
182 NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
184 String outboundTcpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
185 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_TCP);
186 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
187 NwConstants.OUTBOUND_NAPT_TABLE, outboundTcpNatFlowRef);
188 mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
190 String outboundUdpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
191 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_UDP);
192 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
193 NwConstants.OUTBOUND_NAPT_TABLE, outboundUdpNatFlowRef);
194 mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
196 String icmpDropFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
197 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_ICMP);
198 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
200 mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
202 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
203 // External Subnet Vpn Id.
204 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
206 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
207 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
208 if (subnetVpnId != -1 && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
209 dataBroker, externalSubnetId, routerName, naptSwitch)) {
210 String natPfibSubnetFlowRef = externalRouterListener.getFlowRefTs(naptSwitch,
211 NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
212 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,
213 natPfibSubnetFlowRef);
214 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
215 LOG.debug("removeSnatFlowsInOldNaptSwitch : Removed the flow in table {} with external subnet "
216 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
217 subnetVpnId, naptSwitch);
221 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic
222 // matching on the router ID.
223 String naptPFibflowRef =
224 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
225 FlowEntity naptPFibFlowEntity =
226 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
227 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
228 + "with the DPN ID {} and router ID {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
229 mdsalManager.removeFlow(confTx, naptPFibFlowEntity);
231 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic
232 // matching on the vpn ID.
233 boolean switchSharedByRouters = false;
234 Uuid extNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
235 if (extNetworkId != null && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(
236 dataBroker, networkId, routerName, naptSwitch)) {
237 List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
238 for (String routerNameAssociated : routerNamesAssociated) {
239 if (!routerNameAssociated.equals(routerName)) {
240 Long routerIdAssociated = NatUtil.getVpnId(dataBroker, routerNameAssociated);
241 BigInteger naptDpn = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerNameAssociated);
242 if (naptDpn != null && naptDpn.equals(naptSwitch)) {
243 LOG.debug("removeSnatFlowsInOldNaptSwitch : Napt switch {} is also acting as primary "
244 + "for router {}", naptSwitch, routerIdAssociated);
245 switchSharedByRouters = true;
250 if (!switchSharedByRouters) {
251 Long vpnId = getVpnIdForRouter(routerId, extNetworkId);
252 if (vpnId != NatConstants.INVALID_ID) {
253 String naptFibflowRef =
254 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
255 FlowEntity naptFibFlowEntity =
256 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptFibflowRef);
257 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch"
258 + " with the DPN ID {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
259 mdsalManager.removeFlow(confTx, naptFibFlowEntity);
261 LOG.error("removeSnatFlowsInOldNaptSwitch : Invalid vpnId retrieved for routerId {}",
268 //Remove Fib entries,tables 20->44 ,36-> 44
269 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
270 if (externalIpmap != null && !externalIpmap.isEmpty()) {
271 for (Entry<String, Long> entry : externalIpmap.entrySet()) {
272 String externalIp = entry.getKey();
273 Long label = entry.getValue();
274 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp, vpnName,
275 extNetworkId, label, gwMacAddress, true, confTx);
276 LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} "
277 + "for router {} and externalIps {} label {}", naptSwitch, routerId, externalIp, label);
280 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
281 if (networkId != null) {
282 externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, networkId,
283 externalIps, null, gwMacAddress, confTx);
285 "removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} for "
286 + "router {} with networkId {} and externalIps {}", naptSwitch, routerId, networkId,
289 LOG.debug("removeSnatFlowsInOldNaptSwitch : External network not associated to router {}",
292 externalRouterListener.removeNaptFibExternalOutputFlows(routerId, naptSwitch, extNetworkId,
293 externalIps, confTx);
296 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
297 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
298 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
299 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
300 LOG.warn("removeSnatFlowsInOldNaptSwitch : No Internal Ip Port mapping associated to router {}, "
301 + "no flows need to be removed in oldNaptSwitch {}", routerId, naptSwitch);
304 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
305 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
306 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
307 if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
308 LOG.debug("removeSnatFlowsInOldNaptSwitch : No {} session associated to router {},"
309 + "no flows need to be removed in oldNaptSwitch {}",
310 intextIpProtocolType.getProtocol(), routerId, naptSwitch);
313 String protocol = intextIpProtocolType.getProtocol().name();
314 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
315 for (IpPortMap ipPortMap : ipPortMaps) {
316 String ipPortInternal = ipPortMap.getIpPortInternal();
317 String[] ipPortParts = ipPortInternal.split(":");
318 if (ipPortParts.length != 2) {
319 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the Internal IP and port");
322 String internalIp = ipPortParts[0];
323 String internalPort = ipPortParts[1];
325 //Build and remove flow in outbound NAPT table
326 String switchFlowRef =
327 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
328 internalIp, Integer.parseInt(internalPort), protocol);
329 FlowEntity outboundNaptFlowEntity =
330 NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
331 cookieSnatFlow, switchFlowRef);
333 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch "
334 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
335 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
337 //Build and remove flow in inbound NAPT table
339 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
340 internalIp, Integer.parseInt(internalPort), protocol);
341 FlowEntity inboundNaptFlowEntity =
342 NatUtil.buildFlowEntity(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
343 cookieSnatFlow, switchFlowRef);
346 "removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch with the "
347 + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, naptSwitch, routerId);
348 mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
354 private List<String> getRouterIdsForExtNetwork(Uuid extNetworkId) {
355 List<String> routerUuidsAsString = new ArrayList<>();
356 InstanceIdentifier<Networks> extNetwork = InstanceIdentifier.builder(ExternalNetworks.class)
357 .child(Networks.class, new NetworksKey(extNetworkId)).build();
358 Optional<Networks> extNetworkData =
359 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
360 LogicalDatastoreType.CONFIGURATION, extNetwork);
361 if (extNetworkData.isPresent()) {
362 List<Uuid> routerUuids = extNetworkData.get().getRouterIds();
363 if (routerUuids != null) {
364 for (Uuid routerUuid : routerUuids) {
365 routerUuidsAsString.add(routerUuid.getValue());
369 return routerUuidsAsString;
372 public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
373 Long routerVpnId, Collection<String> externalIpCache,
374 TypedReadWriteTransaction<Configuration> confTx)
375 throws ExecutionException, InterruptedException {
376 return isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId, externalIpCache, true,
380 // TODO Clean up the exception handling
381 @SuppressWarnings("checkstyle:IllegalCatch")
382 public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
383 Long routerVpnId, Collection<String> externalIpCache, boolean isClearBgpRts,
384 TypedReadWriteTransaction<Configuration> confTx)
385 throws ExecutionException, InterruptedException {
386 externalIpsCache = externalIpCache;
387 if (!naptSwitch.equals(dpnId)) {
388 LOG.debug("isNaptSwitchDown : DpnId {} is not a naptSwitch {} for Router {}",
389 dpnId, naptSwitch, routerName);
392 LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
393 if (routerId == NatConstants.INVALID_ID) {
394 LOG.error("isNaptSwitchDown : Invalid routerId returned for routerName {}", routerName);
397 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
398 String vpnName = getExtNetworkVpnName(routerName, networkId);
399 //elect a new NaptSwitch
400 naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
401 if (natMode == NatMode.Conntrack) {
402 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
403 natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
404 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_DISBL);
405 if (extRouters.isEnableSnat()) {
406 natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
407 SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
409 natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
410 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
411 if (extRouters.isEnableSnat()) {
412 natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
413 SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
416 if (naptSwitch.equals(BigInteger.ZERO)) {
417 LOG.warn("isNaptSwitchDown : No napt switch is elected since all the switches for router {}"
418 + " are down. SNAT IS NOT SUPPORTED FOR ROUTER {}", routerName, routerName);
419 boolean naptUpdatedStatus = updateNaptSwitch(routerName, naptSwitch);
420 if (!naptUpdatedStatus) {
421 LOG.debug("isNaptSwitchDown : Failed to update naptSwitch {} for router {} in ds",
422 naptSwitch, routerName);
425 if (externalIpsCache != null) {
426 if (vpnName != null) {
427 //List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
428 //if (externalIps != null) {
430 LOG.debug("isNaptSwitchDown : Clearing both FIB entries and the BGP routes");
431 for (String externalIp : externalIpsCache) {
432 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
435 LOG.debug("isNaptSwitchDown : Clearing the FIB entries but not the BGP routes");
436 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
437 for (String externalIp : externalIpsCache) {
438 LOG.debug("isNaptSwitchDown : Removing Fib entry rd {} prefix {}", rd, externalIp);
439 fibManager.removeFibEntry(rd, externalIp, null);
443 LOG.debug("isNaptSwitchDown : vpn is not associated to extn/w for router {}", routerName);
446 LOG.debug("isNaptSwitchDown : No ExternalIps found for subnets under router {}, "
447 + "no bgp routes need to be cleared", routerName);
451 //checking elected switch health status
452 if (!NatUtil.getSwitchStatus(dataBroker, naptSwitch)) {
453 LOG.error("isNaptSwitchDown : Newly elected Napt switch {} for router {} is down",
454 naptSwitch, routerName);
457 LOG.debug("isNaptSwitchDown : New NaptSwitch {} is up for Router {} and can proceed for flow installation",
458 naptSwitch, routerName);
459 //update napt model for new napt switch
460 boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
462 //update group of ordinary switch point to naptSwitch tunnel port
463 updateNaptSwitchBucketStatus(routerName, routerId, naptSwitch);
465 LOG.error("isNaptSwitchDown : Failed to update naptSwitch model for newNaptSwitch {} for router {}",
466 naptSwitch, routerName);
469 //update table26 forward packets to table46(outbound napt table)
470 FlowEntity flowEntity =
471 buildSnatFlowEntityForNaptSwitch(naptSwitch, routerName, routerVpnId, NatConstants.ADD_FLOW);
472 if (flowEntity == null) {
473 LOG.error("isNaptSwitchDown : Failed to populate flowentity for router {} in naptSwitch {}",
474 routerName, naptSwitch);
476 LOG.debug("isNaptSwitchDown : Successfully installed flow in naptSwitch {} for router {}",
477 naptSwitch, routerName);
478 mdsalManager.addFlow(confTx, flowEntity);
481 installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, confTx);
483 boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerName, routerId, dpnId, naptSwitch,
484 routerVpnId, networkId);
485 if (flowInstalledStatus) {
486 LOG.debug("isNaptSwitchDown :Installed all active session flows in newNaptSwitch {} for routerName {}",
487 naptSwitch, routerName);
489 LOG.error("isNaptSwitchDown : Failed to install flows in newNaptSwitch {} for routerId {}",
490 naptSwitch, routerId);
493 //remove group in new naptswitch, coz this switch acted previously as ordinary switch
494 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
496 LOG.info("isNaptSwitchDown : Removing NAPT Group in new naptSwitch {}", naptSwitch);
497 mdsalManager.removeGroup(confTx, naptSwitch, groupId);
498 } catch (Exception ex) {
499 LOG.error("isNaptSwitchDown : Failed to remove group in new naptSwitch {}", naptSwitch, ex);
506 private String getExtNetworkVpnName(String routerName, Uuid networkId) {
507 if (networkId == null) {
508 LOG.error("getExtNetworkVpnName : networkId is null for the router ID {}", routerName);
510 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
511 if (vpnName != null) {
512 LOG.debug("getExtNetworkVpnName : retrieved vpn name {} associated with ext nw {} in router {}",
513 vpnName, networkId, routerName);
516 LOG.error("getExtNetworkVpnName : No VPN associated with ext nw {} belonging to routerId {}",
517 networkId, routerName);
520 LOG.error("getExtNetworkVpnName : External Network VPN not found for router : {}", routerName);
524 public void updateNaptSwitchBucketStatus(String routerName, long routerId, BigInteger naptSwitch) {
525 LOG.debug("updateNaptSwitchBucketStatus : called");
527 List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
528 //List<BigInteger> dpnList = getDpnListForRouter(routerName);
529 if (dpnList.isEmpty()) {
530 LOG.warn("updateNaptSwitchBucketStatus : No switches found for router {}", routerName);
533 for (BigInteger dpn : dpnList) {
534 if (!dpn.equals(naptSwitch)) {
535 LOG.debug("updateNaptSwitchBucketStatus : Updating SNAT_TABLE missentry for DpnId {} "
536 + "which is not naptSwitch for router {}", dpn, routerName);
537 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, routerId, naptSwitch);
538 modifySnatGroupEntry(dpn, bucketInfoList, routerName);
543 // TODO Clean up the exception handling
544 @SuppressWarnings("checkstyle:IllegalCatch")
545 private boolean handleNatFlowsInNewNaptSwitch(String routerName, Long routerId, BigInteger oldNaptSwitch,
546 BigInteger newNaptSwitch, Long routerVpnId, Uuid networkId) {
547 LOG.debug("handleNatFlowsInNewNaptSwitch : Proceeding to install flows in newNaptSwitch {} for routerId {}",
548 newNaptSwitch, routerId);
549 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
550 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
551 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
552 LOG.debug("handleNatFlowsInNewNaptSwitch : No Internal Ip Port mapping associated to router {},"
553 + "no flows need to be installed in newNaptSwitch {}", routerId, newNaptSwitch);
557 Long vpnId = getVpnIdForRouter(routerId, networkId);
558 if (vpnId == NatConstants.INVALID_ID) {
559 LOG.error("handleNatFlowsInNewNaptSwitch : Invalid vpnId for routerId {}", routerId);
563 if (routerId.equals(routerVpnId)) {
564 bgpVpnId = NatConstants.INVALID_ID;
566 bgpVpnId = routerVpnId;
568 LOG.debug("handleNatFlowsInNewNaptSwitch : retrieved bgpVpnId {} for router {}", bgpVpnId, routerId);
569 // Get the External Gateway MAC Address
570 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
571 if (extGwMacAddress != null) {
572 LOG.debug("handleNatFlowsInNewNaptSwitch :External Gateway MAC address {} found for External Router ID {}",
573 extGwMacAddress, routerId);
575 LOG.error("handleNatFlowsInNewNaptSwitch : No External Gateway MAC address found for External Router ID {}",
579 for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
580 if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
581 LOG.debug("handleNatFlowsInNewNaptSwitch : No {} session associated to router {}",
582 protocolType.getProtocol(), routerId);
585 for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
586 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
587 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
588 LOG.debug("handleNatFlowsInNewNaptSwitch : Found Internal IP Address {} and Port Number {}",
589 internalIpAddress, intportnum);
590 //Get the external IP address and the port from the model
591 NAPTEntryEvent.Protocol proto =
592 protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
593 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
594 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
595 internalIpAddress, intportnum, proto);
596 if (ipPortExternal == null) {
597 LOG.debug("handleNatFlowsInNewNaptSwitch : External Ipport mapping is not found for internalIp {} "
598 + "with port {}", internalIpAddress, intportnum);
601 String externalIpAddress = ipPortExternal.getIpAddress();
602 Integer extportNumber = ipPortExternal.getPortNum();
603 LOG.debug("handleNatFlowsInNewNaptSwitch : ExternalIPport {}:{} mapping for internal ipport {}:{}",
604 externalIpAddress, extportNumber, internalIpAddress, intportnum);
606 SessionAddress sourceAddress = new SessionAddress(internalIpAddress, Integer.parseInt(intportnum));
607 SessionAddress externalAddress = new SessionAddress(externalIpAddress, extportNumber);
609 //checking naptSwitch status before installing flows
610 if (NatUtil.getSwitchStatus(dataBroker, newNaptSwitch)) {
611 //Install the flow in newNaptSwitch Inbound NAPT table.
613 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.INBOUND_NAPT_TABLE,
614 vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto, extGwMacAddress);
615 } catch (RuntimeException ex) {
616 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in INBOUND_NAPT_TABLE for "
617 + "routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{} BgpVpnId {}",
618 routerId, newNaptSwitch, externalAddress, extportNumber, proto,
619 internalIpAddress, intportnum, bgpVpnId);
622 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
623 + "Inbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
624 newNaptSwitch, routerId, internalIpAddress,
625 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
626 //Install the flow in newNaptSwitch Outbound NAPT table.
628 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
629 vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto, extGwMacAddress);
630 } catch (RuntimeException ex) {
631 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in OUTBOUND_NAPT_TABLE for "
632 + "routerid {} dpnId {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
633 routerId, newNaptSwitch, internalIpAddress,
634 intportnum, proto, externalAddress, extportNumber, bgpVpnId, ex);
637 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
638 + "Outbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
639 newNaptSwitch, routerId, internalIpAddress,
640 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
642 LOG.error("handleNatFlowsInNewNaptSwitch : NewNaptSwitch {} gone down while installing flows "
643 + "from oldNaptswitch {}", newNaptSwitch, oldNaptSwitch);
651 // TODO Clean up the exception handling
652 @SuppressWarnings("checkstyle:IllegalCatch")
653 private Long getVpnIdForRouter(Long routerId, Uuid networkId) {
656 if (networkId == null) {
657 LOG.debug("getVpnIdForRouter : network is not associated to router {}", routerId);
659 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
660 if (vpnUuid == null) {
661 LOG.debug("getVpnIdForRouter : vpn is not associated for network {} in router {}",
662 networkId, routerId);
664 Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
666 LOG.debug("getVpnIdForRouter : retrieved vpnId {} for router {}", vpnId, routerId);
669 LOG.debug("getVpnIdForRouter : retrieved invalid vpn Id");
673 } catch (Exception ex) {
674 LOG.error("getVpnIdForRouter : Exception while retrieving vpnId for router {}", routerId, ex);
676 return NatConstants.INVALID_ID;
680 public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, long routerId,
681 BigInteger naptSwitch) {
682 List<BucketInfo> listBucketInfo = new ArrayList<>();
683 String ifNamePrimary;
684 if (routerId == NatConstants.INVALID_ID) {
685 LOG.error("handleGroupInNeighborSwitches : Invalid routerId returned for routerName {}", routerName);
686 return listBucketInfo;
688 ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
689 if (ifNamePrimary != null) {
690 LOG.debug("handleGroupInNeighborSwitches : TunnelInterface {} between ordinary switch {} and naptSwitch {}",
691 ifNamePrimary, dpnId, naptSwitch);
692 List<ActionInfo> listActionInfoPrimary =
693 NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager, interfaceManager,
694 ifNamePrimary, routerId, true);
695 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
696 listBucketInfo.add(bucketPrimary);
698 LOG.debug("handleGroupInNeighborSwitches : No TunnelInterface between ordinary switch {} and naptSwitch {}",
701 return listBucketInfo;
704 // TODO Clean up the exception handling
705 @SuppressWarnings("checkstyle:IllegalCatch")
706 protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
707 GroupEntity groupEntity = null;
709 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
710 LOG.debug("installSnatGroupEntry : install SnatMissEntry for groupId {} for dpnId {} for router {}",
711 groupId, dpnId, routerName);
712 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
713 GroupTypes.GroupAll, bucketInfo);
714 mdsalManager.syncInstallGroup(groupEntity);
715 LOG.debug("installSnatGroupEntry : installed the SNAT to NAPT GroupEntity:{}", groupEntity);
716 } catch (Exception ex) {
717 LOG.error("installSnatGroupEntry : Failed to install group for groupEntity {}", groupEntity, ex);
721 private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
722 installSnatGroupEntry(dpnId, bucketInfo, routerName);
723 LOG.debug("modifySnatGroupEntry : modified SnatMissEntry for dpnId {} of router {}", dpnId, routerName);
727 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
728 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
729 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
732 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
733 new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId)
734 .setTunnelType(tunType).build());
735 rpcResult = result.get();
736 if (!rpcResult.isSuccessful()) {
737 tunType = TunnelTypeGre.class;
738 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
739 .setSourceDpid(srcDpId)
740 .setDestinationDpid(dstDpId)
741 .setTunnelType(tunType)
743 rpcResult = result.get();
744 if (!rpcResult.isSuccessful()) {
745 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
746 rpcResult.getErrors());
748 return rpcResult.getResult().getInterfaceName();
750 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
751 rpcResult.getErrors());
753 return rpcResult.getResult().getInterfaceName();
755 } catch (InterruptedException | ExecutionException e) {
756 LOG.error("getTunnelInterfaceName :Exception when getting tunnel interface Id for tunnel between {} and {}",
757 srcDpId, dstDpId, e);
759 LOG.error("getTunnelInterfaceName : Tunnel missing between dpn {}:{}", srcDpId, dstDpId);
763 // TODO Clean up the exception handling
764 @SuppressWarnings("checkstyle:IllegalCatch")
765 public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
766 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
767 .setPrimarySwitchId(naptSwitchId).build();
769 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
770 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
771 } catch (Exception ex) {
772 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
773 naptSwitchId, routerName);
776 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
777 naptSwitchId, routerName);
781 public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId,
782 long routerVpnId, int addordel) {
783 FlowEntity flowEntity;
784 List<MatchInfo> matches = new ArrayList<>();
785 matches.add(MatchEthernetType.IPV4);
786 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
788 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
790 if (addordel == NatConstants.ADD_FLOW) {
791 List<ActionInfo> actionsInfo = new ArrayList<>();
792 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
793 idManager, routerVpnId, routerName);
794 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
795 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
796 actionsInfo.add(new ActionGroup(groupId));
797 List<InstructionInfo> instructions = new ArrayList<>();
798 instructions.add(new InstructionApplyActions(actionsInfo));
800 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
801 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
802 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
804 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
805 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
806 NwConstants.COOKIE_SNAT_TABLE, matches, null);
811 public FlowEntity buildSnatFlowEntityForNaptSwitch(BigInteger dpId, String routerName,
812 long routerVpnId, int addordel) {
813 FlowEntity flowEntity;
814 List<MatchInfo> matches = new ArrayList<>();
815 matches.add(MatchEthernetType.IPV4);
816 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
818 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
820 if (addordel == NatConstants.ADD_FLOW) {
821 List<InstructionInfo> instructions = new ArrayList<>();
823 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
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 private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
837 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
838 .FLOWID_SEPARATOR + routerID;
841 protected void installSnatFlows(String routerName, Long routerId, BigInteger naptSwitch, Long routerVpnId,
842 TypedReadWriteTransaction<Configuration> confTx) {
844 if (routerId.equals(routerVpnId)) {
845 LOG.debug("installSnatFlows : Installing flows for router with internalvpnId");
846 //36 -> 46 ..Install flow forwarding packet to table46 from table36
847 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
848 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
849 externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName, routerId, confTx);
851 //Install default flows punting to controller in table 46(OutBoundNapt table)
852 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
853 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
854 externalRouterListener.createOutboundTblEntry(naptSwitch, routerId, confTx);
856 //Table 47 point to table 21 for inbound traffic
857 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {}",
858 naptSwitch, routerId);
859 externalRouterListener.installNaptPfibEntry(naptSwitch, routerId, confTx);
861 //Table 47 point to group
862 LOG.debug("installSnatFlows : installNaptPfibExternalOutputFlow in naptswitch with dpnId {} for router {}",
863 naptSwitch, routerId);
864 externalRouterListener.installNaptPfibExternalOutputFlow(routerName, routerId, naptSwitch, confTx);
866 Uuid extNetworkUuid = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
867 if (extNetworkUuid == null) {
868 LOG.error("onRouterAssociatedToVpn : Unable to retrieve external network Uuid for router {}",
872 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
874 if (extNwProvType == null) {
875 LOG.error("onRouterAssociatedToVpn : External Network Provider Type missing");
878 //36 -> 46 ..Install flow forwarding packet to table46 from table36
879 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
880 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
881 externalRouterListener
882 .installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerId,
883 routerVpnId, confTx, extNwProvType);
885 //Install default flows punting to controller in table 46(OutBoundNapt table)
886 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
887 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
888 externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
890 //Table 47 point to table 21 for inbound traffic
891 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {} "
892 + "with BgpVpnId {}", naptSwitch, routerId, routerVpnId);
893 externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
896 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
897 String vpnName = getExtNetworkVpnName(routerName, networkId);
898 if (vpnName != null) {
899 //NAPT PFIB point to FIB table for outbound traffic
900 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
901 boolean shouldInstallNaptPfibWithExtNetworkVpnId = true;
902 Collection<Uuid> externalSubnetIds = NatUtil.getExternalSubnetIdsForRouter(dataBroker, routerName);
903 if (!externalSubnetIds.isEmpty()) {
904 //NAPT PFIB point to FIB table for outbound traffic - using external subnetID as vpnID.
905 for (Uuid externalSubnetId : externalSubnetIds) {
906 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, externalSubnetId);
907 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
908 shouldInstallNaptPfibWithExtNetworkVpnId = false;
909 LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
910 + "BgpVpnId {}", naptSwitch, externalSubnetVpnId);
911 externalRouterListener.installNaptPfibEntry(naptSwitch, externalSubnetVpnId, confTx);
915 if (vpnId != NatConstants.INVALID_ID && shouldInstallNaptPfibWithExtNetworkVpnId) {
916 //NAPT PFIB table point to FIB table for outbound traffic - using external networkID as vpnID.
917 LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
918 + "BgpVpnId {}", naptSwitch, vpnId);
919 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId, confTx);
920 } else if (vpnId != NatConstants.INVALID_ID) {
921 LOG.debug("installSnatFlows : Associated BgpvpnId not found for router {}", routerId);
924 //Install Fib entries for ExternalIps & program 36 -> 44
925 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
926 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
927 for (String externalIp : externalIps) {
928 removeFibEntry(rd, externalIp);
929 LOG.debug("installSnatFlows : advToBgpAndInstallFibAndTsFlows in naptswitch id {} "
930 + "with vpnName {} and externalIp {}", naptSwitch, vpnName, externalIp);
931 externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
932 vpnName, routerId, routerName, externalIp, networkId, null /* external-router */, confTx);
933 LOG.debug("installSnatFlows : Successfully added fib entries in naptswitch {} for "
934 + "router {} with external IP {}", naptSwitch, routerId, externalIp);
937 LOG.debug("installSnatFlows : Associated vpnName not found for router {}", routerId);
941 protected void bestEffortDeletion(long routerId, String routerName, Map<String, Long> externalIpLabel,
942 TypedReadWriteTransaction<Configuration> confTx)
943 throws ExecutionException, InterruptedException {
944 Collection<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
945 if (externalIpsCache != null) {
946 Set<String> removedExternalIps = new HashSet<>(externalIpsCache);
947 removedExternalIps.removeAll(newExternalIps);
948 if (removedExternalIps.isEmpty()) {
949 LOG.info("bestEffortDeletion : No external Ip needed to be removed in bestEffortDeletion "
950 + "method for router {}", routerName);
953 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
954 String vpnName = getExtNetworkVpnName(routerName, networkId);
955 if (vpnName == null) {
956 LOG.error("bestEffortDeletion : Vpn is not associated to externalN/w of router {}", routerName);
959 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
960 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
961 LOG.error("bestEffortDeletion : No naptSwitch is selected for router {}", routerName);
964 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName, networkId);
965 if (extNwProvType == null) {
968 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
969 if (gwMacAddress != null) {
970 LOG.debug("bestEffortDeletion : External Gateway MAC address {} found for External Router ID {}",
971 gwMacAddress, routerId);
973 LOG.error("bestEffortDeletion : No External Gateway MAC address found for External Router ID {}",
977 if (extNwProvType == ProviderTypes.VXLAN) {
978 for (String externalIp : removedExternalIps) {
979 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
980 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
981 vpnName, networkId, NatConstants.DEFAULT_LABEL_VALUE, gwMacAddress, true, confTx);
982 LOG.debug("bestEffortDeletion : Successfully removed fib entry for externalIp {} for routerId {} "
983 + "on NAPT switch {} ", externalIp, routerId, naptSwitch);
986 if (externalIpLabel == null || externalIpLabel.isEmpty()) {
987 LOG.error("bestEffortDeletion : ExternalIpLabel map is empty for router {}", routerName);
991 for (String externalIp : removedExternalIps) {
992 if (externalIpLabel.containsKey(externalIp)) {
993 label = externalIpLabel.get(externalIp);
994 LOG.debug("bestEffortDeletion : Label {} for ExternalIp {} for router {}",
995 label, externalIp, routerName);
997 LOG.debug("bestEffortDeletion : Label for ExternalIp {} is not found for router {}",
998 externalIp, routerName);
1001 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1002 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
1003 vpnName, networkId, label, gwMacAddress, true, confTx);
1004 LOG.debug("bestEffortDeletion : Successfully removed fib entries in switch {} for router {} "
1005 + "and externalIps {}", naptSwitch, routerId, externalIp);
1009 LOG.debug("bestEffortDeletion : No external IP found for router {}", routerId);
1013 private void removeFibEntry(String rd, String prefix) {
1014 InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
1015 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
1016 .child(VrfEntry.class, new VrfEntryKey(prefix));
1017 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
1018 Optional<VrfEntry> ent = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
1019 if (ent.isPresent()) {
1020 LOG.debug("removeFibEntry : Removing Fib entry rd {} prefix {}", rd, prefix);
1021 fibManager.removeFibEntry(rd, prefix, null);
1025 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
1026 externalRouterListener.subnetRegisterMapping(routerEntry, segmentId);