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 static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import com.google.common.base.Optional;
13 import java.math.BigInteger;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import javax.annotation.PostConstruct;
20 import javax.inject.Inject;
21 import javax.inject.Singleton;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
25 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
26 import org.opendaylight.genius.infra.Datastore.Configuration;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
29 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
30 import org.opendaylight.genius.mdsalutil.ActionInfo;
31 import org.opendaylight.genius.mdsalutil.FlowEntity;
32 import org.opendaylight.genius.mdsalutil.InstructionInfo;
33 import org.opendaylight.genius.mdsalutil.MDSALUtil;
34 import org.opendaylight.genius.mdsalutil.MatchInfo;
35 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
36 import org.opendaylight.genius.mdsalutil.NwConstants;
37 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
38 import org.opendaylight.genius.mdsalutil.actions.ActionSetDestinationIp;
39 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
40 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
41 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
46 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
47 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
48 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
49 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
50 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
51 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
72 public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<InternalToExternalPortMap, FloatingIPListener> {
73 private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
74 private final DataBroker dataBroker;
75 private final ManagedNewTransactionRunner txRunner;
76 private final IMdsalApiManager mdsalManager;
77 private final OdlInterfaceRpcService interfaceManager;
78 private final FloatingIPHandler floatingIPHandler;
79 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
80 private final JobCoordinator coordinator;
83 public FloatingIPListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
84 final OdlInterfaceRpcService interfaceManager,
85 final FloatingIPHandler floatingIPHandler,
86 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
87 final JobCoordinator coordinator) {
88 super(InternalToExternalPortMap.class, FloatingIPListener.class);
89 this.dataBroker = dataBroker;
90 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
91 this.mdsalManager = mdsalManager;
92 this.interfaceManager = interfaceManager;
93 this.floatingIPHandler = floatingIPHandler;
94 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
95 this.coordinator = coordinator;
101 LOG.info("{} init", getClass().getSimpleName());
102 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
106 protected InstanceIdentifier<InternalToExternalPortMap> getWildCardPath() {
107 return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class)
108 .child(InternalToExternalPortMap.class);
112 protected FloatingIPListener getDataTreeChangeListener() {
113 return FloatingIPListener.this;
117 protected void add(final InstanceIdentifier<InternalToExternalPortMap> identifier,
118 final InternalToExternalPortMap mapping) {
119 LOG.trace("FloatingIPListener add ip mapping method - key: {} value: {}",mapping.key(), mapping);
120 processFloatingIPAdd(identifier, mapping);
124 protected void remove(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap mapping) {
125 LOG.trace("FloatingIPListener remove ip mapping method - kkey: {} value: {}",mapping.key(), mapping);
126 processFloatingIPDel(identifier, mapping);
130 protected void update(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap
131 original, InternalToExternalPortMap update) {
132 LOG.trace("FloatingIPListener update ip mapping method - key: {}, original: {}, update: {}",
133 update.key(), original, update);
136 private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
138 String externalIp = mapping.getExternalIp();
139 Uuid floatingIpId = mapping.getExternalId();
140 //Get the FIP MAC address for DNAT
141 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
142 if (floatingIpPortMacAddress == null) {
143 LOG.error("buildPreDNATFlowEntity : Unable to retrieve floatingIpPortMacAddress from floating IP UUID {} "
144 + "for floating IP {}", floatingIpId, externalIp);
147 LOG.debug("buildPreDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
148 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
149 LOG.debug("buildPreDNATFlowEntity : Segment id {} in build preDNAT Flow", segmentId);
151 List<MatchInfo> matches = new ArrayList<>();
152 matches.add(MatchEthernetType.IPV4);
154 matches.add(new MatchIpv4Destination(externalIp, "32"));
155 //Match Destination Floating IP MAC Address on table = 25 (PDNAT_TABLE)
156 matches.add(new MatchEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
158 // matches.add(new MatchMetadata(
159 // BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
160 List<ActionInfo> actionsInfos = new ArrayList<>();
161 String internalIp = mapping.getInternalIp();
162 actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
164 List<InstructionInfo> instructions = new ArrayList<>();
165 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(segmentId),
166 MetaDataUtil.METADATA_MASK_VRFID));
167 instructions.add(new InstructionApplyActions(actionsInfos));
168 instructions.add(new InstructionGotoTable(NwConstants.DNAT_TABLE));
170 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
172 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
173 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
174 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
179 private FlowEntity buildDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
181 String externalIp = mapping.getExternalIp();
182 LOG.info("buildDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
184 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
185 LOG.debug("buildDNATFlowEntity : Segment id {} in build DNAT", segmentId);
187 List<MatchInfo> matches = new ArrayList<>();
188 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
190 matches.add(MatchEthernetType.IPV4);
191 String internalIp = mapping.getInternalIp();
192 matches.add(new MatchIpv4Destination(internalIp, "32"));
194 List<ActionInfo> actionsInfos = new ArrayList<>();
195 // actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
197 List<InstructionInfo> instructions = new ArrayList<>();
198 // instructions.add(new InstructionWriteMetadata(BigInteger.valueOf
199 // (routerId), MetaDataUtil.METADATA_MASK_VRFID));
200 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
201 instructions.add(new InstructionApplyActions(actionsInfos));
202 //instructions.add(new InstructionGotoTable(NatConstants.L3_FIB_TABLE));
204 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
206 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
207 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
208 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
214 private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long
215 routerId, long associatedVpn) {
217 LOG.debug("buildPreSNATFlowEntity : Building PSNAT Flow entity for ip {} ", internalIp);
219 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
221 LOG.debug("buildPreSNATFlowEntity : Segment id {} in build preSNAT flow", segmentId);
223 List<MatchInfo> matches = new ArrayList<>();
224 matches.add(MatchEthernetType.IPV4);
226 matches.add(new MatchIpv4Source(internalIp, "32"));
228 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
230 List<ActionInfo> actionsInfos = new ArrayList<>();
231 actionsInfos.add(new ActionSetSourceIp(externalIp, "32"));
233 List<InstructionInfo> instructions = new ArrayList<>();
235 new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
236 instructions.add(new InstructionApplyActions(actionsInfos));
237 instructions.add(new InstructionGotoTable(NwConstants.SNAT_TABLE));
239 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
241 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
242 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
243 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
248 private FlowEntity buildSNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long vpnId, Uuid
250 String internalIp = mapping.getInternalIp();
251 LOG.debug("buildSNATFlowEntity : Building SNAT Flow entity for ip {} ", internalIp);
253 ProviderTypes provType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
254 if (provType == null) {
255 LOG.error("buildSNATFlowEntity : Unable to get Network Provider Type for network {}", externalNetworkId);
259 List<MatchInfo> matches = new ArrayList<>();
260 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
261 matches.add(MatchEthernetType.IPV4);
262 String externalIp = mapping.getExternalIp();
263 matches.add(new MatchIpv4Source(externalIp, "32"));
265 List<ActionInfo> actionsInfo = new ArrayList<>();
266 Uuid floatingIpId = mapping.getExternalId();
267 String macAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
268 if (macAddress != null) {
269 actionsInfo.add(new ActionSetFieldEthernetSource(new MacAddress(macAddress)));
271 LOG.warn("buildSNATFlowEntity : No MAC address found for floating IP {}", externalIp);
274 LOG.trace("buildSNATFlowEntity : External Network Provider Type is {}, resubmit to FIB", provType.toString());
275 actionsInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
276 List<InstructionInfo> instructions = new ArrayList<>();
277 instructions.add(new InstructionApplyActions(actionsInfo));
278 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, vpnId, externalIp);
280 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
281 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
282 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
288 private void createDNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long routerId,
289 long associatedVpnId, TypedReadWriteTransaction<Configuration> confTx) {
290 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
291 if (preFlowEntity == null) {
292 LOG.error("createDNATTblEntry : Flow entity received as NULL. "
293 + "Cannot proceed with installation of Pre-DNAT flow table {} --> table {} on DpnId {}",
294 NwConstants.PDNAT_TABLE, NwConstants.DNAT_TABLE, dpnId);
296 mdsalManager.addFlow(confTx, preFlowEntity);
297 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
298 if (flowEntity != null) {
299 mdsalManager.addFlow(confTx, flowEntity);
304 private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId,
305 TypedReadWriteTransaction<Configuration> confTx) {
306 FlowEntity preFlowEntity = buildPreDNATDeleteFlowEntity(dpnId, externalIp, routerId);
307 mdsalManager.removeFlow(confTx, preFlowEntity);
309 FlowEntity flowEntity = buildDNATDeleteFlowEntity(dpnId, internalIp, routerId);
310 if (flowEntity != null) {
311 mdsalManager.removeFlow(confTx, flowEntity);
315 private void createSNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long vpnId, long routerId,
316 long associatedVpnId, Uuid externalNetworkId, TypedReadWriteTransaction<Configuration> confTx) {
317 FlowEntity preFlowEntity = buildPreSNATFlowEntity(dpnId, mapping.getInternalIp(), mapping.getExternalIp(),
318 vpnId, routerId, associatedVpnId);
319 mdsalManager.addFlow(confTx, preFlowEntity);
321 FlowEntity flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
322 if (flowEntity != null) {
323 mdsalManager.addFlow(confTx, flowEntity);
327 private void removeSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId,
328 TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
329 FlowEntity preFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId);
330 mdsalManager.removeFlow(removeFlowInvTx, preFlowEntity);
332 FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, externalIp, vpnId);
333 if (flowEntity != null) {
334 mdsalManager.removeFlow(removeFlowInvTx, flowEntity);
338 private Uuid getExtNetworkId(final InstanceIdentifier<RouterPorts> portIid,
339 LogicalDatastoreType dataStoreType) {
340 Optional<RouterPorts> rtrPort =
341 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
342 dataStoreType, portIid);
343 if (!rtrPort.isPresent()) {
344 LOG.error("getExtNetworkId : Unable to read router port entry for {}", portIid);
348 Uuid extNwId = rtrPort.get().getExternalNetworkId();
352 private long getVpnId(Uuid extNwId, Uuid floatingIpExternalId) {
353 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpExternalId);
354 if (subnetId != null) {
355 long vpnId = NatUtil.getVpnId(dataBroker, subnetId.getValue());
356 if (vpnId != NatConstants.INVALID_ID) {
357 LOG.debug("getVpnId : Got vpnId {} for floatingIpExternalId {}", vpnId, floatingIpExternalId);
362 InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class,
363 new NetworksKey(extNwId)).build();
364 Optional<Networks> nw =
365 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
366 LogicalDatastoreType.CONFIGURATION, nwId);
367 if (!nw.isPresent()) {
368 LOG.error("getVpnId : Unable to read external network for {}", extNwId);
369 return NatConstants.INVALID_ID;
372 Uuid vpnUuid = nw.get().getVpnid();
373 if (vpnUuid == null) {
374 LOG.error("getVpnId : Unable to read vpn from External network: {}", extNwId);
375 return NatConstants.INVALID_ID;
378 //Get the id using the VPN UUID (also vpn instance name)
379 return NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
382 private void processFloatingIPAdd(final InstanceIdentifier<InternalToExternalPortMap> identifier,
383 final InternalToExternalPortMap mapping) {
384 LOG.trace("processFloatingIPAdd key: {}, value: {}", mapping.key(), mapping);
386 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
387 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
388 String interfaceName = pKey.getPortName();
390 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
391 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
392 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
393 tx -> createNATFlowEntries(interfaceName, mapping, portIid, routerId, tx))),
394 NatConstants.NAT_DJC_MAX_RETRIES);
397 private void processFloatingIPDel(final InstanceIdentifier<InternalToExternalPortMap> identifier,
398 final InternalToExternalPortMap mapping) {
399 LOG.trace("processFloatingIPDel : key: {}, value: {}", mapping.key(), mapping);
401 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
402 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
403 String interfaceName = pKey.getPortName();
405 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
406 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
407 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
408 tx -> removeNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
409 NatConstants.NAT_DJC_MAX_RETRIES);
412 private InetAddress getInetAddress(String ipAddr) {
413 InetAddress ipAddress = null;
415 ipAddress = InetAddress.getByName(ipAddr);
416 } catch (UnknownHostException e) {
417 LOG.error("getInetAddress : UnknowHostException for ip {}", ipAddr, e);
422 private boolean validateIpMapping(InternalToExternalPortMap mapping) {
423 return getInetAddress(mapping.getInternalIp()) != null && getInetAddress(mapping.getExternalIp()) != null;
426 void createNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
427 final InstanceIdentifier<RouterPorts> portIid, final String routerName,
428 TypedReadWriteTransaction<Configuration> confTx) {
429 if (!validateIpMapping(mapping)) {
430 LOG.error("createNATFlowEntries : Not a valid ip addresses in the mapping {}", mapping);
434 //Get the DPN on which this interface resides
435 BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
437 if (dpnId.equals(BigInteger.ZERO)) {
438 LOG.warn("createNATFlowEntries : No DPN for interface {}. NAT flow entries for ip mapping {} will "
439 + "not be installed", interfaceName, mapping);
443 long routerId = NatUtil.getVpnId(dataBroker, routerName);
444 if (routerId == NatConstants.INVALID_ID) {
445 LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
449 //Check if the router to vpn association is present
450 //long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
451 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
452 long associatedVpnId = NatConstants.INVALID_ID;
453 if (associatedVpn == null) {
454 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
456 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
457 routerName, associatedVpn);
458 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
459 LOG.debug("createNATFlowEntries : vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
460 //routerId = associatedVpnId;
463 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.CONFIGURATION);
464 if (extNwId == null) {
465 LOG.error("createNATFlowEntries : External network associated with interface {} could not be retrieved",
469 long vpnId = getVpnId(extNwId, mapping.getExternalId());
471 LOG.error("createNATFlowEntries : No VPN associated with Ext nw {}. Unable to create SNAT table entry "
472 + "for fixed ip {}", extNwId, mapping.getInternalIp());
475 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
476 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
477 if (!isSnatEnabled) {
478 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
480 //Create the DNAT and SNAT table entries
481 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
482 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, extNwId, confTx);
483 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, extNwId, interfaceName, mapping, confTx);
486 void createNATFlowEntries(BigInteger dpnId, String interfaceName, String routerName, Uuid externalNetworkId,
487 InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx) {
488 String internalIp = mapping.getInternalIp();
489 long routerId = NatUtil.getVpnId(dataBroker, routerName);
490 if (routerId == NatConstants.INVALID_ID) {
491 LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
495 //Check if the router to vpn association is present
496 long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
497 if (associatedVpnId == NatConstants.INVALID_ID) {
498 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
500 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
501 routerName, associatedVpnId);
502 //routerId = associatedVpnId;
505 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
507 LOG.error("createNATFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
510 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
511 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
512 if (!isSnatEnabled) {
513 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
515 //Create the DNAT and SNAT table entries
516 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
517 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, externalNetworkId, confTx);
518 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, externalNetworkId, interfaceName, mapping,
522 void createNATOnlyFlowEntries(BigInteger dpnId, String routerName, String associatedVPN,
523 Uuid externalNetworkId, InternalToExternalPortMap mapping) {
524 String internalIp = mapping.getInternalIp();
525 //String segmentId = associatedVPN == null ? routerName : associatedVPN;
526 LOG.debug("createNATOnlyFlowEntries : Retrieving vpn id for VPN {} to proceed with create NAT Flows",
528 long routerId = NatUtil.getVpnId(dataBroker, routerName);
529 if (routerId == NatConstants.INVALID_ID) {
530 LOG.error("createNATOnlyFlowEntries : Could not retrieve vpn id for {} to create NAT Flow entries",
534 long associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVPN);
535 LOG.debug("createNATOnlyFlowEntries : Associated VPN Id {} for router {}", associatedVpnId, routerName);
536 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
538 LOG.error("createNATOnlyFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
541 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
542 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
543 if (!isSnatEnabled) {
544 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, null, true);
546 //Create the DNAT and SNAT table entries
547 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
548 mdsalManager.installFlow(preFlowEntity);
550 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
551 mdsalManager.installFlow(flowEntity);
553 String externalIp = mapping.getExternalIp();
554 preFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
555 mdsalManager.installFlow(preFlowEntity);
557 flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
558 if (flowEntity != null) {
559 mdsalManager.installFlow(flowEntity);
564 void removeNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
565 InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
566 TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
567 String internalIp = mapping.getInternalIp();
568 String externalIp = mapping.getExternalIp();
569 //Get the DPN on which this interface resides
571 dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
572 if (dpnId.equals(BigInteger.ZERO)) {
573 LOG.warn("removeNATFlowEntries: Abort processing Floating ip configuration. No DPN for port: {}",
579 long routerId = NatUtil.getVpnId(dataBroker, routerName);
580 if (routerId == NatConstants.INVALID_ID) {
581 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
586 //Delete the DNAT and SNAT table entries
587 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, removeFlowInvTx);
589 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.OPERATIONAL);
590 if (extNwId == null) {
591 LOG.error("removeNATFlowEntries : External network associated with interface {} could not be retrieved",
595 long vpnId = getVpnId(extNwId, mapping.getExternalId());
597 LOG.error("removeNATFlowEntries : No VPN associated with ext nw {}. Unable to delete SNAT table "
598 + "entry for fixed ip {}", extNwId, internalIp);
601 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, removeFlowInvTx);
602 //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
603 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
604 if (!isSnatEnabled) {
605 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, removeFlowInvTx, false);
607 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
608 if (provType == null) {
609 LOG.error("removeNATFlowEntries : External Network Provider Type missing");
612 if (provType == ProviderTypes.VXLAN) {
613 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping,
614 NatConstants.DEFAULT_L3VNI_VALUE, removeFlowInvTx);
615 removeOperationalDS(routerName, interfaceName, internalIp);
618 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
620 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
621 internalIp, routerId);
624 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping, (int) label,
626 removeOperationalDS(routerName, interfaceName, internalIp);
629 void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName,
630 InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx) {
631 String internalIp = mapping.getInternalIp();
632 String externalIp = mapping.getExternalIp();
633 long routerId = NatUtil.getVpnId(dataBroker, routerName);
634 if (routerId == NatConstants.INVALID_ID) {
635 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
640 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
641 if (vpnId == NatConstants.INVALID_ID) {
642 LOG.warn("removeNATFlowEntries : VPN Id not found for {} to remove NAT flow entries {}",
643 vpnName, internalIp);
646 //Delete the DNAT and SNAT table entries
647 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, confTx);
648 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, confTx);
649 //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
650 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
651 if (!isSnatEnabled) {
652 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, false);
654 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
655 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, externalNetworkId);
656 if (provType == null) {
657 LOG.error("removeNATFlowEntries : External Network Provider Type Missing");
660 if (provType == ProviderTypes.VXLAN) {
661 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, NatConstants.DEFAULT_L3VNI_VALUE,
663 removeOperationalDS(routerName, interfaceName, internalIp);
666 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
668 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
669 internalIp, routerId);
672 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, label, confTx, provType);
673 removeOperationalDS(routerName, interfaceName, internalIp);
676 protected long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
677 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapIdentifier =
678 NatUtil.getIntExtPortMapIdentifier(routerId, interfaceName, internalIp);
679 return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
680 LogicalDatastoreType.OPERATIONAL, intExtPortMapIdentifier).toJavaUtil().map(
681 InternalToExternalPortMap::getLabel).orElse(NatConstants.INVALID_ID);
684 static void updateOperationalDS(DataBroker dataBroker, String routerId, String interfaceName, long label,
685 String internalIp, String externalIp) {
687 LOG.info("updateOperationalDS : Updating operational DS for floating ip config : {} with label {}",
689 InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
690 Optional<Ports> optPorts =
691 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
692 LogicalDatastoreType.OPERATIONAL, portsId);
693 InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
694 InternalToExternalPortMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp)
695 .setLabel(label).build();
696 if (optPorts.isPresent()) {
697 LOG.debug("updateOperationalDS : Ports {} entry already present. Updating intExtPortMap for internal ip {}",
698 interfaceName, internalIp);
699 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId.child(InternalToExternalPortMap
700 .class, new InternalToExternalPortMapKey(internalIp)), intExtPortMap);
702 LOG.debug("updateOperationalDS : Adding Ports entry {} along with intExtPortMap {}",
703 interfaceName, internalIp);
704 List<InternalToExternalPortMap> intExtPortMapList = new ArrayList<>();
705 intExtPortMapList.add(intExtPortMap);
706 Ports ports = new PortsBuilder().withKey(new PortsKey(interfaceName)).setPortName(interfaceName)
707 .setInternalToExternalPortMap(intExtPortMapList).build();
708 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
712 void removeOperationalDS(String routerId, String interfaceName, String internalIp) {
713 LOG.info("removeOperationalDS : Remove operational DS for floating ip config: {}", internalIp);
714 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapId = NatUtil.getIntExtPortMapIdentifier(routerId,
715 interfaceName, internalIp);
716 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, intExtPortMapId);
719 private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
721 LOG.info("buildPreDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", externalIp);
723 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
725 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
726 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
727 NwConstants.COOKIE_DNAT_TABLE, null, null);
734 private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
736 LOG.info("buildDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", internalIp);
738 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
740 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
741 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
742 NwConstants.COOKIE_DNAT_TABLE, null, null);
748 private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
750 LOG.info("buildPreSNATDeleteFlowEntity : Building Delete PSNAT Flow entity for ip {} ", internalIp);
752 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
754 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
755 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
756 NwConstants.COOKIE_DNAT_TABLE, null, null);
760 private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
762 LOG.info("buildSNATDeleteFlowEntity : Building Delete SNAT Flow entity for ip {} ", externalIp);
764 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, routerId, externalIp);
766 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
767 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
768 NwConstants.COOKIE_DNAT_TABLE, null, null);
773 private void addOrDelDefaultFibRouteForDnat(BigInteger dpnId, String routerName, long routerId,
774 TypedReadWriteTransaction<Configuration> confTx, boolean create) {
775 if (confTx == null) {
776 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
777 newTx -> addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, newTx, create)), LOG,
778 "Error handling default FIB route for DNAT");
781 //Check if the router to bgp-vpn association is present
782 long associatedVpnId = NatConstants.INVALID_ID;
783 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
784 if (associatedVpn != null) {
785 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
788 if (associatedVpnId != NatConstants.INVALID_ID) {
789 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
790 + "vpn-id {}", dpnId, routerName, associatedVpnId);
791 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
793 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
794 + "vpn-id {}", dpnId, routerName, routerId);
795 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
798 if (associatedVpnId != NatConstants.INVALID_ID) {
799 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
800 + "with vpn-id {}", dpnId, routerName, associatedVpnId);
801 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
803 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
804 + "with vpn-id {}", dpnId, routerName, routerId);
805 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);