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.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
17 import javax.annotation.PostConstruct;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
24 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
25 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
26 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
27 import org.opendaylight.genius.mdsalutil.ActionInfo;
28 import org.opendaylight.genius.mdsalutil.FlowEntity;
29 import org.opendaylight.genius.mdsalutil.InstructionInfo;
30 import org.opendaylight.genius.mdsalutil.MDSALUtil;
31 import org.opendaylight.genius.mdsalutil.MatchInfo;
32 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
33 import org.opendaylight.genius.mdsalutil.NwConstants;
34 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
35 import org.opendaylight.genius.mdsalutil.actions.ActionSetDestinationIp;
36 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
37 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
38 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
39 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
40 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
41 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
42 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
43 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
44 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
45 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
46 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
47 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
48 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
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.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
64 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
69 public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<InternalToExternalPortMap, FloatingIPListener> {
70 private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
71 private final DataBroker dataBroker;
72 private final ManagedNewTransactionRunner txRunner;
73 private final IMdsalApiManager mdsalManager;
74 private final OdlInterfaceRpcService interfaceManager;
75 private final FloatingIPHandler floatingIPHandler;
76 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
77 private final JobCoordinator coordinator;
80 public FloatingIPListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
81 final OdlInterfaceRpcService interfaceManager,
82 final FloatingIPHandler floatingIPHandler,
83 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
84 final JobCoordinator coordinator) {
85 super(InternalToExternalPortMap.class, FloatingIPListener.class);
86 this.dataBroker = dataBroker;
87 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
88 this.mdsalManager = mdsalManager;
89 this.interfaceManager = interfaceManager;
90 this.floatingIPHandler = floatingIPHandler;
91 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
92 this.coordinator = coordinator;
98 LOG.info("{} init", getClass().getSimpleName());
99 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
103 protected InstanceIdentifier<InternalToExternalPortMap> getWildCardPath() {
104 return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class)
105 .child(InternalToExternalPortMap.class);
109 protected FloatingIPListener getDataTreeChangeListener() {
110 return FloatingIPListener.this;
114 protected void add(final InstanceIdentifier<InternalToExternalPortMap> identifier,
115 final InternalToExternalPortMap mapping) {
116 LOG.trace("FloatingIPListener add ip mapping method - key: {} value: {}",mapping.getKey(), mapping);
117 processFloatingIPAdd(identifier, mapping);
121 protected void remove(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap mapping) {
122 LOG.trace("FloatingIPListener remove ip mapping method - kkey: {} value: {}",mapping.getKey(), mapping);
123 processFloatingIPDel(identifier, mapping);
127 protected void update(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap
128 original, InternalToExternalPortMap update) {
129 LOG.trace("FloatingIPListener update ip mapping method - key: {}, original: {}, update: {}",
130 update.getKey(), original, update);
133 private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
135 String externalIp = mapping.getExternalIp();
136 Uuid floatingIpId = mapping.getExternalId();
137 //Get the FIP MAC address for DNAT
138 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
139 if (floatingIpPortMacAddress == null) {
140 LOG.error("buildPreDNATFlowEntity : Unable to retrieve floatingIpPortMacAddress from floating IP UUID {} "
141 + "for floating IP {}", floatingIpId, externalIp);
144 LOG.debug("buildPreDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
145 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
146 LOG.debug("buildPreDNATFlowEntity : Segment id {} in build preDNAT Flow", segmentId);
148 List<MatchInfo> matches = new ArrayList<>();
149 matches.add(MatchEthernetType.IPV4);
151 matches.add(new MatchIpv4Destination(externalIp, "32"));
152 //Match Destination Floating IP MAC Address on table = 25 (PDNAT_TABLE)
153 matches.add(new MatchEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
155 // matches.add(new MatchMetadata(
156 // BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
157 List<ActionInfo> actionsInfos = new ArrayList<>();
158 String internalIp = mapping.getInternalIp();
159 actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
161 List<InstructionInfo> instructions = new ArrayList<>();
162 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(segmentId),
163 MetaDataUtil.METADATA_MASK_VRFID));
164 instructions.add(new InstructionApplyActions(actionsInfos));
165 instructions.add(new InstructionGotoTable(NwConstants.DNAT_TABLE));
167 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
169 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
170 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
171 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
176 private FlowEntity buildDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
178 String externalIp = mapping.getExternalIp();
179 LOG.info("buildDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
181 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
182 LOG.debug("buildDNATFlowEntity : Segment id {} in build DNAT", segmentId);
184 List<MatchInfo> matches = new ArrayList<>();
185 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
187 matches.add(MatchEthernetType.IPV4);
188 String internalIp = mapping.getInternalIp();
189 matches.add(new MatchIpv4Destination(internalIp, "32"));
191 List<ActionInfo> actionsInfos = new ArrayList<>();
192 // actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
194 List<InstructionInfo> instructions = new ArrayList<>();
195 // instructions.add(new InstructionWriteMetadata(BigInteger.valueOf
196 // (routerId), MetaDataUtil.METADATA_MASK_VRFID));
197 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
198 instructions.add(new InstructionApplyActions(actionsInfos));
199 //instructions.add(new InstructionGotoTable(NatConstants.L3_FIB_TABLE));
201 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
203 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
204 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
205 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
211 private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long
212 routerId, long associatedVpn) {
214 LOG.debug("buildPreSNATFlowEntity : Building PSNAT Flow entity for ip {} ", internalIp);
216 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
218 LOG.debug("buildPreSNATFlowEntity : Segment id {} in build preSNAT flow", segmentId);
220 List<MatchInfo> matches = new ArrayList<>();
221 matches.add(MatchEthernetType.IPV4);
223 matches.add(new MatchIpv4Source(internalIp, "32"));
225 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
227 List<ActionInfo> actionsInfos = new ArrayList<>();
228 actionsInfos.add(new ActionSetSourceIp(externalIp, "32"));
230 List<InstructionInfo> instructions = new ArrayList<>();
232 new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
233 instructions.add(new InstructionApplyActions(actionsInfos));
234 instructions.add(new InstructionGotoTable(NwConstants.SNAT_TABLE));
236 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
238 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
239 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
240 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
245 private FlowEntity buildSNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long vpnId, Uuid
247 String internalIp = mapping.getInternalIp();
248 LOG.debug("buildSNATFlowEntity : Building SNAT Flow entity for ip {} ", internalIp);
250 ProviderTypes provType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
251 if (provType == null) {
252 LOG.error("buildSNATFlowEntity : Unable to get Network Provider Type for network {}", externalNetworkId);
256 List<MatchInfo> matches = new ArrayList<>();
257 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
258 matches.add(MatchEthernetType.IPV4);
259 String externalIp = mapping.getExternalIp();
260 matches.add(new MatchIpv4Source(externalIp, "32"));
262 List<ActionInfo> actionsInfo = new ArrayList<>();
263 Uuid floatingIpId = mapping.getExternalId();
264 String macAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
265 if (macAddress != null) {
266 actionsInfo.add(new ActionSetFieldEthernetSource(new MacAddress(macAddress)));
268 LOG.warn("buildSNATFlowEntity : No MAC address found for floating IP {}", externalIp);
271 LOG.trace("buildSNATFlowEntity : External Network Provider Type is {}, resubmit to FIB", provType.toString());
272 actionsInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
273 List<InstructionInfo> instructions = new ArrayList<>();
274 instructions.add(new InstructionApplyActions(actionsInfo));
275 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, vpnId, externalIp);
277 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
278 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
279 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
285 private void createDNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long routerId,
286 long associatedVpnId, WriteTransaction writeFlowInvTx) {
287 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
288 if (preFlowEntity == null) {
289 LOG.error("createDNATTblEntry : Flow entity received as NULL. "
290 + "Cannot proceed with installation of Pre-DNAT flow table {} --> table {} on DpnId {}",
291 NwConstants.PDNAT_TABLE, NwConstants.DNAT_TABLE, dpnId);
293 mdsalManager.addFlowToTx(preFlowEntity, writeFlowInvTx);
294 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
295 if (flowEntity != null) {
296 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
301 private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId,
302 WriteTransaction removeFlowInvTx) {
303 FlowEntity preFlowEntity = buildPreDNATDeleteFlowEntity(dpnId, externalIp, routerId);
304 mdsalManager.removeFlowToTx(preFlowEntity, removeFlowInvTx);
306 FlowEntity flowEntity = buildDNATDeleteFlowEntity(dpnId, internalIp, routerId);
307 if (flowEntity != null) {
308 mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
312 private void createSNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long vpnId, long routerId,
313 long associatedVpnId, Uuid externalNetworkId, WriteTransaction writeFlowInvTx) {
314 FlowEntity preFlowEntity = buildPreSNATFlowEntity(dpnId, mapping.getInternalIp(), mapping.getExternalIp(),
315 vpnId, routerId, associatedVpnId);
316 mdsalManager.addFlowToTx(preFlowEntity, writeFlowInvTx);
318 FlowEntity flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
319 if (flowEntity != null) {
320 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
324 private void removeSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId,
325 WriteTransaction removeFlowInvTx) {
326 FlowEntity preFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId);
327 mdsalManager.removeFlowToTx(preFlowEntity, removeFlowInvTx);
329 FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, externalIp, vpnId);
330 if (flowEntity != null) {
331 mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
335 private Uuid getExtNetworkId(final InstanceIdentifier<RouterPorts> portIid,
336 LogicalDatastoreType dataStoreType) {
337 Optional<RouterPorts> rtrPort =
338 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
339 dataStoreType, portIid);
340 if (!rtrPort.isPresent()) {
341 LOG.error("getExtNetworkId : Unable to read router port entry for {}", portIid);
345 Uuid extNwId = rtrPort.get().getExternalNetworkId();
349 private long getVpnId(Uuid extNwId, Uuid floatingIpExternalId) {
350 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpExternalId);
351 if (subnetId != null) {
352 long vpnId = NatUtil.getVpnId(dataBroker, subnetId.getValue());
353 if (vpnId != NatConstants.INVALID_ID) {
354 LOG.debug("getVpnId : Got vpnId {} for floatingIpExternalId {}", vpnId, floatingIpExternalId);
359 InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class,
360 new NetworksKey(extNwId)).build();
361 Optional<Networks> nw =
362 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
363 LogicalDatastoreType.CONFIGURATION, nwId);
364 if (!nw.isPresent()) {
365 LOG.error("getVpnId : Unable to read external network for {}", extNwId);
366 return NatConstants.INVALID_ID;
369 Uuid vpnUuid = nw.get().getVpnid();
370 if (vpnUuid == null) {
371 LOG.error("getVpnId : Unable to read vpn from External network: {}", extNwId);
372 return NatConstants.INVALID_ID;
375 //Get the id using the VPN UUID (also vpn instance name)
376 return NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
379 private void processFloatingIPAdd(final InstanceIdentifier<InternalToExternalPortMap> identifier,
380 final InternalToExternalPortMap mapping) {
381 LOG.trace("processFloatingIPAdd key: {}, value: {}", mapping.getKey(), mapping);
383 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
384 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
385 String interfaceName = pKey.getPortName();
387 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
388 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.getKey(), () -> Collections.singletonList(
389 txRunner.callWithNewWriteOnlyTransactionAndSubmit(
390 tx -> createNATFlowEntries(interfaceName, mapping, portIid, routerId, tx))),
391 NatConstants.NAT_DJC_MAX_RETRIES);
394 private void processFloatingIPDel(final InstanceIdentifier<InternalToExternalPortMap> identifier,
395 final InternalToExternalPortMap mapping) {
396 LOG.trace("processFloatingIPDel : key: {}, value: {}", mapping.getKey(), mapping);
398 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
399 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
400 String interfaceName = pKey.getPortName();
402 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
403 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.getKey(), () -> Collections.singletonList(
404 txRunner.callWithNewWriteOnlyTransactionAndSubmit(
405 tx -> removeNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
406 NatConstants.NAT_DJC_MAX_RETRIES);
409 private InetAddress getInetAddress(String ipAddr) {
410 InetAddress ipAddress = null;
412 ipAddress = InetAddress.getByName(ipAddr);
413 } catch (UnknownHostException e) {
414 LOG.error("getInetAddress : UnknowHostException for ip {}", ipAddr, e);
419 private boolean validateIpMapping(InternalToExternalPortMap mapping) {
420 return getInetAddress(mapping.getInternalIp()) != null && getInetAddress(mapping.getExternalIp()) != null;
423 void createNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
424 final InstanceIdentifier<RouterPorts> portIid, final String routerName,
425 WriteTransaction writeFlowInvTx) {
426 if (!validateIpMapping(mapping)) {
427 LOG.error("createNATFlowEntries : Not a valid ip addresses in the mapping {}", mapping);
431 //Get the DPN on which this interface resides
432 BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
434 if (dpnId.equals(BigInteger.ZERO)) {
435 LOG.warn("createNATFlowEntries : No DPN for interface {}. NAT flow entries for ip mapping {} will "
436 + "not be installed", interfaceName, mapping);
440 long routerId = NatUtil.getVpnId(dataBroker, routerName);
441 if (routerId == NatConstants.INVALID_ID) {
442 LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
446 //Check if the router to vpn association is present
447 //long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
448 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
449 long associatedVpnId = NatConstants.INVALID_ID;
450 if (associatedVpn == null) {
451 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
453 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
454 routerName, associatedVpn);
455 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
456 LOG.debug("createNATFlowEntries : vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
457 //routerId = associatedVpnId;
460 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.CONFIGURATION);
461 if (extNwId == null) {
462 LOG.error("createNATFlowEntries : External network associated with interface {} could not be retrieved",
466 long vpnId = getVpnId(extNwId, mapping.getExternalId());
468 LOG.error("createNATFlowEntries : No VPN associated with Ext nw {}. Unable to create SNAT table entry "
469 + "for fixed ip {}", extNwId, mapping.getInternalIp());
472 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
473 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
474 if (!isSnatEnabled) {
475 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, writeFlowInvTx, true);
477 //Create the DNAT and SNAT table entries
478 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, writeFlowInvTx);
479 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, extNwId, writeFlowInvTx);
480 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, extNwId, interfaceName, mapping, writeFlowInvTx);
483 void createNATFlowEntries(BigInteger dpnId, String interfaceName, String routerName, Uuid externalNetworkId,
484 InternalToExternalPortMap mapping, WriteTransaction writeFlowInvTx) {
485 String internalIp = mapping.getInternalIp();
486 long routerId = NatUtil.getVpnId(dataBroker, routerName);
487 if (routerId == NatConstants.INVALID_ID) {
488 LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
492 //Check if the router to vpn association is present
493 long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
494 if (associatedVpnId == NatConstants.INVALID_ID) {
495 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
497 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
498 routerName, associatedVpnId);
499 //routerId = associatedVpnId;
502 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
504 LOG.error("createNATFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
507 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
508 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
509 if (!isSnatEnabled) {
510 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, writeFlowInvTx, true);
512 //Create the DNAT and SNAT table entries
513 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, writeFlowInvTx);
514 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, externalNetworkId, writeFlowInvTx);
515 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, externalNetworkId, interfaceName, mapping,
519 void createNATOnlyFlowEntries(BigInteger dpnId, String routerName, String associatedVPN,
520 Uuid externalNetworkId, InternalToExternalPortMap mapping) {
521 String internalIp = mapping.getInternalIp();
522 //String segmentId = associatedVPN == null ? routerName : associatedVPN;
523 LOG.debug("createNATOnlyFlowEntries : Retrieving vpn id for VPN {} to proceed with create NAT Flows",
525 long routerId = NatUtil.getVpnId(dataBroker, routerName);
526 if (routerId == NatConstants.INVALID_ID) {
527 LOG.error("createNATOnlyFlowEntries : Could not retrieve vpn id for {} to create NAT Flow entries",
531 long associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVPN);
532 LOG.debug("createNATOnlyFlowEntries : Associated VPN Id {} for router {}", associatedVpnId, routerName);
533 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
535 LOG.error("createNATOnlyFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
538 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
539 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
540 if (!isSnatEnabled) {
541 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, null, true);
543 //Create the DNAT and SNAT table entries
544 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
545 mdsalManager.installFlow(preFlowEntity);
547 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
548 mdsalManager.installFlow(flowEntity);
550 String externalIp = mapping.getExternalIp();
551 preFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
552 mdsalManager.installFlow(preFlowEntity);
554 flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
555 if (flowEntity != null) {
556 mdsalManager.installFlow(flowEntity);
561 void removeNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
562 InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
563 WriteTransaction removeFlowInvTx) {
564 String internalIp = mapping.getInternalIp();
565 String externalIp = mapping.getExternalIp();
566 //Get the DPN on which this interface resides
568 dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
569 if (dpnId.equals(BigInteger.ZERO)) {
570 LOG.warn("removeNATFlowEntries: Abort processing Floating ip configuration. No DPN for port: {}",
576 long routerId = NatUtil.getVpnId(dataBroker, routerName);
577 if (routerId == NatConstants.INVALID_ID) {
578 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
583 //Delete the DNAT and SNAT table entries
584 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, removeFlowInvTx);
586 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.OPERATIONAL);
587 if (extNwId == null) {
588 LOG.error("removeNATFlowEntries : External network associated with interface {} could not be retrieved",
592 long vpnId = getVpnId(extNwId, mapping.getExternalId());
594 LOG.error("removeNATFlowEntries : No VPN associated with ext nw {}. Unable to delete SNAT table "
595 + "entry for fixed ip {}", extNwId, internalIp);
598 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, removeFlowInvTx);
599 //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
600 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
601 if (!isSnatEnabled) {
602 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, removeFlowInvTx, false);
604 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
605 if (provType == null) {
606 LOG.error("removeNATFlowEntries : External Network Provider Type missing");
609 if (provType == ProviderTypes.VXLAN) {
610 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping,
611 NatConstants.DEFAULT_L3VNI_VALUE, removeFlowInvTx);
612 removeOperationalDS(routerName, interfaceName, internalIp);
615 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
617 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
618 internalIp, routerId);
621 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping, (int) label,
623 removeOperationalDS(routerName, interfaceName, internalIp);
626 void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName,
627 InternalToExternalPortMap mapping, WriteTransaction removeFlowInvTx) {
628 String internalIp = mapping.getInternalIp();
629 String externalIp = mapping.getExternalIp();
630 long routerId = NatUtil.getVpnId(dataBroker, routerName);
631 if (routerId == NatConstants.INVALID_ID) {
632 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
637 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
638 if (vpnId == NatConstants.INVALID_ID) {
639 LOG.warn("removeNATFlowEntries : VPN Id not found for {} to remove NAT flow entries {}",
640 vpnName, internalIp);
643 //Delete the DNAT and SNAT table entries
644 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, removeFlowInvTx);
645 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, removeFlowInvTx);
646 //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
647 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
648 if (!isSnatEnabled) {
649 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, removeFlowInvTx, false);
651 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
652 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, externalNetworkId);
653 if (provType == null) {
654 LOG.error("removeNATFlowEntries : External Network Provider Type Missing");
657 if (provType == ProviderTypes.VXLAN) {
658 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, NatConstants.DEFAULT_L3VNI_VALUE,
659 removeFlowInvTx, provType);
660 removeOperationalDS(routerName, interfaceName, internalIp);
663 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
665 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
666 internalIp, routerId);
669 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, label, removeFlowInvTx, provType);
670 removeOperationalDS(routerName, interfaceName, internalIp);
673 protected long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
674 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapIdentifier =
675 NatUtil.getIntExtPortMapIdentifier(routerId, interfaceName, internalIp);
676 return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
677 LogicalDatastoreType.OPERATIONAL, intExtPortMapIdentifier).toJavaUtil().map(
678 InternalToExternalPortMap::getLabel).orElse(NatConstants.INVALID_ID);
681 static void updateOperationalDS(DataBroker dataBroker, String routerId, String interfaceName, long label,
682 String internalIp, String externalIp) {
684 LOG.info("updateOperationalDS : Updating operational DS for floating ip config : {} with label {}",
686 InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
687 Optional<Ports> optPorts =
688 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
689 LogicalDatastoreType.OPERATIONAL, portsId);
690 InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().setKey(new
691 InternalToExternalPortMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp)
692 .setLabel(label).build();
693 if (optPorts.isPresent()) {
694 LOG.debug("updateOperationalDS : Ports {} entry already present. Updating intExtPortMap for internal ip {}",
695 interfaceName, internalIp);
696 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId.child(InternalToExternalPortMap
697 .class, new InternalToExternalPortMapKey(internalIp)), intExtPortMap);
699 LOG.debug("updateOperationalDS : Adding Ports entry {} along with intExtPortMap {}",
700 interfaceName, internalIp);
701 List<InternalToExternalPortMap> intExtPortMapList = new ArrayList<>();
702 intExtPortMapList.add(intExtPortMap);
703 Ports ports = new PortsBuilder().setKey(new PortsKey(interfaceName)).setPortName(interfaceName)
704 .setInternalToExternalPortMap(intExtPortMapList).build();
705 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
709 void removeOperationalDS(String routerId, String interfaceName, String internalIp) {
710 LOG.info("removeOperationalDS : Remove operational DS for floating ip config: {}", internalIp);
711 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapId = NatUtil.getIntExtPortMapIdentifier(routerId,
712 interfaceName, internalIp);
713 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, intExtPortMapId);
716 private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
718 LOG.info("buildPreDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", externalIp);
720 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
722 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
723 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
724 NwConstants.COOKIE_DNAT_TABLE, null, null);
731 private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
733 LOG.info("buildDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", internalIp);
735 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
737 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
738 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
739 NwConstants.COOKIE_DNAT_TABLE, null, null);
745 private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
747 LOG.info("buildPreSNATDeleteFlowEntity : Building Delete PSNAT Flow entity for ip {} ", internalIp);
749 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
751 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
752 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
753 NwConstants.COOKIE_DNAT_TABLE, null, null);
757 private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
759 LOG.info("buildSNATDeleteFlowEntity : Building Delete SNAT Flow entity for ip {} ", externalIp);
761 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, routerId, externalIp);
763 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
764 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
765 NwConstants.COOKIE_DNAT_TABLE, null, null);
770 private void addOrDelDefaultFibRouteForDnat(BigInteger dpnId, String routerName,
771 long routerId, WriteTransaction tx, boolean create) {
773 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
774 newTx -> addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, newTx, create)), LOG,
775 "Error handling default FIB route for DNAT");
778 //Check if the router to bgp-vpn association is present
779 long associatedVpnId = NatConstants.INVALID_ID;
780 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
781 if (associatedVpn != null) {
782 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
785 if (associatedVpnId != NatConstants.INVALID_ID) {
786 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
787 + "vpn-id {}", dpnId, routerName, associatedVpnId);
788 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, associatedVpnId, routerId, tx);
790 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
791 + "vpn-id {}", dpnId, routerName, routerId);
792 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, tx);
795 if (associatedVpnId != NatConstants.INVALID_ID) {
796 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
797 + "with vpn-id {}", dpnId, routerName, associatedVpnId);
798 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, associatedVpnId, routerId, tx);
800 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
801 + "with vpn-id {}", dpnId, routerName, routerId);
802 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, tx);