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.annotation.Nonnull;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
27 import org.opendaylight.genius.infra.Datastore.Configuration;
28 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
29 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
30 import org.opendaylight.genius.mdsalutil.ActionInfo;
31 import org.opendaylight.genius.mdsalutil.BucketInfo;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
33 import org.opendaylight.genius.mdsalutil.GroupEntity;
34 import org.opendaylight.genius.mdsalutil.InstructionInfo;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.mdsalutil.MatchInfo;
37 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
38 import org.opendaylight.genius.mdsalutil.NwConstants;
39 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
40 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
41 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
46 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
47 import org.opendaylight.netvirt.elanmanager.api.IElanService;
48 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
49 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.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;
103 private volatile Collection<String> externalIpsCache;
106 public NaptSwitchHA(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
107 final ExternalRoutersListener externalRouterListener,
108 final ItmRpcService itmManager,
109 final OdlInterfaceRpcService odlInterfaceRpcService,
110 final IdManagerService idManager,
111 final NAPTSwitchSelector naptSwitchSelector,
112 final IFibManager fibManager,
113 final EvpnNaptSwitchHA evpnNaptSwitchHA,
114 final IElanService elanManager,
115 final SnatServiceManager natServiceManager,
116 final NatserviceConfig config,
117 final NaptEventHandler naptEventHandler,
118 final IInterfaceManager interfaceManager) {
119 this.dataBroker = dataBroker;
120 this.mdsalManager = mdsalManager;
121 this.externalRouterListener = externalRouterListener;
122 this.itmManager = itmManager;
123 this.odlInterfaceRpcService = odlInterfaceRpcService;
124 this.idManager = idManager;
125 this.naptSwitchSelector = naptSwitchSelector;
126 this.naptEventHandler = naptEventHandler;
127 this.fibManager = fibManager;
128 this.evpnNaptSwitchHA = evpnNaptSwitchHA;
129 this.elanManager = elanManager;
130 this.natServiceManager = natServiceManager;
131 this.interfaceManager = interfaceManager;
132 if (config != null) {
133 this.natMode = config.getNatMode();
135 this.natMode = NatMode.Controller;
139 protected void removeSnatFlowsInOldNaptSwitch(String routerName, Long routerId, BigInteger naptSwitch,
140 Map<String, Long> externalIpmap,
141 TypedReadWriteTransaction<Configuration> confTx)
142 throws ExecutionException, InterruptedException {
144 //remove SNAT flows in old NAPT SWITCH
145 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
146 String vpnName = getExtNetworkVpnName(routerName, networkId);
147 if (vpnName == null) {
148 LOG.error("removeSnatFlowsInOldNaptSwitch : Vpn is not associated to externalN/w of router {}",
152 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, networkId);
153 if (extNwProvType == null) {
154 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the External Network Provider Type "
155 + "for Router {}", routerName);
158 if (extNwProvType == ProviderTypes.VXLAN) {
159 evpnNaptSwitchHA.evpnRemoveSnatFlowsInOldNaptSwitch(routerName, routerId, vpnName, naptSwitch, confTx);
161 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
162 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
164 String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
166 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
169 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
170 + "with the DPN ID {} and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
171 mdsalManager.removeFlow(confTx, tsNatFlowEntity);
173 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
174 //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
175 NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, naptSwitch);
177 //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
178 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
179 NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
181 String outboundTcpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
182 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_TCP);
183 FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
184 NwConstants.OUTBOUND_NAPT_TABLE, outboundTcpNatFlowRef);
185 mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
187 String outboundUdpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
188 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_UDP);
189 FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
190 NwConstants.OUTBOUND_NAPT_TABLE, outboundUdpNatFlowRef);
191 mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
193 String icmpDropFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
194 NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_ICMP);
195 FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
197 mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
199 //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
200 // External Subnet Vpn Id.
201 Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
203 for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
204 long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
205 if (subnetVpnId != -1 && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
206 dataBroker, externalSubnetId, routerName, naptSwitch)) {
207 String natPfibSubnetFlowRef = externalRouterListener.getFlowRefTs(naptSwitch,
208 NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
209 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,
210 natPfibSubnetFlowRef);
211 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
212 LOG.debug("removeSnatFlowsInOldNaptSwitch : Removed the flow in table {} with external subnet "
213 + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
214 subnetVpnId, naptSwitch);
218 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic
219 // matching on the router ID.
220 String naptPFibflowRef =
221 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
222 FlowEntity naptPFibFlowEntity =
223 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
224 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
225 + "with the DPN ID {} and router ID {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
226 mdsalManager.removeFlow(confTx, naptPFibFlowEntity);
228 // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic
229 // matching on the vpn ID.
230 boolean switchSharedByRouters = false;
231 Uuid extNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
232 if (extNetworkId != null && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(
233 dataBroker, networkId, routerName, naptSwitch)) {
234 List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
235 for (String routerNameAssociated : routerNamesAssociated) {
236 if (!routerNameAssociated.equals(routerName)) {
237 Long routerIdAssociated = NatUtil.getVpnId(dataBroker, routerNameAssociated);
238 BigInteger naptDpn = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerNameAssociated);
239 if (naptDpn != null && naptDpn.equals(naptSwitch)) {
240 LOG.debug("removeSnatFlowsInOldNaptSwitch : Napt switch {} is also acting as primary "
241 + "for router {}", naptSwitch, routerIdAssociated);
242 switchSharedByRouters = true;
247 if (!switchSharedByRouters) {
248 Long vpnId = getVpnIdForRouter(routerId, extNetworkId);
249 if (vpnId != NatConstants.INVALID_ID) {
250 String naptFibflowRef =
251 externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
252 FlowEntity naptFibFlowEntity =
253 NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptFibflowRef);
254 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch"
255 + " with the DPN ID {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
256 mdsalManager.removeFlow(confTx, naptFibFlowEntity);
258 LOG.error("removeSnatFlowsInOldNaptSwitch : Invalid vpnId retrieved for routerId {}",
265 //Remove Fib entries,tables 20->44 ,36-> 44
266 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
267 if (externalIpmap != null && !externalIpmap.isEmpty()) {
268 for (Entry<String, Long> entry : externalIpmap.entrySet()) {
269 String externalIp = entry.getKey();
270 Long label = entry.getValue();
271 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
272 extNetworkId, label, gwMacAddress, true, confTx);
273 LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} "
274 + "for router {} and externalIps {} label {}", naptSwitch, routerId, externalIp, label);
277 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
278 if (networkId != null) {
279 externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, networkId,
280 externalIps, null, gwMacAddress, confTx);
282 "removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} for "
283 + "router {} with networkId {} and externalIps {}", naptSwitch, routerId, networkId,
286 LOG.debug("removeSnatFlowsInOldNaptSwitch : External network not associated to router {}",
289 externalRouterListener.removeNaptFibExternalOutputFlows(routerId, naptSwitch, extNetworkId,
290 externalIps, confTx);
293 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
294 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
295 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
296 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
297 LOG.warn("removeSnatFlowsInOldNaptSwitch : No Internal Ip Port mapping associated to router {}, "
298 + "no flows need to be removed in oldNaptSwitch {}", routerId, naptSwitch);
301 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
302 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
303 for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
304 if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
305 LOG.debug("removeSnatFlowsInOldNaptSwitch : No {} session associated to router {},"
306 + "no flows need to be removed in oldNaptSwitch {}",
307 intextIpProtocolType.getProtocol(), routerId, naptSwitch);
310 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
311 for (IpPortMap ipPortMap : ipPortMaps) {
312 String ipPortInternal = ipPortMap.getIpPortInternal();
313 String[] ipPortParts = ipPortInternal.split(":");
314 if (ipPortParts.length != 2) {
315 LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the Internal IP and port");
318 String internalIp = ipPortParts[0];
319 String internalPort = ipPortParts[1];
321 //Build and remove flow in outbound NAPT table
322 String switchFlowRef =
323 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
324 internalIp, Integer.parseInt(internalPort));
325 FlowEntity outboundNaptFlowEntity =
326 NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
327 cookieSnatFlow, switchFlowRef);
329 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch "
330 + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
331 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
333 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
334 if (ipPortExternal == null) {
336 "removeSnatFlowsInOldNaptSwitch : External Ipport mapping not found for internalIp {} "
337 + "with port {} for router {}", internalIp, internalPort, routerId);
340 String externalIp = ipPortExternal.getIpAddress();
341 int externalPort = ipPortExternal.getPortNum();
343 //Build and remove flow in inbound NAPT table
345 NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
346 externalIp, externalPort);
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(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
379 Long routerVpnId, Collection<String> externalIpCache,
380 TypedReadWriteTransaction<Configuration> confTx)
381 throws ExecutionException, InterruptedException {
382 return isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId, externalIpCache, true,
386 // TODO Clean up the exception handling
387 @SuppressWarnings("checkstyle:IllegalCatch")
388 public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
389 Long routerVpnId, Collection<String> externalIpCache, boolean isClearBgpRts,
390 TypedReadWriteTransaction<Configuration> confTx)
391 throws ExecutionException, InterruptedException {
392 externalIpsCache = externalIpCache;
393 if (!naptSwitch.equals(dpnId)) {
394 LOG.debug("isNaptSwitchDown : DpnId {} is not a naptSwitch {} for Router {}",
395 dpnId, naptSwitch, routerName);
398 LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
399 if (routerId == NatConstants.INVALID_ID) {
400 LOG.error("isNaptSwitchDown : Invalid routerId returned for routerName {}", routerName);
403 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
404 String vpnName = getExtNetworkVpnName(routerName, networkId);
405 //elect a new NaptSwitch
406 naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
407 if (natMode == NatMode.Conntrack) {
408 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
409 natServiceManager.notify(confTx, extRouters, dpnId, dpnId, SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
410 natServiceManager.notify(confTx, extRouters, naptSwitch, naptSwitch,
411 SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
413 if (naptSwitch.equals(BigInteger.ZERO)) {
414 LOG.warn("isNaptSwitchDown : No napt switch is elected since all the switches for router {}"
415 + " are down. SNAT IS NOT SUPPORTED FOR ROUTER {}", routerName, routerName);
416 boolean naptUpdatedStatus = updateNaptSwitch(routerName, naptSwitch);
417 if (!naptUpdatedStatus) {
418 LOG.debug("isNaptSwitchDown : Failed to update naptSwitch {} for router {} in ds",
419 naptSwitch, routerName);
422 if (externalIpsCache != null) {
423 if (vpnName != null) {
424 //List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
425 //if (externalIps != null) {
427 LOG.debug("isNaptSwitchDown : Clearing both FIB entries and the BGP routes");
428 for (String externalIp : externalIpsCache) {
429 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
432 LOG.debug("isNaptSwitchDown : Clearing the FIB entries but not the BGP routes");
433 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
434 for (String externalIp : externalIpsCache) {
435 LOG.debug("isNaptSwitchDown : Removing Fib entry rd {} prefix {}", rd, externalIp);
436 fibManager.removeFibEntry(rd, externalIp, null);
440 LOG.debug("isNaptSwitchDown : vpn is not associated to extn/w for router {}", routerName);
443 LOG.debug("isNaptSwitchDown : No ExternalIps found for subnets under router {}, "
444 + "no bgp routes need to be cleared", routerName);
448 //checking elected switch health status
449 if (!NatUtil.getSwitchStatus(dataBroker, naptSwitch)) {
450 LOG.error("isNaptSwitchDown : Newly elected Napt switch {} for router {} is down",
451 naptSwitch, routerName);
454 LOG.debug("isNaptSwitchDown : New NaptSwitch {} is up for Router {} and can proceed for flow installation",
455 naptSwitch, routerName);
456 //update napt model for new napt switch
457 boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
459 //update group of ordinary switch point to naptSwitch tunnel port
460 updateNaptSwitchBucketStatus(routerName, routerId, naptSwitch);
462 LOG.error("isNaptSwitchDown : Failed to update naptSwitch model for newNaptSwitch {} for router {}",
463 naptSwitch, routerName);
466 //update table26 forward packets to table46(outbound napt table)
467 FlowEntity flowEntity =
468 buildSnatFlowEntityForNaptSwitch(naptSwitch, routerName, routerVpnId, NatConstants.ADD_FLOW);
469 if (flowEntity == null) {
470 LOG.error("isNaptSwitchDown : Failed to populate flowentity for router {} in naptSwitch {}",
471 routerName, naptSwitch);
473 LOG.debug("isNaptSwitchDown : Successfully installed flow in naptSwitch {} for router {}",
474 naptSwitch, routerName);
475 mdsalManager.addFlow(confTx, flowEntity);
478 installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, confTx);
480 boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerName, routerId, dpnId, naptSwitch,
481 routerVpnId, networkId);
482 if (flowInstalledStatus) {
483 LOG.debug("isNaptSwitchDown :Installed all active session flows in newNaptSwitch {} for routerName {}",
484 naptSwitch, routerName);
486 LOG.error("isNaptSwitchDown : Failed to install flows in newNaptSwitch {} for routerId {}",
487 naptSwitch, routerId);
490 //remove group in new naptswitch, coz this switch acted previously as ordinary switch
491 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
493 LOG.info("isNaptSwitchDown : Removing NAPT Group in new naptSwitch {}", naptSwitch);
494 mdsalManager.removeGroup(confTx, naptSwitch, groupId);
495 } catch (Exception ex) {
496 LOG.error("isNaptSwitchDown : Failed to remove group in new naptSwitch {}", naptSwitch, ex);
502 private String getExtNetworkVpnName(String routerName, Uuid networkId) {
503 if (networkId == null) {
504 LOG.error("getExtNetworkVpnName : networkId is null for the router ID {}", routerName);
506 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
507 if (vpnName != null) {
508 LOG.debug("getExtNetworkVpnName : retrieved vpn name {} associated with ext nw {} in router {}",
509 vpnName, networkId, routerName);
512 LOG.error("getExtNetworkVpnName : No VPN associated with ext nw {} belonging to routerId {}",
513 networkId, routerName);
516 LOG.error("getExtNetworkVpnName : External Network VPN not found for router : {}", routerName);
520 public void updateNaptSwitchBucketStatus(String routerName, long routerId, BigInteger naptSwitch) {
521 LOG.debug("updateNaptSwitchBucketStatus : called");
523 List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
524 //List<BigInteger> dpnList = getDpnListForRouter(routerName);
525 if (dpnList.isEmpty()) {
526 LOG.warn("updateNaptSwitchBucketStatus : No switches found for router {}", routerName);
529 for (BigInteger dpn : dpnList) {
530 if (!dpn.equals(naptSwitch)) {
531 LOG.debug("updateNaptSwitchBucketStatus : Updating SNAT_TABLE missentry for DpnId {} "
532 + "which is not naptSwitch for router {}", dpn, routerName);
533 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, routerId, naptSwitch);
534 modifySnatGroupEntry(dpn, bucketInfoList, routerName);
539 // TODO Clean up the exception handling
540 @SuppressWarnings("checkstyle:IllegalCatch")
541 private boolean handleNatFlowsInNewNaptSwitch(String routerName, Long routerId, BigInteger oldNaptSwitch,
542 BigInteger newNaptSwitch, Long routerVpnId, Uuid networkId) {
543 LOG.debug("handleNatFlowsInNewNaptSwitch : Proceeding to install flows in newNaptSwitch {} for routerId {}",
544 newNaptSwitch, routerId);
545 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
546 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
547 || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
548 LOG.debug("handleNatFlowsInNewNaptSwitch : No Internal Ip Port mapping associated to router {},"
549 + "no flows need to be installed in newNaptSwitch {}", routerId, newNaptSwitch);
553 Long vpnId = getVpnIdForRouter(routerId, networkId);
554 if (vpnId == NatConstants.INVALID_ID) {
555 LOG.error("handleNatFlowsInNewNaptSwitch : Invalid vpnId for routerId {}", routerId);
559 if (routerId.equals(routerVpnId)) {
560 bgpVpnId = NatConstants.INVALID_ID;
562 bgpVpnId = routerVpnId;
564 LOG.debug("handleNatFlowsInNewNaptSwitch : retrieved bgpVpnId {} for router {}", bgpVpnId, routerId);
565 // Get the External Gateway MAC Address
566 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
567 if (extGwMacAddress != null) {
568 LOG.debug("handleNatFlowsInNewNaptSwitch :External Gateway MAC address {} found for External Router ID {}",
569 extGwMacAddress, routerId);
571 LOG.error("handleNatFlowsInNewNaptSwitch : No External Gateway MAC address found for External Router ID {}",
575 for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
576 if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
577 LOG.debug("handleNatFlowsInNewNaptSwitch : No {} session associated to router {}",
578 protocolType.getProtocol(), routerId);
581 for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
582 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
583 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
584 LOG.debug("handleNatFlowsInNewNaptSwitch : Found Internal IP Address {} and Port Number {}",
585 internalIpAddress, intportnum);
586 //Get the external IP address and the port from the model
587 NAPTEntryEvent.Protocol proto =
588 protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
589 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
590 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
591 internalIpAddress, intportnum, proto);
592 if (ipPortExternal == null) {
593 LOG.debug("handleNatFlowsInNewNaptSwitch : External Ipport mapping is not found for internalIp {} "
594 + "with port {}", internalIpAddress, intportnum);
597 String externalIpAddress = ipPortExternal.getIpAddress();
598 Integer extportNumber = ipPortExternal.getPortNum();
599 LOG.debug("handleNatFlowsInNewNaptSwitch : ExternalIPport {}:{} mapping for internal ipport {}:{}",
600 externalIpAddress, extportNumber, internalIpAddress, intportnum);
602 SessionAddress sourceAddress = new SessionAddress(internalIpAddress, Integer.parseInt(intportnum));
603 SessionAddress externalAddress = new SessionAddress(externalIpAddress, extportNumber);
605 //checking naptSwitch status before installing flows
606 if (NatUtil.getSwitchStatus(dataBroker, newNaptSwitch)) {
607 //Install the flow in newNaptSwitch Inbound NAPT table.
609 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.INBOUND_NAPT_TABLE,
610 vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto, extGwMacAddress);
611 } catch (RuntimeException ex) {
612 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in INBOUND_NAPT_TABLE for "
613 + "routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{} BgpVpnId {}",
614 routerId, newNaptSwitch, externalAddress, extportNumber, proto,
615 internalIpAddress, intportnum, bgpVpnId);
618 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
619 + "Inbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
620 newNaptSwitch, routerId, internalIpAddress,
621 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
622 //Install the flow in newNaptSwitch Outbound NAPT table.
624 naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
625 vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto, extGwMacAddress);
626 } catch (RuntimeException ex) {
627 LOG.error("handleNatFlowsInNewNaptSwitch : Failed to add flow in OUTBOUND_NAPT_TABLE for "
628 + "routerid {} dpnId {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
629 routerId, newNaptSwitch, internalIpAddress,
630 intportnum, proto, externalAddress, extportNumber, bgpVpnId, ex);
633 LOG.debug("handleNatFlowsInNewNaptSwitch : Successfully installed a flow in Primary switch {} "
634 + "Outbound NAPT table for router {} ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
635 newNaptSwitch, routerId, internalIpAddress,
636 intportnum, proto, externalAddress, extportNumber, bgpVpnId);
638 LOG.error("handleNatFlowsInNewNaptSwitch : NewNaptSwitch {} gone down while installing flows "
639 + "from oldNaptswitch {}", newNaptSwitch, oldNaptSwitch);
647 // TODO Clean up the exception handling
648 @SuppressWarnings("checkstyle:IllegalCatch")
649 private Long getVpnIdForRouter(Long routerId, Uuid networkId) {
652 if (networkId == null) {
653 LOG.debug("getVpnIdForRouter : network is not associated to router {}", routerId);
655 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
656 if (vpnUuid == null) {
657 LOG.debug("getVpnIdForRouter : vpn is not associated for network {} in router {}",
658 networkId, routerId);
660 Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
662 LOG.debug("getVpnIdForRouter : retrieved vpnId {} for router {}", vpnId, routerId);
665 LOG.debug("getVpnIdForRouter : retrieved invalid vpn Id");
669 } catch (Exception ex) {
670 LOG.error("getVpnIdForRouter : Exception while retrieving vpnId for router {}", routerId, ex);
672 return NatConstants.INVALID_ID;
675 public List<BucketInfo> handleGroupInPrimarySwitch() {
676 List<BucketInfo> listBucketInfo = new ArrayList<>();
677 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
678 listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
679 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
680 listBucketInfo.add(bucketPrimary);
681 return listBucketInfo;
685 public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, long routerId,
686 BigInteger naptSwitch) {
687 List<BucketInfo> listBucketInfo = new ArrayList<>();
688 String ifNamePrimary;
689 if (routerId == NatConstants.INVALID_ID) {
690 LOG.error("handleGroupInNeighborSwitches : Invalid routerId returned for routerName {}", routerName);
691 return listBucketInfo;
693 ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
694 if (ifNamePrimary != null) {
695 LOG.debug("handleGroupInNeighborSwitches : TunnelInterface {} between ordinary switch {} and naptSwitch {}",
696 ifNamePrimary, dpnId, naptSwitch);
697 List<ActionInfo> listActionInfoPrimary =
698 NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager, interfaceManager,
699 ifNamePrimary, routerId, true);
700 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
701 listBucketInfo.add(bucketPrimary);
703 LOG.debug("handleGroupInNeighborSwitches : No TunnelInterface between ordinary switch {} and naptSwitch {}",
706 return listBucketInfo;
709 // TODO Clean up the exception handling
710 @SuppressWarnings("checkstyle:IllegalCatch")
711 protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
712 GroupEntity groupEntity = null;
714 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
715 LOG.debug("installSnatGroupEntry : install SnatMissEntry for groupId {} for dpnId {} for router {}",
716 groupId, dpnId, routerName);
717 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
718 GroupTypes.GroupAll, bucketInfo);
719 mdsalManager.syncInstallGroup(groupEntity);
720 LOG.debug("installSnatGroupEntry : installed the SNAT to NAPT GroupEntity:{}", groupEntity);
721 } catch (Exception ex) {
722 LOG.error("installSnatGroupEntry : Failed to install group for groupEntity {}", groupEntity, ex);
726 private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
727 installSnatGroupEntry(dpnId, bucketInfo, routerName);
728 LOG.debug("modifySnatGroupEntry : modified SnatMissEntry for dpnId {} of router {}", dpnId, routerName);
731 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
732 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
733 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
736 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
737 new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId)
738 .setTunnelType(tunType).build());
739 rpcResult = result.get();
740 if (!rpcResult.isSuccessful()) {
741 tunType = TunnelTypeGre.class;
742 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
743 .setSourceDpid(srcDpId)
744 .setDestinationDpid(dstDpId)
745 .setTunnelType(tunType)
747 rpcResult = result.get();
748 if (!rpcResult.isSuccessful()) {
749 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
750 rpcResult.getErrors());
752 return rpcResult.getResult().getInterfaceName();
754 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
755 rpcResult.getErrors());
757 return rpcResult.getResult().getInterfaceName();
759 } catch (InterruptedException | ExecutionException e) {
760 LOG.error("getTunnelInterfaceName :Exception when getting tunnel interface Id for tunnel between {} and {}",
761 srcDpId, dstDpId, e);
763 LOG.error("getTunnelInterfaceName : Tunnel missing between dpn {}:{}", srcDpId, dstDpId);
767 // TODO Clean up the exception handling
768 @SuppressWarnings("checkstyle:IllegalCatch")
769 public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
770 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
771 .setPrimarySwitchId(naptSwitchId).build();
773 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
774 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
775 } catch (Exception ex) {
776 LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
777 naptSwitchId, routerName);
780 LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
781 naptSwitchId, routerName);
785 public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId,
786 long routerVpnId, int addordel) {
787 FlowEntity flowEntity;
788 List<MatchInfo> matches = new ArrayList<>();
789 matches.add(MatchEthernetType.IPV4);
790 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
792 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
794 if (addordel == NatConstants.ADD_FLOW) {
795 List<ActionInfo> actionsInfo = new ArrayList<>();
796 long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerVpnId,
798 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
799 LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
800 actionsInfo.add(new ActionGroup(groupId));
801 List<InstructionInfo> instructions = new ArrayList<>();
802 instructions.add(new InstructionApplyActions(actionsInfo));
804 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
805 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
806 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
808 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
809 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
810 NwConstants.COOKIE_SNAT_TABLE, matches, null);
815 public FlowEntity buildSnatFlowEntityForNaptSwitch(BigInteger dpId, String routerName,
816 long routerVpnId, int addordel) {
817 FlowEntity flowEntity;
818 List<MatchInfo> matches = new ArrayList<>();
819 matches.add(MatchEthernetType.IPV4);
820 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
822 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
824 if (addordel == NatConstants.ADD_FLOW) {
825 List<InstructionInfo> instructions = new ArrayList<>();
827 instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
829 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
830 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
831 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
833 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
834 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
835 NwConstants.COOKIE_SNAT_TABLE, matches, null);
840 private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
841 return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
842 .FLOWID_SEPARATOR + routerID;
845 protected void installSnatFlows(String routerName, Long routerId, BigInteger naptSwitch, Long routerVpnId,
846 TypedReadWriteTransaction<Configuration> confTx) {
848 if (routerId.equals(routerVpnId)) {
849 LOG.debug("installSnatFlows : Installing flows for router with internalvpnId");
850 //36 -> 46 ..Install flow forwarding packet to table46 from table36
851 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
852 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
853 externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName, routerId, confTx);
855 //Install default flows punting to controller in table 46(OutBoundNapt table)
856 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
857 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
858 externalRouterListener.createOutboundTblEntry(naptSwitch, routerId, confTx);
860 //Table 47 point to table 21 for inbound traffic
861 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {}",
862 naptSwitch, routerId);
863 externalRouterListener.installNaptPfibEntry(naptSwitch, routerId, confTx);
865 //Table 47 point to group
866 LOG.debug("installSnatFlows : installNaptPfibExternalOutputFlow in naptswitch with dpnId {} for router {}",
867 naptSwitch, routerId);
868 externalRouterListener.installNaptPfibExternalOutputFlow(routerName, routerId, naptSwitch, confTx);
870 Uuid extNetworkUuid = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
871 if (extNetworkUuid == null) {
872 LOG.error("onRouterAssociatedToVpn : Unable to retrieve external network Uuid for router {}",
876 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
878 if (extNwProvType == null) {
879 LOG.error("onRouterAssociatedToVpn : External Network Provider Type missing");
882 //36 -> 46 ..Install flow forwarding packet to table46 from table36
883 LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
884 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
885 externalRouterListener
886 .installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerId,
887 routerVpnId, confTx, extNwProvType);
889 //Install default flows punting to controller in table 46(OutBoundNapt table)
890 LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
891 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
892 externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
894 //Table 47 point to table 21 for inbound traffic
895 LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {} "
896 + "with BgpVpnId {}", naptSwitch, routerId, routerVpnId);
897 externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
900 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
901 String vpnName = getExtNetworkVpnName(routerName, networkId);
902 if (vpnName != null) {
903 //NAPT PFIB point to FIB table for outbound traffic
904 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
905 boolean shouldInstallNaptPfibWithExtNetworkVpnId = true;
906 Collection<Uuid> externalSubnetIds = NatUtil.getExternalSubnetIdsForRouter(dataBroker, routerName);
907 if (!externalSubnetIds.isEmpty()) {
908 //NAPT PFIB point to FIB table for outbound traffic - using external subnetID as vpnID.
909 for (Uuid externalSubnetId : externalSubnetIds) {
910 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, externalSubnetId);
911 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
912 shouldInstallNaptPfibWithExtNetworkVpnId = false;
913 LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
914 + "BgpVpnId {}", naptSwitch, externalSubnetVpnId);
915 externalRouterListener.installNaptPfibEntry(naptSwitch, externalSubnetVpnId, confTx);
919 if (vpnId != NatConstants.INVALID_ID && shouldInstallNaptPfibWithExtNetworkVpnId) {
920 //NAPT PFIB table point to FIB table for outbound traffic - using external networkID as vpnID.
921 LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
922 + "BgpVpnId {}", naptSwitch, vpnId);
923 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId, confTx);
924 } else if (vpnId != NatConstants.INVALID_ID) {
925 LOG.debug("installSnatFlows : Associated BgpvpnId not found for router {}", routerId);
928 //Install Fib entries for ExternalIps & program 36 -> 44
929 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
930 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
931 for (String externalIp : externalIps) {
932 removeFibEntry(rd, externalIp);
933 LOG.debug("installSnatFlows : advToBgpAndInstallFibAndTsFlows in naptswitch id {} "
934 + "with vpnName {} and externalIp {}", naptSwitch, vpnName, externalIp);
935 externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
936 vpnName, routerId, routerName, externalIp, networkId, null /* external-router */, confTx);
937 LOG.debug("installSnatFlows : Successfully added fib entries in naptswitch {} for "
938 + "router {} with external IP {}", naptSwitch, routerId, externalIp);
941 LOG.debug("installSnatFlows : Associated vpnName not found for router {}", routerId);
945 protected void bestEffortDeletion(long routerId, String routerName, Map<String, Long> externalIpLabel,
946 TypedReadWriteTransaction<Configuration> confTx)
947 throws ExecutionException, InterruptedException {
948 Collection<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
949 if (externalIpsCache != null) {
950 Set<String> removedExternalIps = new HashSet<>(externalIpsCache);
951 removedExternalIps.removeAll(newExternalIps);
952 if (removedExternalIps.isEmpty()) {
953 LOG.info("bestEffortDeletion : No external Ip needed to be removed in bestEffortDeletion "
954 + "method for router {}", routerName);
957 Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
958 String vpnName = getExtNetworkVpnName(routerName, networkId);
959 if (vpnName == null) {
960 LOG.error("bestEffortDeletion : Vpn is not associated to externalN/w of router {}", routerName);
963 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
964 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
965 LOG.error("bestEffortDeletion : No naptSwitch is selected for router {}", routerName);
968 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName, networkId);
969 if (extNwProvType == null) {
972 String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
973 if (gwMacAddress != null) {
974 LOG.debug("bestEffortDeletion : External Gateway MAC address {} found for External Router ID {}",
975 gwMacAddress, routerId);
977 LOG.error("bestEffortDeletion : No External Gateway MAC address found for External Router ID {}",
981 if (extNwProvType == ProviderTypes.VXLAN) {
982 for (String externalIp : removedExternalIps) {
983 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
984 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
985 networkId, NatConstants.DEFAULT_LABEL_VALUE, gwMacAddress, true, confTx);
986 LOG.debug("bestEffortDeletion : Successfully removed fib entry for externalIp {} for routerId {} "
987 + "on NAPT switch {} ", externalIp, routerId, naptSwitch);
990 if (externalIpLabel == null || externalIpLabel.isEmpty()) {
991 LOG.error("bestEffortDeletion : ExternalIpLabel map is empty for router {}", routerName);
995 for (String externalIp : removedExternalIps) {
996 if (externalIpLabel.containsKey(externalIp)) {
997 label = externalIpLabel.get(externalIp);
998 LOG.debug("bestEffortDeletion : Label {} for ExternalIp {} for router {}",
999 label, externalIp, routerName);
1001 LOG.debug("bestEffortDeletion : Label for ExternalIp {} is not found for router {}",
1002 externalIp, routerName);
1005 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1006 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
1007 networkId, label, gwMacAddress, true, confTx);
1008 LOG.debug("bestEffortDeletion : Successfully removed fib entries in switch {} for router {} "
1009 + "and externalIps {}", naptSwitch, routerId, externalIp);
1013 LOG.debug("bestEffortDeletion : No external IP found for router {}", routerId);
1017 private void removeFibEntry(String rd, String prefix) {
1018 InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
1019 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
1020 .child(VrfEntry.class, new VrfEntryKey(prefix));
1021 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
1022 Optional<VrfEntry> ent = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
1023 if (ent.isPresent()) {
1024 LOG.debug("removeFibEntry : Removing Fib entry rd {} prefix {}", rd, prefix);
1025 fibManager.removeFibEntry(rd, prefix, null);
1029 protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
1030 externalRouterListener.subnetRegisterMapping(routerEntry, segmentId);