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 java.util.concurrent.ExecutionException;
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.netvirt.natservice.api.CentralizedSwitchScheduler;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
74 public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<InternalToExternalPortMap, FloatingIPListener> {
75 private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
76 private final DataBroker dataBroker;
77 private final ManagedNewTransactionRunner txRunner;
78 private final IMdsalApiManager mdsalManager;
79 private final OdlInterfaceRpcService interfaceManager;
80 private final FloatingIPHandler floatingIPHandler;
81 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
82 private final JobCoordinator coordinator;
83 private final CentralizedSwitchScheduler centralizedSwitchScheduler;
86 public FloatingIPListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
87 final OdlInterfaceRpcService interfaceManager,
88 final FloatingIPHandler floatingIPHandler,
89 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
90 final JobCoordinator coordinator,
91 final CentralizedSwitchScheduler centralizedSwitchScheduler) {
92 super(InternalToExternalPortMap.class, FloatingIPListener.class);
93 this.dataBroker = dataBroker;
94 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
95 this.mdsalManager = mdsalManager;
96 this.interfaceManager = interfaceManager;
97 this.floatingIPHandler = floatingIPHandler;
98 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
99 this.coordinator = coordinator;
100 this.centralizedSwitchScheduler = centralizedSwitchScheduler;
106 LOG.info("{} init", getClass().getSimpleName());
107 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
111 protected InstanceIdentifier<InternalToExternalPortMap> getWildCardPath() {
112 return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class)
113 .child(InternalToExternalPortMap.class);
117 protected FloatingIPListener getDataTreeChangeListener() {
118 return FloatingIPListener.this;
122 protected void add(final InstanceIdentifier<InternalToExternalPortMap> identifier,
123 final InternalToExternalPortMap mapping) {
124 LOG.trace("FloatingIPListener add ip mapping method - key: {} value: {}",mapping.key(), mapping);
125 processFloatingIPAdd(identifier, mapping);
129 protected void remove(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap mapping) {
130 LOG.trace("FloatingIPListener remove ip mapping method - kkey: {} value: {}",mapping.key(), mapping);
131 processFloatingIPDel(identifier, mapping);
135 protected void update(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap
136 original, InternalToExternalPortMap update) {
137 LOG.trace("FloatingIPListener update ip mapping method - key: {}, original: {}, update: {}",
138 update.key(), original, update);
141 private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
143 String externalIp = mapping.getExternalIp();
144 Uuid floatingIpId = mapping.getExternalId();
145 //Get the FIP MAC address for DNAT
146 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
147 if (floatingIpPortMacAddress == null) {
148 LOG.error("buildPreDNATFlowEntity : Unable to retrieve floatingIpPortMacAddress from floating IP UUID {} "
149 + "for floating IP {}", floatingIpId, externalIp);
152 LOG.debug("buildPreDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
153 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
154 LOG.debug("buildPreDNATFlowEntity : Segment id {} in build preDNAT Flow", segmentId);
156 List<MatchInfo> matches = new ArrayList<>();
157 matches.add(MatchEthernetType.IPV4);
159 matches.add(new MatchIpv4Destination(externalIp, "32"));
160 //Match Destination Floating IP MAC Address on table = 25 (PDNAT_TABLE)
161 matches.add(new MatchEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
163 // matches.add(new MatchMetadata(
164 // BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
165 List<ActionInfo> actionsInfos = new ArrayList<>();
166 String internalIp = mapping.getInternalIp();
167 actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
169 List<InstructionInfo> instructions = new ArrayList<>();
170 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(segmentId),
171 MetaDataUtil.METADATA_MASK_VRFID));
172 instructions.add(new InstructionApplyActions(actionsInfos));
173 instructions.add(new InstructionGotoTable(NwConstants.DNAT_TABLE));
175 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
177 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
178 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
179 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
184 private FlowEntity buildDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
186 String externalIp = mapping.getExternalIp();
187 LOG.info("buildDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
189 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
190 LOG.debug("buildDNATFlowEntity : Segment id {} in build DNAT", segmentId);
192 List<MatchInfo> matches = new ArrayList<>();
193 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
195 matches.add(MatchEthernetType.IPV4);
196 String internalIp = mapping.getInternalIp();
197 matches.add(new MatchIpv4Destination(internalIp, "32"));
199 List<ActionInfo> actionsInfos = new ArrayList<>();
200 // actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
202 List<InstructionInfo> instructions = new ArrayList<>();
203 // instructions.add(new InstructionWriteMetadata(BigInteger.valueOf
204 // (routerId), MetaDataUtil.METADATA_MASK_VRFID));
205 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
206 instructions.add(new InstructionApplyActions(actionsInfos));
207 //instructions.add(new InstructionGotoTable(NatConstants.L3_FIB_TABLE));
209 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
211 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
212 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
213 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
219 private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long
220 routerId, long associatedVpn) {
222 LOG.debug("buildPreSNATFlowEntity : Building PSNAT Flow entity for ip {} ", internalIp);
224 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
226 LOG.debug("buildPreSNATFlowEntity : Segment id {} in build preSNAT flow", segmentId);
228 List<MatchInfo> matches = new ArrayList<>();
229 matches.add(MatchEthernetType.IPV4);
231 matches.add(new MatchIpv4Source(internalIp, "32"));
233 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
235 List<ActionInfo> actionsInfos = new ArrayList<>();
236 actionsInfos.add(new ActionSetSourceIp(externalIp, "32"));
238 List<InstructionInfo> instructions = new ArrayList<>();
240 new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
241 instructions.add(new InstructionApplyActions(actionsInfos));
242 instructions.add(new InstructionGotoTable(NwConstants.SNAT_TABLE));
244 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
246 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
247 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
248 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
253 private FlowEntity buildSNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long vpnId, Uuid
255 String internalIp = mapping.getInternalIp();
256 LOG.debug("buildSNATFlowEntity : Building SNAT Flow entity for ip {} ", internalIp);
258 ProviderTypes provType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
259 if (provType == null) {
260 LOG.error("buildSNATFlowEntity : Unable to get Network Provider Type for network {}", externalNetworkId);
264 List<MatchInfo> matches = new ArrayList<>();
265 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
266 matches.add(MatchEthernetType.IPV4);
267 String externalIp = mapping.getExternalIp();
268 matches.add(new MatchIpv4Source(externalIp, "32"));
270 List<ActionInfo> actionsInfo = new ArrayList<>();
271 Uuid floatingIpId = mapping.getExternalId();
272 String macAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
273 if (macAddress != null) {
274 actionsInfo.add(new ActionSetFieldEthernetSource(new MacAddress(macAddress)));
276 LOG.warn("buildSNATFlowEntity : No MAC address found for floating IP {}", externalIp);
279 LOG.trace("buildSNATFlowEntity : External Network Provider Type is {}, resubmit to FIB", provType.toString());
280 actionsInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
281 List<InstructionInfo> instructions = new ArrayList<>();
282 instructions.add(new InstructionApplyActions(actionsInfo));
283 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, vpnId, externalIp);
285 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
286 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
287 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
293 private void createDNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long routerId,
294 long associatedVpnId, TypedReadWriteTransaction<Configuration> confTx) {
295 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
296 if (preFlowEntity == null) {
297 LOG.error("createDNATTblEntry : Flow entity received as NULL. "
298 + "Cannot proceed with installation of Pre-DNAT flow table {} --> table {} on DpnId {}",
299 NwConstants.PDNAT_TABLE, NwConstants.DNAT_TABLE, dpnId);
301 mdsalManager.addFlow(confTx, preFlowEntity);
302 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
303 if (flowEntity != null) {
304 mdsalManager.addFlow(confTx, flowEntity);
309 private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId,
310 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
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);
320 private void createSNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long vpnId, long routerId,
321 long associatedVpnId, Uuid externalNetworkId, TypedReadWriteTransaction<Configuration> confTx) {
322 FlowEntity preFlowEntity = buildPreSNATFlowEntity(dpnId, mapping.getInternalIp(), mapping.getExternalIp(),
323 vpnId, routerId, associatedVpnId);
324 mdsalManager.addFlow(confTx, preFlowEntity);
326 FlowEntity flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
327 if (flowEntity != null) {
328 mdsalManager.addFlow(confTx, flowEntity);
332 private void removeSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId,
333 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
334 throws ExecutionException, InterruptedException {
335 FlowEntity preFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId);
336 mdsalManager.removeFlow(removeFlowInvTx, preFlowEntity);
338 FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, externalIp, vpnId);
339 if (flowEntity != null) {
340 mdsalManager.removeFlow(removeFlowInvTx, flowEntity);
344 private Uuid getExtNetworkId(final InstanceIdentifier<RouterPorts> portIid,
345 LogicalDatastoreType dataStoreType) {
346 Optional<RouterPorts> rtrPort =
347 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
348 dataStoreType, portIid);
349 if (!rtrPort.isPresent()) {
350 LOG.error("getExtNetworkId : Unable to read router port entry for {}", portIid);
354 Uuid extNwId = rtrPort.get().getExternalNetworkId();
358 private long getVpnId(Uuid extNwId, Uuid floatingIpExternalId) {
359 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpExternalId);
360 if (subnetId != null) {
361 long vpnId = NatUtil.getVpnId(dataBroker, subnetId.getValue());
362 if (vpnId != NatConstants.INVALID_ID) {
363 LOG.debug("getVpnId : Got vpnId {} for floatingIpExternalId {}", vpnId, floatingIpExternalId);
368 InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class,
369 new NetworksKey(extNwId)).build();
370 Optional<Networks> nw =
371 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
372 LogicalDatastoreType.CONFIGURATION, nwId);
373 if (!nw.isPresent()) {
374 LOG.error("getVpnId : Unable to read external network for {}", extNwId);
375 return NatConstants.INVALID_ID;
378 Uuid vpnUuid = nw.get().getVpnid();
379 if (vpnUuid == null) {
380 LOG.error("getVpnId : Unable to read vpn from External network: {}", extNwId);
381 return NatConstants.INVALID_ID;
384 //Get the id using the VPN UUID (also vpn instance name)
385 return NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
388 private void processFloatingIPAdd(final InstanceIdentifier<InternalToExternalPortMap> identifier,
389 final InternalToExternalPortMap mapping) {
390 LOG.trace("processFloatingIPAdd key: {}, value: {}", mapping.key(), mapping);
392 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
393 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
394 String interfaceName = pKey.getPortName();
396 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
397 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
398 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
399 tx -> createNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
400 NatConstants.NAT_DJC_MAX_RETRIES);
403 private void processFloatingIPDel(final InstanceIdentifier<InternalToExternalPortMap> identifier,
404 final InternalToExternalPortMap mapping) {
405 LOG.trace("processFloatingIPDel : key: {}, value: {}", mapping.key(), mapping);
407 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
408 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
409 String interfaceName = pKey.getPortName();
411 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
412 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
413 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
414 tx -> removeNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
415 NatConstants.NAT_DJC_MAX_RETRIES);
418 private InetAddress getInetAddress(String ipAddr) {
419 InetAddress ipAddress = null;
421 ipAddress = InetAddress.getByName(ipAddr);
422 } catch (UnknownHostException e) {
423 LOG.error("getInetAddress : UnknowHostException for ip {}", ipAddr, e);
428 private boolean validateIpMapping(InternalToExternalPortMap mapping) {
429 return getInetAddress(mapping.getInternalIp()) != null && getInetAddress(mapping.getExternalIp()) != null;
432 private BigInteger getAssociatedDpnWithExternalInterface(final String routerName, Uuid extNwId, BigInteger dpnId,
433 String interfaceName) {
434 //Get the DPN on which this interface resides
436 dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
438 BigInteger updatedDpnId = dpnId;
439 if (updatedDpnId.equals(BigInteger.ZERO)) {
440 LOG.debug("getAssociatedDpnWithExternalInterface : The interface {} is not associated with any dpn",
444 ProviderTypes providerType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
445 if (providerType == null) {
446 LOG.warn("getAssociatedDpnWithExternalInterface : Provider Network Type for router {} and"
447 + " externalNetwork {} is missing.", routerName, extNwId);
451 // For FLAT and VLAN provider networks, we have to ensure that dpn hosting the VM has connectivity
452 // to External Network via provider_mappings. In case the dpn does not have the provider mappings,
453 // traffic from the VM has to be forwarded to the NAPT Switch (which is scheduled based on the provider
454 // mappings) and then sent out on the external Network.
455 if (providerType == ProviderTypes.FLAT || providerType == ProviderTypes.VLAN) {
456 String providerNet = NatUtil.getElanInstancePhysicalNetwok(extNwId.getValue(), dataBroker);
457 boolean isDpnConnected = centralizedSwitchScheduler.isSwitchConnectedToExternal(updatedDpnId, providerNet);
458 if (!isDpnConnected) {
459 updatedDpnId = centralizedSwitchScheduler.getCentralizedSwitch(routerName);
465 void createNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
466 final InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
467 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
468 if (!validateIpMapping(mapping)) {
469 LOG.error("createNATFlowEntries : Not a valid ip addresses in the mapping {}", mapping);
473 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.CONFIGURATION);
474 if (extNwId == null) {
475 LOG.error("createNATFlowEntries : External network associated with interface {} could not be retrieved",
480 // For Overlay Networks, get the DPN on which this interface resides.
481 // For FLAT/VLAN Networks, get the DPN with provider_mappings for external network.
482 dpnId = getAssociatedDpnWithExternalInterface(routerName, extNwId, dpnId, interfaceName);
483 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
484 LOG.warn("createNATFlowEntries : No DPN for interface {}. NAT flow entries for ip mapping {} will "
485 + "not be installed", interfaceName, mapping);
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 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
498 long associatedVpnId = NatConstants.INVALID_ID;
499 if (associatedVpn == null) {
500 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
502 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
503 routerName, associatedVpn);
504 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
505 LOG.debug("createNATFlowEntries : vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
506 //routerId = associatedVpnId;
509 long vpnId = getVpnId(extNwId, mapping.getExternalId());
511 LOG.error("createNATFlowEntries : No VPN associated with Ext nw {}. Unable to create SNAT table entry "
512 + "for fixed ip {}", extNwId, mapping.getInternalIp());
515 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
516 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
517 if (!isSnatEnabled) {
518 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
520 //Create the DNAT and SNAT table entries
521 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
522 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, extNwId, confTx);
523 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, extNwId, interfaceName, mapping, confTx);
526 void createNATFlowEntries(BigInteger dpnId, String interfaceName, String routerName, Uuid externalNetworkId,
527 InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx)
528 throws ExecutionException, InterruptedException {
529 String internalIp = mapping.getInternalIp();
530 long routerId = NatUtil.getVpnId(dataBroker, routerName);
531 if (routerId == NatConstants.INVALID_ID) {
532 LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
536 //Check if the router to vpn association is present
537 long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
538 if (associatedVpnId == NatConstants.INVALID_ID) {
539 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
541 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
542 routerName, associatedVpnId);
543 //routerId = associatedVpnId;
546 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
548 LOG.error("createNATFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
551 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
552 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
553 if (!isSnatEnabled) {
554 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
556 //Create the DNAT and SNAT table entries
557 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
558 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, externalNetworkId, confTx);
559 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, externalNetworkId, interfaceName, mapping,
563 void createNATOnlyFlowEntries(BigInteger dpnId, String routerName, String associatedVPN,
564 Uuid externalNetworkId, InternalToExternalPortMap mapping)
565 throws ExecutionException, InterruptedException {
566 String internalIp = mapping.getInternalIp();
567 //String segmentId = associatedVPN == null ? routerName : associatedVPN;
568 LOG.debug("createNATOnlyFlowEntries : Retrieving vpn id for VPN {} to proceed with create NAT Flows",
570 long routerId = NatUtil.getVpnId(dataBroker, routerName);
571 if (routerId == NatConstants.INVALID_ID) {
572 LOG.error("createNATOnlyFlowEntries : Could not retrieve vpn id for {} to create NAT Flow entries",
576 long associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVPN);
577 LOG.debug("createNATOnlyFlowEntries : Associated VPN Id {} for router {}", associatedVpnId, routerName);
578 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
580 LOG.error("createNATOnlyFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
583 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
584 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
585 if (!isSnatEnabled) {
586 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, null, true);
588 //Create the DNAT and SNAT table entries
589 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
590 mdsalManager.installFlow(preFlowEntity);
592 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
593 mdsalManager.installFlow(flowEntity);
595 String externalIp = mapping.getExternalIp();
596 preFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
597 mdsalManager.installFlow(preFlowEntity);
599 flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
600 if (flowEntity != null) {
601 mdsalManager.installFlow(flowEntity);
606 void removeNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
607 InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
608 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
609 throws ExecutionException, InterruptedException {
610 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.OPERATIONAL);
611 if (extNwId == null) {
612 LOG.error("removeNATFlowEntries : External network associated with interface {} could not be retrieved",
617 // For Overlay Networks, get the DPN on which this interface resides.
618 // For FLAT/VLAN Networks, get the DPN with provider_mappings for external network.
620 dpnId = getAssociatedDpnWithExternalInterface(routerName, extNwId,
621 NatUtil.getDpnForInterface(interfaceManager, interfaceName), interfaceName);
622 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
623 LOG.warn("removeNATFlowEntries: Abort processing Floating ip configuration. No DPN for port: {}",
629 long routerId = NatUtil.getVpnId(dataBroker, routerName);
630 if (routerId == NatConstants.INVALID_ID) {
631 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
636 String internalIp = mapping.getInternalIp();
637 String externalIp = mapping.getExternalIp();
639 //Delete the DNAT and SNAT table entries
640 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, removeFlowInvTx);
642 long vpnId = getVpnId(extNwId, mapping.getExternalId());
644 LOG.error("removeNATFlowEntries : No VPN associated with ext nw {}. Unable to delete SNAT table "
645 + "entry for fixed ip {}", extNwId, internalIp);
648 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, removeFlowInvTx);
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, removeFlowInvTx, false);
654 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
655 if (provType == null) {
656 LOG.error("removeNATFlowEntries : External Network Provider Type missing");
659 if (provType == ProviderTypes.VXLAN) {
660 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping,
661 NatConstants.DEFAULT_L3VNI_VALUE, removeFlowInvTx);
662 removeOperationalDS(routerName, interfaceName, internalIp);
665 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
667 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
668 internalIp, routerId);
671 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping, (int) label,
673 removeOperationalDS(routerName, interfaceName, internalIp);
676 void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName,
677 InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx)
678 throws ExecutionException, InterruptedException {
679 String internalIp = mapping.getInternalIp();
680 String externalIp = mapping.getExternalIp();
681 long routerId = NatUtil.getVpnId(dataBroker, routerName);
682 if (routerId == NatConstants.INVALID_ID) {
683 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
688 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
689 if (vpnId == NatConstants.INVALID_ID) {
690 LOG.warn("removeNATFlowEntries : VPN Id not found for {} to remove NAT flow entries {}",
691 vpnName, internalIp);
694 //Delete the DNAT and SNAT table entries
695 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, confTx);
696 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, confTx);
697 //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
698 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
699 if (!isSnatEnabled) {
700 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, false);
702 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
703 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, externalNetworkId);
704 if (provType == null) {
705 LOG.error("removeNATFlowEntries : External Network Provider Type Missing");
708 if (provType == ProviderTypes.VXLAN) {
709 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, NatConstants.DEFAULT_L3VNI_VALUE,
711 removeOperationalDS(routerName, interfaceName, internalIp);
714 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
716 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
717 internalIp, routerId);
720 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, label, confTx, provType);
721 removeOperationalDS(routerName, interfaceName, internalIp);
724 protected long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
725 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapIdentifier =
726 NatUtil.getIntExtPortMapIdentifier(routerId, interfaceName, internalIp);
727 return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
728 LogicalDatastoreType.OPERATIONAL, intExtPortMapIdentifier).toJavaUtil().map(
729 InternalToExternalPortMap::getLabel).orElse(NatConstants.INVALID_ID);
732 static void updateOperationalDS(DataBroker dataBroker, String routerId, String interfaceName, long label,
733 String internalIp, String externalIp) {
735 LOG.info("updateOperationalDS : Updating operational DS for floating ip config : {} with label {}",
737 InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
738 Optional<Ports> optPorts =
739 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
740 LogicalDatastoreType.OPERATIONAL, portsId);
741 InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
742 InternalToExternalPortMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp)
743 .setLabel(label).build();
744 if (optPorts.isPresent()) {
745 LOG.debug("updateOperationalDS : Ports {} entry already present. Updating intExtPortMap for internal ip {}",
746 interfaceName, internalIp);
747 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId.child(InternalToExternalPortMap
748 .class, new InternalToExternalPortMapKey(internalIp)), intExtPortMap);
750 LOG.debug("updateOperationalDS : Adding Ports entry {} along with intExtPortMap {}",
751 interfaceName, internalIp);
752 List<InternalToExternalPortMap> intExtPortMapList = new ArrayList<>();
753 intExtPortMapList.add(intExtPortMap);
754 Ports ports = new PortsBuilder().withKey(new PortsKey(interfaceName)).setPortName(interfaceName)
755 .setInternalToExternalPortMap(intExtPortMapList).build();
756 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
760 void removeOperationalDS(String routerId, String interfaceName, String internalIp) {
761 LOG.info("removeOperationalDS : Remove operational DS for floating ip config: {}", internalIp);
762 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapId = NatUtil.getIntExtPortMapIdentifier(routerId,
763 interfaceName, internalIp);
764 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, intExtPortMapId);
767 private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
769 LOG.info("buildPreDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", externalIp);
771 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
773 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
774 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
775 NwConstants.COOKIE_DNAT_TABLE, null, null);
782 private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
784 LOG.info("buildDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", internalIp);
786 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
788 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
789 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
790 NwConstants.COOKIE_DNAT_TABLE, null, null);
796 private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
798 LOG.info("buildPreSNATDeleteFlowEntity : Building Delete PSNAT Flow entity for ip {} ", internalIp);
800 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
802 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
803 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
804 NwConstants.COOKIE_DNAT_TABLE, null, null);
808 private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
810 LOG.info("buildSNATDeleteFlowEntity : Building Delete SNAT Flow entity for ip {} ", externalIp);
812 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, routerId, externalIp);
814 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
815 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
816 NwConstants.COOKIE_DNAT_TABLE, null, null);
821 private void addOrDelDefaultFibRouteForDnat(BigInteger dpnId, String routerName, long routerId,
822 TypedReadWriteTransaction<Configuration> confTx, boolean create)
823 throws ExecutionException, InterruptedException {
824 if (confTx == null) {
825 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
826 newTx -> addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, newTx, create)), LOG,
827 "Error handling default FIB route for DNAT");
830 //Check if the router to bgp-vpn association is present
831 long associatedVpnId = NatConstants.INVALID_ID;
832 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
833 if (associatedVpn != null) {
834 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
837 if (associatedVpnId != NatConstants.INVALID_ID) {
838 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
839 + "vpn-id {}", dpnId, routerName, associatedVpnId);
840 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
842 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
843 + "vpn-id {}", dpnId, routerName, routerId);
844 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
847 if (associatedVpnId != NatConstants.INVALID_ID) {
848 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
849 + "with vpn-id {}", dpnId, routerName, associatedVpnId);
850 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
852 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
853 + "with vpn-id {}", dpnId, routerName, routerId);
854 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);