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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.math.BigInteger;
15 import java.net.InetAddress;
16 import java.net.UnknownHostException;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.List;
20 import javax.annotation.PostConstruct;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
26 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
27 import org.opendaylight.genius.infra.Datastore.Configuration;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
30 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
31 import org.opendaylight.genius.mdsalutil.ActionInfo;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
33 import org.opendaylight.genius.mdsalutil.InstructionInfo;
34 import org.opendaylight.genius.mdsalutil.MDSALUtil;
35 import org.opendaylight.genius.mdsalutil.MatchInfo;
36 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
37 import org.opendaylight.genius.mdsalutil.NwConstants;
38 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
39 import org.opendaylight.genius.mdsalutil.actions.ActionSetDestinationIp;
40 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
41 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
44 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
45 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
46 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
47 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
48 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
49 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
50 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
51 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
52 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
73 public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<InternalToExternalPortMap, FloatingIPListener> {
74 private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
75 private final DataBroker dataBroker;
76 private final ManagedNewTransactionRunner txRunner;
77 private final IMdsalApiManager mdsalManager;
78 private final OdlInterfaceRpcService interfaceManager;
79 private final FloatingIPHandler floatingIPHandler;
80 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
81 private final JobCoordinator coordinator;
84 public FloatingIPListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
85 final OdlInterfaceRpcService interfaceManager,
86 final FloatingIPHandler floatingIPHandler,
87 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
88 final JobCoordinator coordinator) {
89 super(InternalToExternalPortMap.class, FloatingIPListener.class);
90 this.dataBroker = dataBroker;
91 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
92 this.mdsalManager = mdsalManager;
93 this.interfaceManager = interfaceManager;
94 this.floatingIPHandler = floatingIPHandler;
95 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
96 this.coordinator = coordinator;
102 LOG.info("{} init", getClass().getSimpleName());
103 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
107 protected InstanceIdentifier<InternalToExternalPortMap> getWildCardPath() {
108 return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class)
109 .child(InternalToExternalPortMap.class);
113 protected FloatingIPListener getDataTreeChangeListener() {
114 return FloatingIPListener.this;
118 protected void add(final InstanceIdentifier<InternalToExternalPortMap> identifier,
119 final InternalToExternalPortMap mapping) {
120 LOG.trace("FloatingIPListener add ip mapping method - key: {} value: {}",mapping.key(), mapping);
121 processFloatingIPAdd(identifier, mapping);
125 protected void remove(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap mapping) {
126 LOG.trace("FloatingIPListener remove ip mapping method - kkey: {} value: {}",mapping.key(), mapping);
127 processFloatingIPDel(identifier, mapping);
131 protected void update(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap
132 original, InternalToExternalPortMap update) {
133 LOG.trace("FloatingIPListener update ip mapping method - key: {}, original: {}, update: {}",
134 update.key(), original, update);
137 private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
139 String externalIp = mapping.getExternalIp();
140 Uuid floatingIpId = mapping.getExternalId();
141 //Get the FIP MAC address for DNAT
142 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
143 if (floatingIpPortMacAddress == null) {
144 LOG.error("buildPreDNATFlowEntity : Unable to retrieve floatingIpPortMacAddress from floating IP UUID {} "
145 + "for floating IP {}", floatingIpId, externalIp);
148 LOG.debug("buildPreDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
149 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
150 LOG.debug("buildPreDNATFlowEntity : Segment id {} in build preDNAT Flow", segmentId);
152 List<MatchInfo> matches = new ArrayList<>();
153 matches.add(MatchEthernetType.IPV4);
155 matches.add(new MatchIpv4Destination(externalIp, "32"));
156 //Match Destination Floating IP MAC Address on table = 25 (PDNAT_TABLE)
157 matches.add(new MatchEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
159 // matches.add(new MatchMetadata(
160 // BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
161 List<ActionInfo> actionsInfos = new ArrayList<>();
162 String internalIp = mapping.getInternalIp();
163 actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
165 List<InstructionInfo> instructions = new ArrayList<>();
166 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(segmentId),
167 MetaDataUtil.METADATA_MASK_VRFID));
168 instructions.add(new InstructionApplyActions(actionsInfos));
169 instructions.add(new InstructionGotoTable(NwConstants.DNAT_TABLE));
171 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
173 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
174 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
175 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
180 private FlowEntity buildDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
182 String externalIp = mapping.getExternalIp();
183 LOG.info("buildDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
185 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
186 LOG.debug("buildDNATFlowEntity : Segment id {} in build DNAT", segmentId);
188 List<MatchInfo> matches = new ArrayList<>();
189 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
191 matches.add(MatchEthernetType.IPV4);
192 String internalIp = mapping.getInternalIp();
193 matches.add(new MatchIpv4Destination(internalIp, "32"));
195 List<ActionInfo> actionsInfos = new ArrayList<>();
196 // actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
198 List<InstructionInfo> instructions = new ArrayList<>();
199 // instructions.add(new InstructionWriteMetadata(BigInteger.valueOf
200 // (routerId), MetaDataUtil.METADATA_MASK_VRFID));
201 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
202 instructions.add(new InstructionApplyActions(actionsInfos));
203 //instructions.add(new InstructionGotoTable(NatConstants.L3_FIB_TABLE));
205 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
207 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
208 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
209 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
215 private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long
216 routerId, long associatedVpn) {
218 LOG.debug("buildPreSNATFlowEntity : Building PSNAT Flow entity for ip {} ", internalIp);
220 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
222 LOG.debug("buildPreSNATFlowEntity : Segment id {} in build preSNAT flow", segmentId);
224 List<MatchInfo> matches = new ArrayList<>();
225 matches.add(MatchEthernetType.IPV4);
227 matches.add(new MatchIpv4Source(internalIp, "32"));
229 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
231 List<ActionInfo> actionsInfos = new ArrayList<>();
232 actionsInfos.add(new ActionSetSourceIp(externalIp, "32"));
234 List<InstructionInfo> instructions = new ArrayList<>();
236 new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
237 instructions.add(new InstructionApplyActions(actionsInfos));
238 instructions.add(new InstructionGotoTable(NwConstants.SNAT_TABLE));
240 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
242 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
243 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
244 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
249 private FlowEntity buildSNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long vpnId, Uuid
251 String internalIp = mapping.getInternalIp();
252 LOG.debug("buildSNATFlowEntity : Building SNAT Flow entity for ip {} ", internalIp);
254 ProviderTypes provType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
255 if (provType == null) {
256 LOG.error("buildSNATFlowEntity : Unable to get Network Provider Type for network {}", externalNetworkId);
260 List<MatchInfo> matches = new ArrayList<>();
261 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
262 matches.add(MatchEthernetType.IPV4);
263 String externalIp = mapping.getExternalIp();
264 matches.add(new MatchIpv4Source(externalIp, "32"));
266 List<ActionInfo> actionsInfo = new ArrayList<>();
267 Uuid floatingIpId = mapping.getExternalId();
268 String macAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
269 if (macAddress != null) {
270 actionsInfo.add(new ActionSetFieldEthernetSource(new MacAddress(macAddress)));
272 LOG.warn("buildSNATFlowEntity : No MAC address found for floating IP {}", externalIp);
275 LOG.trace("buildSNATFlowEntity : External Network Provider Type is {}, resubmit to FIB", provType.toString());
276 actionsInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
277 List<InstructionInfo> instructions = new ArrayList<>();
278 instructions.add(new InstructionApplyActions(actionsInfo));
279 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, vpnId, externalIp);
281 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
282 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
283 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
289 private void createDNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long routerId,
290 long associatedVpnId, TypedReadWriteTransaction<Configuration> confTx) {
291 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
292 if (preFlowEntity == null) {
293 LOG.error("createDNATTblEntry : Flow entity received as NULL. "
294 + "Cannot proceed with installation of Pre-DNAT flow table {} --> table {} on DpnId {}",
295 NwConstants.PDNAT_TABLE, NwConstants.DNAT_TABLE, dpnId);
297 mdsalManager.addFlow(confTx, preFlowEntity);
298 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
299 if (flowEntity != null) {
300 mdsalManager.addFlow(confTx, flowEntity);
305 // TODO skitt Fix the exception handling here
306 @SuppressWarnings("checkstyle:IllegalCatch")
307 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
308 private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId,
309 TypedReadWriteTransaction<Configuration> confTx) {
311 FlowEntity preFlowEntity = buildPreDNATDeleteFlowEntity(dpnId, externalIp, routerId);
312 mdsalManager.removeFlow(confTx, preFlowEntity);
314 FlowEntity flowEntity = buildDNATDeleteFlowEntity(dpnId, internalIp, routerId);
315 if (flowEntity != null) {
316 mdsalManager.removeFlow(confTx, flowEntity);
318 } catch (Exception e) {
319 LOG.error("Error removing flow", e);
320 throw new RuntimeException("Error removing flow", e);
324 private void createSNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long vpnId, long routerId,
325 long associatedVpnId, Uuid externalNetworkId, TypedReadWriteTransaction<Configuration> confTx) {
326 FlowEntity preFlowEntity = buildPreSNATFlowEntity(dpnId, mapping.getInternalIp(), mapping.getExternalIp(),
327 vpnId, routerId, associatedVpnId);
328 mdsalManager.addFlow(confTx, preFlowEntity);
330 FlowEntity flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
331 if (flowEntity != null) {
332 mdsalManager.addFlow(confTx, flowEntity);
336 // TODO skitt Fix the exception handling here
337 @SuppressWarnings("checkstyle:IllegalCatch")
338 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
339 private void removeSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId,
340 TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
342 FlowEntity preFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId);
343 mdsalManager.removeFlow(removeFlowInvTx, preFlowEntity);
345 FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, externalIp, vpnId);
346 if (flowEntity != null) {
347 mdsalManager.removeFlow(removeFlowInvTx, flowEntity);
349 } catch (Exception e) {
350 LOG.error("Error removing flow", e);
351 throw new RuntimeException("Error removing flow", e);
355 private Uuid getExtNetworkId(final InstanceIdentifier<RouterPorts> portIid,
356 LogicalDatastoreType dataStoreType) {
357 Optional<RouterPorts> rtrPort =
358 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
359 dataStoreType, portIid);
360 if (!rtrPort.isPresent()) {
361 LOG.error("getExtNetworkId : Unable to read router port entry for {}", portIid);
365 Uuid extNwId = rtrPort.get().getExternalNetworkId();
369 private long getVpnId(Uuid extNwId, Uuid floatingIpExternalId) {
370 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpExternalId);
371 if (subnetId != null) {
372 long vpnId = NatUtil.getVpnId(dataBroker, subnetId.getValue());
373 if (vpnId != NatConstants.INVALID_ID) {
374 LOG.debug("getVpnId : Got vpnId {} for floatingIpExternalId {}", vpnId, floatingIpExternalId);
379 InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class,
380 new NetworksKey(extNwId)).build();
381 Optional<Networks> nw =
382 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
383 LogicalDatastoreType.CONFIGURATION, nwId);
384 if (!nw.isPresent()) {
385 LOG.error("getVpnId : Unable to read external network for {}", extNwId);
386 return NatConstants.INVALID_ID;
389 Uuid vpnUuid = nw.get().getVpnid();
390 if (vpnUuid == null) {
391 LOG.error("getVpnId : Unable to read vpn from External network: {}", extNwId);
392 return NatConstants.INVALID_ID;
395 //Get the id using the VPN UUID (also vpn instance name)
396 return NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
399 private void processFloatingIPAdd(final InstanceIdentifier<InternalToExternalPortMap> identifier,
400 final InternalToExternalPortMap mapping) {
401 LOG.trace("processFloatingIPAdd key: {}, value: {}", mapping.key(), mapping);
403 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
404 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
405 String interfaceName = pKey.getPortName();
407 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
408 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
409 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
410 tx -> createNATFlowEntries(interfaceName, mapping, portIid, routerId, tx))),
411 NatConstants.NAT_DJC_MAX_RETRIES);
414 private void processFloatingIPDel(final InstanceIdentifier<InternalToExternalPortMap> identifier,
415 final InternalToExternalPortMap mapping) {
416 LOG.trace("processFloatingIPDel : key: {}, value: {}", mapping.key(), mapping);
418 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
419 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
420 String interfaceName = pKey.getPortName();
422 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
423 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
424 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
425 tx -> removeNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
426 NatConstants.NAT_DJC_MAX_RETRIES);
429 private InetAddress getInetAddress(String ipAddr) {
430 InetAddress ipAddress = null;
432 ipAddress = InetAddress.getByName(ipAddr);
433 } catch (UnknownHostException e) {
434 LOG.error("getInetAddress : UnknowHostException for ip {}", ipAddr, e);
439 private boolean validateIpMapping(InternalToExternalPortMap mapping) {
440 return getInetAddress(mapping.getInternalIp()) != null && getInetAddress(mapping.getExternalIp()) != null;
443 void createNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
444 final InstanceIdentifier<RouterPorts> portIid, final String routerName,
445 TypedReadWriteTransaction<Configuration> confTx) {
446 if (!validateIpMapping(mapping)) {
447 LOG.error("createNATFlowEntries : Not a valid ip addresses in the mapping {}", mapping);
451 //Get the DPN on which this interface resides
452 BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
454 if (dpnId.equals(BigInteger.ZERO)) {
455 LOG.warn("createNATFlowEntries : No DPN for interface {}. NAT flow entries for ip mapping {} will "
456 + "not be installed", interfaceName, mapping);
460 long routerId = NatUtil.getVpnId(dataBroker, routerName);
461 if (routerId == NatConstants.INVALID_ID) {
462 LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
466 //Check if the router to vpn association is present
467 //long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
468 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
469 long associatedVpnId = NatConstants.INVALID_ID;
470 if (associatedVpn == null) {
471 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
473 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
474 routerName, associatedVpn);
475 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
476 LOG.debug("createNATFlowEntries : vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
477 //routerId = associatedVpnId;
480 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.CONFIGURATION);
481 if (extNwId == null) {
482 LOG.error("createNATFlowEntries : External network associated with interface {} could not be retrieved",
486 long vpnId = getVpnId(extNwId, mapping.getExternalId());
488 LOG.error("createNATFlowEntries : No VPN associated with Ext nw {}. Unable to create SNAT table entry "
489 + "for fixed ip {}", extNwId, mapping.getInternalIp());
492 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
493 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
494 if (!isSnatEnabled) {
495 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
497 //Create the DNAT and SNAT table entries
498 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
499 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, extNwId, confTx);
500 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, extNwId, interfaceName, mapping, confTx);
503 void createNATFlowEntries(BigInteger dpnId, String interfaceName, String routerName, Uuid externalNetworkId,
504 InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx) {
505 String internalIp = mapping.getInternalIp();
506 long routerId = NatUtil.getVpnId(dataBroker, routerName);
507 if (routerId == NatConstants.INVALID_ID) {
508 LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
512 //Check if the router to vpn association is present
513 long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
514 if (associatedVpnId == NatConstants.INVALID_ID) {
515 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
517 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
518 routerName, associatedVpnId);
519 //routerId = associatedVpnId;
522 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
524 LOG.error("createNATFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
527 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
528 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
529 if (!isSnatEnabled) {
530 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
532 //Create the DNAT and SNAT table entries
533 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
534 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, externalNetworkId, confTx);
535 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, externalNetworkId, interfaceName, mapping,
539 void createNATOnlyFlowEntries(BigInteger dpnId, String routerName, String associatedVPN,
540 Uuid externalNetworkId, InternalToExternalPortMap mapping) {
541 String internalIp = mapping.getInternalIp();
542 //String segmentId = associatedVPN == null ? routerName : associatedVPN;
543 LOG.debug("createNATOnlyFlowEntries : Retrieving vpn id for VPN {} to proceed with create NAT Flows",
545 long routerId = NatUtil.getVpnId(dataBroker, routerName);
546 if (routerId == NatConstants.INVALID_ID) {
547 LOG.error("createNATOnlyFlowEntries : Could not retrieve vpn id for {} to create NAT Flow entries",
551 long associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVPN);
552 LOG.debug("createNATOnlyFlowEntries : Associated VPN Id {} for router {}", associatedVpnId, routerName);
553 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
555 LOG.error("createNATOnlyFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
558 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
559 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
560 if (!isSnatEnabled) {
561 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, null, true);
563 //Create the DNAT and SNAT table entries
564 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
565 mdsalManager.installFlow(preFlowEntity);
567 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
568 mdsalManager.installFlow(flowEntity);
570 String externalIp = mapping.getExternalIp();
571 preFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
572 mdsalManager.installFlow(preFlowEntity);
574 flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
575 if (flowEntity != null) {
576 mdsalManager.installFlow(flowEntity);
581 void removeNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
582 InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
583 TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
584 String internalIp = mapping.getInternalIp();
585 String externalIp = mapping.getExternalIp();
586 //Get the DPN on which this interface resides
588 dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
589 if (dpnId.equals(BigInteger.ZERO)) {
590 LOG.warn("removeNATFlowEntries: Abort processing Floating ip configuration. No DPN for port: {}",
596 long routerId = NatUtil.getVpnId(dataBroker, routerName);
597 if (routerId == NatConstants.INVALID_ID) {
598 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
603 //Delete the DNAT and SNAT table entries
604 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, removeFlowInvTx);
606 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.OPERATIONAL);
607 if (extNwId == null) {
608 LOG.error("removeNATFlowEntries : External network associated with interface {} could not be retrieved",
612 long vpnId = getVpnId(extNwId, mapping.getExternalId());
614 LOG.error("removeNATFlowEntries : No VPN associated with ext nw {}. Unable to delete SNAT table "
615 + "entry for fixed ip {}", extNwId, internalIp);
618 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, removeFlowInvTx);
619 //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
620 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
621 if (!isSnatEnabled) {
622 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, removeFlowInvTx, false);
624 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
625 if (provType == null) {
626 LOG.error("removeNATFlowEntries : External Network Provider Type missing");
629 if (provType == ProviderTypes.VXLAN) {
630 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping,
631 NatConstants.DEFAULT_L3VNI_VALUE, removeFlowInvTx);
632 removeOperationalDS(routerName, interfaceName, internalIp);
635 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
637 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
638 internalIp, routerId);
641 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping, (int) label,
643 removeOperationalDS(routerName, interfaceName, internalIp);
646 void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName,
647 InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx) {
648 String internalIp = mapping.getInternalIp();
649 String externalIp = mapping.getExternalIp();
650 long routerId = NatUtil.getVpnId(dataBroker, routerName);
651 if (routerId == NatConstants.INVALID_ID) {
652 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
657 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
658 if (vpnId == NatConstants.INVALID_ID) {
659 LOG.warn("removeNATFlowEntries : VPN Id not found for {} to remove NAT flow entries {}",
660 vpnName, internalIp);
663 //Delete the DNAT and SNAT table entries
664 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, confTx);
665 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, confTx);
666 //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
667 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
668 if (!isSnatEnabled) {
669 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, false);
671 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
672 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, externalNetworkId);
673 if (provType == null) {
674 LOG.error("removeNATFlowEntries : External Network Provider Type Missing");
677 if (provType == ProviderTypes.VXLAN) {
678 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, NatConstants.DEFAULT_L3VNI_VALUE,
680 removeOperationalDS(routerName, interfaceName, internalIp);
683 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
685 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
686 internalIp, routerId);
689 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, label, confTx, provType);
690 removeOperationalDS(routerName, interfaceName, internalIp);
693 protected long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
694 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapIdentifier =
695 NatUtil.getIntExtPortMapIdentifier(routerId, interfaceName, internalIp);
696 return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
697 LogicalDatastoreType.OPERATIONAL, intExtPortMapIdentifier).toJavaUtil().map(
698 InternalToExternalPortMap::getLabel).orElse(NatConstants.INVALID_ID);
701 static void updateOperationalDS(DataBroker dataBroker, String routerId, String interfaceName, long label,
702 String internalIp, String externalIp) {
704 LOG.info("updateOperationalDS : Updating operational DS for floating ip config : {} with label {}",
706 InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
707 Optional<Ports> optPorts =
708 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
709 LogicalDatastoreType.OPERATIONAL, portsId);
710 InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
711 InternalToExternalPortMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp)
712 .setLabel(label).build();
713 if (optPorts.isPresent()) {
714 LOG.debug("updateOperationalDS : Ports {} entry already present. Updating intExtPortMap for internal ip {}",
715 interfaceName, internalIp);
716 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId.child(InternalToExternalPortMap
717 .class, new InternalToExternalPortMapKey(internalIp)), intExtPortMap);
719 LOG.debug("updateOperationalDS : Adding Ports entry {} along with intExtPortMap {}",
720 interfaceName, internalIp);
721 List<InternalToExternalPortMap> intExtPortMapList = new ArrayList<>();
722 intExtPortMapList.add(intExtPortMap);
723 Ports ports = new PortsBuilder().withKey(new PortsKey(interfaceName)).setPortName(interfaceName)
724 .setInternalToExternalPortMap(intExtPortMapList).build();
725 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
729 void removeOperationalDS(String routerId, String interfaceName, String internalIp) {
730 LOG.info("removeOperationalDS : Remove operational DS for floating ip config: {}", internalIp);
731 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapId = NatUtil.getIntExtPortMapIdentifier(routerId,
732 interfaceName, internalIp);
733 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, intExtPortMapId);
736 private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
738 LOG.info("buildPreDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", externalIp);
740 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
742 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
743 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
744 NwConstants.COOKIE_DNAT_TABLE, null, null);
751 private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
753 LOG.info("buildDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", internalIp);
755 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
757 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
758 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
759 NwConstants.COOKIE_DNAT_TABLE, null, null);
765 private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
767 LOG.info("buildPreSNATDeleteFlowEntity : Building Delete PSNAT Flow entity for ip {} ", internalIp);
769 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
771 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
772 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
773 NwConstants.COOKIE_DNAT_TABLE, null, null);
777 private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
779 LOG.info("buildSNATDeleteFlowEntity : Building Delete SNAT Flow entity for ip {} ", externalIp);
781 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, routerId, externalIp);
783 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
784 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
785 NwConstants.COOKIE_DNAT_TABLE, null, null);
790 private void addOrDelDefaultFibRouteForDnat(BigInteger dpnId, String routerName, long routerId,
791 TypedReadWriteTransaction<Configuration> confTx, boolean create) {
792 if (confTx == null) {
793 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
794 newTx -> addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, newTx, create)), LOG,
795 "Error handling default FIB route for DNAT");
798 //Check if the router to bgp-vpn association is present
799 long associatedVpnId = NatConstants.INVALID_ID;
800 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
801 if (associatedVpn != null) {
802 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
805 if (associatedVpnId != NatConstants.INVALID_ID) {
806 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
807 + "vpn-id {}", dpnId, routerName, associatedVpnId);
808 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
810 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
811 + "vpn-id {}", dpnId, routerName, routerId);
812 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
815 if (associatedVpnId != NatConstants.INVALID_ID) {
816 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
817 + "with vpn-id {}", dpnId, routerName, associatedVpnId);
818 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
820 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
821 + "with vpn-id {}", dpnId, routerName, routerId);
822 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);